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 * nfs version 2, 3 and 4 server calls to vnode ops
41 * - these routines generally have 3 phases
42 * 1 - break down and validate rpc request in mbuf list
43 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
44 * function in nfsd_port.c
45 * 3 - build the rpc reply in an mbuf list
46 * For nfsv4, these functions are called for each Op within the Compound RPC.
50 #include <fs/nfs/nfsport.h>
53 extern u_int32_t newnfs_false, newnfs_true;
54 extern enum vtype nv34tov_type[8];
55 extern struct timeval nfsboottime;
56 extern int nfs_rootfhset;
57 extern int nfsrv_enable_crossmntpt;
58 extern int nfsrv_statehashsize;
59 #endif /* !APPLEKEXT */
61 static int nfs_async = 0;
62 SYSCTL_DECL(_vfs_nfsd);
63 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
64 "Tell client that writes were synced even though they were not");
67 * This list defines the GSS mechanisms supported.
68 * (Don't ask me how you get these strings from the RFC stuff like
69 * iso(1), org(3)... but someone did it, so I don't need to know.)
71 static struct nfsgss_mechlist nfsgss_mechlist[] = {
72 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
77 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
78 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
79 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
80 int *diraft_retp, nfsattrbit_t *attrbitp,
81 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
83 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
84 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
85 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
86 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
87 NFSPROC_T *p, struct nfsexstuff *exp);
90 * nfs access service (not a part of NFS V2)
93 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
94 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
97 int getret, error = 0;
99 u_int32_t testmode, nfsmode, supported = 0;
102 if (nd->nd_repstat) {
103 nfsrv_postopattr(nd, 1, &nva);
106 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
107 nfsmode = fxdr_unsigned(u_int32_t, *tl);
108 if ((nd->nd_flag & ND_NFSV4) &&
109 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
110 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
111 NFSACCESS_EXECUTE))) {
112 nd->nd_repstat = NFSERR_INVAL;
116 if (nfsmode & NFSACCESS_READ) {
117 supported |= NFSACCESS_READ;
118 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
119 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
120 nfsmode &= ~NFSACCESS_READ;
122 if (nfsmode & NFSACCESS_MODIFY) {
123 supported |= NFSACCESS_MODIFY;
124 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
125 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
126 nfsmode &= ~NFSACCESS_MODIFY;
128 if (nfsmode & NFSACCESS_EXTEND) {
129 supported |= NFSACCESS_EXTEND;
130 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
131 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
132 nfsmode &= ~NFSACCESS_EXTEND;
134 if (nfsmode & NFSACCESS_DELETE) {
135 supported |= NFSACCESS_DELETE;
136 if (vp->v_type == VDIR)
137 deletebit = VDELETE_CHILD;
140 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
141 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
142 nfsmode &= ~NFSACCESS_DELETE;
144 if (vnode_vtype(vp) == VDIR)
145 testmode = NFSACCESS_LOOKUP;
147 testmode = NFSACCESS_EXECUTE;
148 if (nfsmode & testmode) {
149 supported |= (nfsmode & testmode);
150 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
151 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
152 nfsmode &= ~testmode;
154 nfsmode &= supported;
155 if (nd->nd_flag & ND_NFSV3) {
156 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
157 nfsrv_postopattr(nd, getret, &nva);
160 if (nd->nd_flag & ND_NFSV4) {
161 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
162 *tl++ = txdr_unsigned(supported);
164 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
165 *tl = txdr_unsigned(nfsmode);
172 NFSEXITCODE2(error, nd);
177 * nfs getattr service
180 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
181 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
185 int at_root = 0, error = 0, supports_nfsv4acls;
186 struct nfsreferral *refp;
187 nfsattrbit_t attrbits, tmpbits;
189 struct vnode *tvp = NULL;
191 uint64_t mounted_on_fileno = 0;
196 if (nd->nd_flag & ND_NFSV4) {
197 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
204 * Check for a referral.
206 refp = nfsv4root_getreferral(vp, NULL, 0);
208 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
213 if (nd->nd_repstat == 0) {
215 NFSSET_ATTRBIT(&tmpbits, &attrbits);
218 * GETATTR with write-only attr time_access_set and time_modify_set
219 * should return NFS4ERR_INVAL.
221 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
222 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
223 error = NFSERR_INVAL;
227 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
228 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
229 accmode |= VREAD_ACL;
231 if (NFSNONZERO_ATTRBIT(&tmpbits))
232 accmode |= VREAD_ATTRIBUTES;
234 nd->nd_repstat = nfsvno_accchk(vp, accmode,
235 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
236 NFSACCCHK_VPISLOCKED, NULL);
240 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
241 if (!nd->nd_repstat) {
242 if (nd->nd_flag & ND_NFSV4) {
243 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
244 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
246 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
247 &nva, &attrbits, nd->nd_cred, p);
248 if (nd->nd_repstat == 0) {
249 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
251 if (nfsrv_enable_crossmntpt != 0 &&
252 vp->v_type == VDIR &&
253 (vp->v_vflag & VV_ROOT) != 0 &&
255 tvp = mp->mnt_vnodecovered;
263 if ((nd->nd_repstat =
264 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
265 nd->nd_repstat = VOP_GETATTR(
266 tvp, &va, nd->nd_cred);
270 if (nd->nd_repstat == 0)
271 mounted_on_fileno = (uint64_t)
276 if (nd->nd_repstat == 0)
277 nd->nd_repstat = vfs_busy(mp, 0);
279 if (nd->nd_repstat == 0) {
280 (void)nfsvno_fillattr(nd, mp, vp, &nva,
281 &fh, 0, &attrbits, nd->nd_cred, p,
282 isdgram, 1, supports_nfsv4acls,
283 at_root, mounted_on_fileno);
290 nfsrv_fillattr(nd, &nva);
298 NFSEXITCODE2(error, nd);
303 * nfs setattr service
306 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
307 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
309 struct nfsvattr nva, nva2;
311 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
312 struct timespec guard = { 0, 0 };
313 nfsattrbit_t attrbits, retbits;
314 nfsv4stateid_t stateid;
315 NFSACL_T *aclp = NULL;
317 if (nd->nd_repstat) {
318 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
321 #ifdef NFS4_ACL_EXTATTR_NAME
322 aclp = acl_alloc(M_WAITOK);
325 NFSVNO_ATTRINIT(&nva);
326 NFSZERO_ATTRBIT(&retbits);
327 if (nd->nd_flag & ND_NFSV4) {
328 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
329 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
330 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
332 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
335 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
337 nd->nd_repstat = preat_ret;
338 if (nd->nd_flag & ND_NFSV3) {
339 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
340 gcheck = fxdr_unsigned(int, *tl);
342 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
343 fxdr_nfsv3time(tl, &guard);
345 if (!nd->nd_repstat && gcheck &&
346 (nva2.na_ctime.tv_sec != guard.tv_sec ||
347 nva2.na_ctime.tv_nsec != guard.tv_nsec))
348 nd->nd_repstat = NFSERR_NOT_SYNC;
349 if (nd->nd_repstat) {
351 #ifdef NFS4_ACL_EXTATTR_NAME
354 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
357 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
358 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
361 * Now that we have all the fields, lets do it.
362 * If the size is being changed write access is required, otherwise
363 * just check for a read only file system.
365 if (!nd->nd_repstat) {
366 if (NFSVNO_NOTSETSIZE(&nva)) {
367 if (NFSVNO_EXRDONLY(exp) ||
368 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
369 nd->nd_repstat = EROFS;
371 if (vnode_vtype(vp) != VREG)
372 nd->nd_repstat = EINVAL;
373 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
374 NFSVNO_EXSTRICTACCESS(exp))
375 nd->nd_repstat = nfsvno_accchk(vp,
376 VWRITE, nd->nd_cred, exp, p,
377 NFSACCCHK_NOOVERRIDE,
378 NFSACCCHK_VPISLOCKED, NULL);
381 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
382 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
383 &nva, &attrbits, exp, p);
385 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
387 * For V4, try setting the attrbutes in sets, so that the
388 * reply bitmap will be correct for an error case.
390 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
391 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
392 NFSVNO_ATTRINIT(&nva2);
393 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
394 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
395 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
397 if (!nd->nd_repstat) {
398 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
399 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
400 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
401 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
404 if (!nd->nd_repstat &&
405 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
406 NFSVNO_ATTRINIT(&nva2);
407 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
408 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
411 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
413 if (!nd->nd_repstat &&
414 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
415 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
416 NFSVNO_ATTRINIT(&nva2);
417 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
418 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
419 if (nva.na_vaflags & VA_UTIMES_NULL) {
420 nva2.na_vaflags |= VA_UTIMES_NULL;
421 NFSVNO_SETACTIVE(&nva2, vaflags);
423 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
425 if (!nd->nd_repstat) {
426 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
427 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
428 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
429 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
432 if (!nd->nd_repstat &&
433 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
434 NFSVNO_ATTRINIT(&nva2);
435 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
436 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
439 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
442 #ifdef NFS4_ACL_EXTATTR_NAME
443 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
444 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
445 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
447 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
450 } else if (!nd->nd_repstat) {
451 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
454 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
455 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
457 nd->nd_repstat = postat_ret;
460 #ifdef NFS4_ACL_EXTATTR_NAME
463 if (nd->nd_flag & ND_NFSV3)
464 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
465 else if (nd->nd_flag & ND_NFSV4)
466 (void) nfsrv_putattrbit(nd, &retbits);
467 else if (!nd->nd_repstat)
468 nfsrv_fillattr(nd, &nva);
475 #ifdef NFS4_ACL_EXTATTR_NAME
478 if (nd->nd_flag & ND_NFSV4) {
480 * For all nd_repstat, the V4 reply includes a bitmap,
481 * even NFSERR_BADXDR, which is what this will end up
484 (void) nfsrv_putattrbit(nd, &retbits);
486 NFSEXITCODE2(error, nd);
492 * (Also performs lookup parent for v4)
495 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
496 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
497 struct nfsexstuff *exp)
499 struct nameidata named;
500 vnode_t vp, dirp = NULL;
501 int error = 0, dattr_ret = 1;
502 struct nfsvattr nva, dattr;
506 if (nd->nd_repstat) {
507 nfsrv_postopattr(nd, dattr_ret, &dattr);
512 * For some reason, if dp is a symlink, the error
513 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
515 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
516 nd->nd_repstat = NFSERR_SYMLINK;
521 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
522 LOCKLEAF | SAVESTART);
523 nfsvno_setpathbuf(&named, &bufp, &hashp);
524 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
527 nfsvno_relpathbuf(&named);
530 if (!nd->nd_repstat) {
531 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
534 nfsvno_relpathbuf(&named);
536 if (nd->nd_repstat) {
538 if (nd->nd_flag & ND_NFSV3)
539 dattr_ret = nfsvno_getattr(dirp, &dattr,
543 if (nd->nd_flag & ND_NFSV3)
544 nfsrv_postopattr(nd, dattr_ret, &dattr);
547 if (named.ni_startdir)
548 vrele(named.ni_startdir);
549 nfsvno_relpathbuf(&named);
551 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
552 vp->v_type != VDIR && vp->v_type != VLNK)
554 * Only allow lookup of VDIR and VLNK for traversal of
555 * non-exported volumes during NFSv4 mounting.
557 nd->nd_repstat = ENOENT;
558 if (nd->nd_repstat == 0)
559 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
560 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
561 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
562 if (vpp != NULL && nd->nd_repstat == 0)
567 if (nd->nd_flag & ND_NFSV3)
568 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
572 if (nd->nd_repstat) {
573 if (nd->nd_flag & ND_NFSV3)
574 nfsrv_postopattr(nd, dattr_ret, &dattr);
577 if (nd->nd_flag & ND_NFSV2) {
578 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
579 nfsrv_fillattr(nd, &nva);
580 } else if (nd->nd_flag & ND_NFSV3) {
581 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
582 nfsrv_postopattr(nd, 0, &nva);
583 nfsrv_postopattr(nd, dattr_ret, &dattr);
587 NFSEXITCODE2(error, nd);
592 * nfs readlink service
595 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
596 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
599 mbuf_t mp = NULL, mpend = NULL;
603 if (nd->nd_repstat) {
604 nfsrv_postopattr(nd, getret, &nva);
607 if (vnode_vtype(vp) != VLNK) {
608 if (nd->nd_flag & ND_NFSV2)
609 nd->nd_repstat = ENXIO;
611 nd->nd_repstat = EINVAL;
614 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
616 if (nd->nd_flag & ND_NFSV3)
617 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
619 if (nd->nd_flag & ND_NFSV3)
620 nfsrv_postopattr(nd, getret, &nva);
623 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
624 *tl = txdr_unsigned(len);
625 mbuf_setnext(nd->nd_mb, mp);
627 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
638 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
639 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
642 int error = 0, cnt, getret = 1, reqlen, eof = 0;
646 struct nfsstate st, *stp = &st;
647 struct nfslock lo, *lop = &lo;
648 nfsv4stateid_t stateid;
651 if (nd->nd_repstat) {
652 nfsrv_postopattr(nd, getret, &nva);
655 if (nd->nd_flag & ND_NFSV2) {
656 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
657 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
658 reqlen = fxdr_unsigned(int, *tl);
659 } else if (nd->nd_flag & ND_NFSV3) {
660 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
661 off = fxdr_hyper(tl);
663 reqlen = fxdr_unsigned(int, *tl);
665 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
666 reqlen = fxdr_unsigned(int, *(tl + 6));
668 if (reqlen > NFS_SRVMAXDATA(nd)) {
669 reqlen = NFS_SRVMAXDATA(nd);
670 } else if (reqlen < 0) {
674 if (nd->nd_flag & ND_NFSV4) {
675 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
676 lop->lo_flags = NFSLCK_READ;
677 stp->ls_ownerlen = 0;
679 stp->ls_uid = nd->nd_cred->cr_uid;
680 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
681 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
682 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
683 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
684 if ((nd->nd_flag & ND_NFSV41) != 0)
685 clientid.qval = nd->nd_clientid.qval;
686 else if (nd->nd_clientid.qval != clientid.qval)
687 printf("EEK1 multiple clids\n");
689 if ((nd->nd_flag & ND_NFSV41) != 0)
690 printf("EEK! no clientid from session\n");
691 nd->nd_flag |= ND_IMPLIEDCLID;
692 nd->nd_clientid.qval = clientid.qval;
694 stp->ls_stateid.other[2] = *tl++;
695 off = fxdr_hyper(tl);
698 lop->lo_end = off + reqlen;
700 * Paranoia, just in case it wraps around.
702 if (lop->lo_end < off)
703 lop->lo_end = NFS64BITSSET;
705 if (vnode_vtype(vp) != VREG) {
706 if (nd->nd_flag & ND_NFSV3)
707 nd->nd_repstat = EINVAL;
709 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
712 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
714 nd->nd_repstat = getret;
715 if (!nd->nd_repstat &&
716 (nva.na_uid != nd->nd_cred->cr_uid ||
717 NFSVNO_EXSTRICTACCESS(exp))) {
718 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
720 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
722 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
723 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
724 NFSACCCHK_VPISLOCKED, NULL);
726 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
727 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
728 &stateid, exp, nd, p);
729 if (nd->nd_repstat) {
731 if (nd->nd_flag & ND_NFSV3)
732 nfsrv_postopattr(nd, getret, &nva);
735 if (off >= nva.na_size) {
738 } else if (reqlen == 0)
740 else if ((off + reqlen) >= nva.na_size) {
741 cnt = nva.na_size - off;
747 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
749 if (!(nd->nd_flag & ND_NFSV4)) {
750 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
752 nd->nd_repstat = getret;
754 if (nd->nd_repstat) {
758 if (nd->nd_flag & ND_NFSV3)
759 nfsrv_postopattr(nd, getret, &nva);
764 if (nd->nd_flag & ND_NFSV2) {
765 nfsrv_fillattr(nd, &nva);
766 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
768 if (nd->nd_flag & ND_NFSV3) {
769 nfsrv_postopattr(nd, getret, &nva);
770 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
771 *tl++ = txdr_unsigned(cnt);
773 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
777 *tl++ = newnfs_false;
779 *tl = txdr_unsigned(cnt);
781 mbuf_setnext(nd->nd_mb, m3);
783 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
791 NFSEXITCODE2(error, nd);
799 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
800 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
805 struct nfsvattr nva, forat;
806 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
807 int stable = NFSWRITE_FILESYNC;
809 struct nfsstate st, *stp = &st;
810 struct nfslock lo, *lop = &lo;
811 nfsv4stateid_t stateid;
814 if (nd->nd_repstat) {
815 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
818 if (nd->nd_flag & ND_NFSV2) {
819 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
820 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
822 retlen = len = fxdr_unsigned(int32_t, *tl);
823 } else if (nd->nd_flag & ND_NFSV3) {
824 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
825 off = fxdr_hyper(tl);
827 stable = fxdr_unsigned(int, *tl++);
828 retlen = len = fxdr_unsigned(int32_t, *tl);
830 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
831 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
832 lop->lo_flags = NFSLCK_WRITE;
833 stp->ls_ownerlen = 0;
835 stp->ls_uid = nd->nd_cred->cr_uid;
836 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
837 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
838 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
839 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
840 if ((nd->nd_flag & ND_NFSV41) != 0)
841 clientid.qval = nd->nd_clientid.qval;
842 else if (nd->nd_clientid.qval != clientid.qval)
843 printf("EEK2 multiple clids\n");
845 if ((nd->nd_flag & ND_NFSV41) != 0)
846 printf("EEK! no clientid from session\n");
847 nd->nd_flag |= ND_IMPLIEDCLID;
848 nd->nd_clientid.qval = clientid.qval;
850 stp->ls_stateid.other[2] = *tl++;
851 off = fxdr_hyper(tl);
854 stable = fxdr_unsigned(int, *tl++);
855 retlen = len = fxdr_unsigned(int32_t, *tl);
856 lop->lo_end = off + len;
858 * Paranoia, just in case it wraps around, which shouldn't
859 * ever happen anyhow.
861 if (lop->lo_end < lop->lo_first)
862 lop->lo_end = NFS64BITSSET;
866 * Loop through the mbuf chain, counting how many mbufs are a
867 * part of this write operation, so the iovec size is known.
871 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
887 if (retlen > NFS_SRVMAXIO || retlen < 0)
888 nd->nd_repstat = EIO;
889 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
890 if (nd->nd_flag & ND_NFSV3)
891 nd->nd_repstat = EINVAL;
893 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
896 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
898 nd->nd_repstat = forat_ret;
899 if (!nd->nd_repstat &&
900 (forat.na_uid != nd->nd_cred->cr_uid ||
901 NFSVNO_EXSTRICTACCESS(exp)))
902 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
904 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
905 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
906 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
907 &stateid, exp, nd, p);
909 if (nd->nd_repstat) {
911 if (nd->nd_flag & ND_NFSV3)
912 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
917 * For NFS Version 2, it is not obvious what a write of zero length
918 * should do, but I might as well be consistent with Version 3,
919 * which is to return ok so long as there are no permission problems.
922 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
923 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
924 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
928 if (nd->nd_flag & ND_NFSV4)
931 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
934 nd->nd_repstat = aftat_ret;
935 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
936 if (nd->nd_flag & ND_NFSV3)
937 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
940 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
941 *tl++ = txdr_unsigned(retlen);
943 * If nfs_async is set, then pretend the write was FILESYNC.
944 * Warning: Doing this violates RFC1813 and runs a risk
945 * of data written by a client being lost when the server
948 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
949 *tl++ = txdr_unsigned(stable);
951 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
953 * Actually, there is no need to txdr these fields,
954 * but it may make the values more human readable,
955 * for debugging purposes.
957 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
958 *tl = txdr_unsigned(nfsboottime.tv_usec);
959 } else if (!nd->nd_repstat)
960 nfsrv_fillattr(nd, &nva);
967 NFSEXITCODE2(error, nd);
972 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
973 * now does a truncate to 0 length via. setattr if it already exists
974 * The core creation routine has been extracted out into nfsrv_creatsub(),
975 * so it can also be used by nfsrv_open() for V4.
978 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
979 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
981 struct nfsvattr nva, dirfor, diraft;
982 struct nfsv2_sattr *sp;
983 struct nameidata named;
985 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
986 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
988 vnode_t vp = NULL, dirp = NULL;
993 int32_t cverf[2], tverf[2] = { 0, 0 };
995 if (nd->nd_repstat) {
996 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
999 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1000 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
1001 nfsvno_setpathbuf(&named, &bufp, &hashp);
1002 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1005 if (!nd->nd_repstat) {
1006 NFSVNO_ATTRINIT(&nva);
1007 if (nd->nd_flag & ND_NFSV2) {
1008 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1009 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1012 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1013 NFSVNO_SETATTRVAL(&nva, mode,
1014 nfstov_mode(sp->sa_mode));
1015 switch (nva.na_type) {
1017 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1019 NFSVNO_SETATTRVAL(&nva, size,
1025 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1032 how = fxdr_unsigned(int, *tl);
1034 case NFSCREATE_GUARDED:
1035 case NFSCREATE_UNCHECKED:
1036 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1040 case NFSCREATE_EXCLUSIVE:
1041 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1047 NFSVNO_SETATTRVAL(&nva, type, VREG);
1050 if (nd->nd_repstat) {
1051 nfsvno_relpathbuf(&named);
1052 if (nd->nd_flag & ND_NFSV3) {
1053 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1055 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1062 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1064 if (nd->nd_flag & ND_NFSV2) {
1068 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1072 if (nd->nd_repstat) {
1073 if (nd->nd_flag & ND_NFSV3)
1074 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1081 if (!(nd->nd_flag & ND_NFSV2)) {
1083 case NFSCREATE_GUARDED:
1085 nd->nd_repstat = EEXIST;
1087 case NFSCREATE_UNCHECKED:
1089 case NFSCREATE_EXCLUSIVE:
1090 if (named.ni_vp == NULL)
1091 NFSVNO_SETATTRVAL(&nva, mode, 0);
1097 * Iff doesn't exist, create it
1098 * otherwise just truncate to 0 length
1099 * should I set the mode too ?
1101 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1102 &exclusive_flag, cverf, rdev, p, exp);
1104 if (!nd->nd_repstat) {
1105 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1106 if (!nd->nd_repstat)
1107 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1110 if (!nd->nd_repstat) {
1111 tverf[0] = nva.na_atime.tv_sec;
1112 tverf[1] = nva.na_atime.tv_nsec;
1115 if (nd->nd_flag & ND_NFSV2) {
1116 if (!nd->nd_repstat) {
1117 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1118 nfsrv_fillattr(nd, &nva);
1121 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1122 || cverf[1] != tverf[1]))
1123 nd->nd_repstat = EEXIST;
1124 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1126 if (!nd->nd_repstat) {
1127 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1128 nfsrv_postopattr(nd, 0, &nva);
1130 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1134 NFSEXITCODE2(0, nd);
1138 nfsvno_relpathbuf(&named);
1139 NFSEXITCODE2(error, nd);
1144 * nfs v3 mknod service (and v4 create)
1147 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1148 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1149 struct nfsexstuff *exp)
1151 struct nfsvattr nva, dirfor, diraft;
1153 struct nameidata named;
1154 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1155 u_int32_t major, minor;
1156 enum vtype vtyp = VNON;
1157 nfstype nfs4type = NFNON;
1158 vnode_t vp, dirp = NULL;
1159 nfsattrbit_t attrbits;
1160 char *bufp = NULL, *pathcp = NULL;
1161 u_long *hashp, cnflags;
1162 NFSACL_T *aclp = NULL;
1164 NFSVNO_ATTRINIT(&nva);
1165 cnflags = (LOCKPARENT | SAVESTART);
1166 if (nd->nd_repstat) {
1167 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1170 #ifdef NFS4_ACL_EXTATTR_NAME
1171 aclp = acl_alloc(M_WAITOK);
1176 * For V4, the creation stuff is here, Yuck!
1178 if (nd->nd_flag & ND_NFSV4) {
1179 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1180 vtyp = nfsv34tov_type(*tl);
1181 nfs4type = fxdr_unsigned(nfstype, *tl);
1184 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1191 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1192 major = fxdr_unsigned(u_int32_t, *tl++);
1193 minor = fxdr_unsigned(u_int32_t, *tl);
1194 nva.na_rdev = NFSMAKEDEV(major, minor);
1200 cnflags = (LOCKPARENT | SAVENAME);
1203 nd->nd_repstat = NFSERR_BADTYPE;
1205 #ifdef NFS4_ACL_EXTATTR_NAME
1211 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1212 nfsvno_setpathbuf(&named, &bufp, &hashp);
1213 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1216 if (!nd->nd_repstat) {
1217 if (nd->nd_flag & ND_NFSV3) {
1218 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1219 vtyp = nfsv34tov_type(*tl);
1221 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1225 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1226 (vtyp == VCHR || vtyp == VBLK)) {
1227 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1228 major = fxdr_unsigned(u_int32_t, *tl++);
1229 minor = fxdr_unsigned(u_int32_t, *tl);
1230 nva.na_rdev = NFSMAKEDEV(major, minor);
1234 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1235 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1236 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1237 dirfor.na_gid == nva.na_gid)
1238 NFSVNO_UNSET(&nva, gid);
1239 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1241 if (nd->nd_repstat) {
1243 #ifdef NFS4_ACL_EXTATTR_NAME
1246 nfsvno_relpathbuf(&named);
1248 FREE(pathcp, M_TEMP);
1249 if (nd->nd_flag & ND_NFSV3)
1250 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1256 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1257 * in va_mode, so we'll have to set a default here.
1259 if (NFSVNO_NOTSETMODE(&nva)) {
1267 named.ni_cnd.cn_flags |= WILLBEDIR;
1268 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1269 if (nd->nd_repstat) {
1271 if (nd->nd_flag & ND_NFSV3)
1272 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1276 #ifdef NFS4_ACL_EXTATTR_NAME
1279 if (nd->nd_flag & ND_NFSV3)
1280 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1285 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1287 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1289 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1290 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1292 #ifdef NFS4_ACL_EXTATTR_NAME
1296 } else if (vtyp == VLNK) {
1297 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1298 &dirfor, &diraft, &diraft_ret, &attrbits,
1299 aclp, p, exp, pathcp, pathlen);
1300 #ifdef NFS4_ACL_EXTATTR_NAME
1303 FREE(pathcp, M_TEMP);
1308 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1309 if (!nd->nd_repstat) {
1311 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1312 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1313 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1314 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1316 if (vpp != NULL && nd->nd_repstat == 0) {
1317 NFSVOPUNLOCK(vp, 0);
1323 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1325 if (!nd->nd_repstat) {
1326 if (nd->nd_flag & ND_NFSV3) {
1327 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1328 nfsrv_postopattr(nd, 0, &nva);
1330 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1331 *tl++ = newnfs_false;
1332 txdr_hyper(dirfor.na_filerev, tl);
1334 txdr_hyper(diraft.na_filerev, tl);
1335 (void) nfsrv_putattrbit(nd, &attrbits);
1338 if (nd->nd_flag & ND_NFSV3)
1339 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1340 #ifdef NFS4_ACL_EXTATTR_NAME
1345 NFSEXITCODE2(0, nd);
1349 #ifdef NFS4_ACL_EXTATTR_NAME
1353 nfsvno_relpathbuf(&named);
1355 FREE(pathcp, M_TEMP);
1357 NFSEXITCODE2(error, nd);
1362 * nfs remove service
1365 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1366 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1368 struct nameidata named;
1370 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1371 vnode_t dirp = NULL;
1372 struct nfsvattr dirfor, diraft;
1376 if (nd->nd_repstat) {
1377 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1380 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1381 LOCKPARENT | LOCKLEAF);
1382 nfsvno_setpathbuf(&named, &bufp, &hashp);
1383 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1386 nfsvno_relpathbuf(&named);
1389 if (!nd->nd_repstat) {
1390 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1393 nfsvno_relpathbuf(&named);
1396 if (!(nd->nd_flag & ND_NFSV2)) {
1397 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1404 if (!nd->nd_repstat) {
1405 if (nd->nd_flag & ND_NFSV4) {
1406 if (vnode_vtype(named.ni_vp) == VDIR)
1407 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1408 nd->nd_cred, p, exp);
1410 nd->nd_repstat = nfsvno_removesub(&named, 1,
1411 nd->nd_cred, p, exp);
1412 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1413 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1414 nd->nd_cred, p, exp);
1416 nd->nd_repstat = nfsvno_removesub(&named, 0,
1417 nd->nd_cred, p, exp);
1420 if (!(nd->nd_flag & ND_NFSV2)) {
1422 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1426 if (nd->nd_flag & ND_NFSV3) {
1427 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1429 } else if (!nd->nd_repstat) {
1430 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1431 *tl++ = newnfs_false;
1432 txdr_hyper(dirfor.na_filerev, tl);
1434 txdr_hyper(diraft.na_filerev, tl);
1439 NFSEXITCODE2(error, nd);
1444 * nfs rename service
1447 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1448 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1449 struct nfsexstuff *toexp)
1452 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1453 int tdirfor_ret = 1, tdiraft_ret = 1;
1454 struct nameidata fromnd, tond;
1455 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1456 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1457 struct nfsexstuff tnes;
1459 char *bufp, *tbufp = NULL;
1463 if (nd->nd_repstat) {
1464 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1465 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1468 if (!(nd->nd_flag & ND_NFSV2))
1469 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1470 tond.ni_cnd.cn_nameiop = 0;
1471 tond.ni_startdir = NULL;
1472 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1473 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1474 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1479 nfsvno_relpathbuf(&fromnd);
1483 * Unlock dp in this code section, so it is unlocked before
1484 * tdp gets locked. This avoids a potential LOR if tdp is the
1485 * parent directory of dp.
1487 if (nd->nd_flag & ND_NFSV4) {
1491 NFSVOPUNLOCK(dp, 0);
1492 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1493 p, 0); /* Might lock tdp. */
1495 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1497 NFSVOPUNLOCK(dp, 0);
1500 tfh.nfsrvfh_len = 0;
1501 error = nfsrv_mtofh(nd, &tfh);
1503 error = nfsvno_getfh(dp, &fh, p);
1506 /* todp is always NULL except NFSv4 */
1507 nfsvno_relpathbuf(&fromnd);
1511 /* If this is the same file handle, just VREF() the vnode. */
1512 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1513 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1517 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1519 NFSVOPUNLOCK(dp, 0);
1521 NFSVOPUNLOCK(dp, 0);
1522 nd->nd_cred->cr_uid = nd->nd_saveduid;
1523 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1524 0, p); /* Locks tdp. */
1526 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1528 NFSVOPUNLOCK(tdp, 0);
1532 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1533 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1534 if (!nd->nd_repstat) {
1535 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1540 nfsvno_relpathbuf(&fromnd);
1541 nfsvno_relpathbuf(&tond);
1545 if (nd->nd_repstat) {
1546 if (nd->nd_flag & ND_NFSV3) {
1547 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1549 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1555 nfsvno_relpathbuf(&fromnd);
1556 nfsvno_relpathbuf(&tond);
1561 * Done parsing, now down to business.
1563 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1564 if (nd->nd_repstat) {
1565 if (nd->nd_flag & ND_NFSV3) {
1566 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1568 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1575 nfsvno_relpathbuf(&tond);
1578 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1579 tond.ni_cnd.cn_flags |= WILLBEDIR;
1580 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1581 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1582 nd->nd_flag, nd->nd_cred, p);
1584 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1587 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1593 if (nd->nd_flag & ND_NFSV3) {
1594 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1595 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1596 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1597 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1598 *tl++ = newnfs_false;
1599 txdr_hyper(fdirfor.na_filerev, tl);
1601 txdr_hyper(fdiraft.na_filerev, tl);
1603 *tl++ = newnfs_false;
1604 txdr_hyper(tdirfor.na_filerev, tl);
1606 txdr_hyper(tdiraft.na_filerev, tl);
1610 NFSEXITCODE2(error, nd);
1618 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1619 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1620 struct nfsexstuff *toexp)
1622 struct nameidata named;
1624 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1625 vnode_t dirp = NULL, dp = NULL;
1626 struct nfsvattr dirfor, diraft, at;
1627 struct nfsexstuff tnes;
1632 if (nd->nd_repstat) {
1633 nfsrv_postopattr(nd, getret, &at);
1634 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1637 NFSVOPUNLOCK(vp, 0);
1638 if (vnode_vtype(vp) == VDIR) {
1639 if (nd->nd_flag & ND_NFSV4)
1640 nd->nd_repstat = NFSERR_ISDIR;
1642 nd->nd_repstat = NFSERR_INVAL;
1646 if (!nd->nd_repstat) {
1647 if (nd->nd_flag & ND_NFSV4) {
1651 error = nfsrv_mtofh(nd, &dfh);
1654 /* tovp is always NULL unless NFSv4 */
1657 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1660 NFSVOPUNLOCK(dp, 0);
1663 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1664 LOCKPARENT | SAVENAME | NOCACHE);
1665 if (!nd->nd_repstat) {
1666 nfsvno_setpathbuf(&named, &bufp, &hashp);
1667 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1672 nfsvno_relpathbuf(&named);
1675 if (!nd->nd_repstat) {
1676 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1681 nfsvno_relpathbuf(&named);
1685 if (nd->nd_flag & ND_NFSV2) {
1689 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1693 if (!nd->nd_repstat)
1694 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1695 if (nd->nd_flag & ND_NFSV3)
1696 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1698 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1702 if (nd->nd_flag & ND_NFSV3) {
1703 nfsrv_postopattr(nd, getret, &at);
1704 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1705 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1706 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1707 *tl++ = newnfs_false;
1708 txdr_hyper(dirfor.na_filerev, tl);
1710 txdr_hyper(diraft.na_filerev, tl);
1714 NFSEXITCODE2(error, nd);
1719 * nfs symbolic link service
1722 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1723 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1724 struct nfsexstuff *exp)
1726 struct nfsvattr nva, dirfor, diraft;
1727 struct nameidata named;
1728 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1729 vnode_t dirp = NULL;
1730 char *bufp, *pathcp = NULL;
1733 if (nd->nd_repstat) {
1734 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1739 NFSVNO_ATTRINIT(&nva);
1740 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1741 LOCKPARENT | SAVESTART | NOCACHE);
1742 nfsvno_setpathbuf(&named, &bufp, &hashp);
1743 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1744 if (!error && !nd->nd_repstat)
1745 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1748 nfsvno_relpathbuf(&named);
1751 if (!nd->nd_repstat) {
1752 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1755 nfsvno_relpathbuf(&named);
1757 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1763 * And call nfsrvd_symlinksub() to do the common code. It will
1764 * return EBADRPC upon a parsing error, 0 otherwise.
1766 if (!nd->nd_repstat) {
1768 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1770 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1771 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1773 } else if (dirp != NULL) {
1774 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1778 FREE(pathcp, M_TEMP);
1780 if (nd->nd_flag & ND_NFSV3) {
1781 if (!nd->nd_repstat) {
1782 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1783 nfsrv_postopattr(nd, 0, &nva);
1785 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1789 NFSEXITCODE2(error, nd);
1794 * Common code for creating a symbolic link.
1797 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1798 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1799 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1800 int *diraft_retp, nfsattrbit_t *attrbitp,
1801 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1806 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1807 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1808 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1809 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1810 if (nd->nd_flag & ND_NFSV3) {
1811 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1812 if (!nd->nd_repstat)
1813 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1814 nvap, nd->nd_cred, p, 1);
1816 if (vpp != NULL && nd->nd_repstat == 0) {
1817 NFSVOPUNLOCK(ndp->ni_vp, 0);
1823 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1826 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1827 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1828 *tl++ = newnfs_false;
1829 txdr_hyper(dirforp->na_filerev, tl);
1831 txdr_hyper(diraftp->na_filerev, tl);
1832 (void) nfsrv_putattrbit(nd, attrbitp);
1835 NFSEXITCODE2(0, nd);
1842 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1843 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1844 struct nfsexstuff *exp)
1846 struct nfsvattr nva, dirfor, diraft;
1847 struct nameidata named;
1849 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1850 vnode_t dirp = NULL;
1854 if (nd->nd_repstat) {
1855 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1858 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1859 LOCKPARENT | SAVENAME | NOCACHE);
1860 nfsvno_setpathbuf(&named, &bufp, &hashp);
1861 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1864 if (!nd->nd_repstat) {
1865 NFSVNO_ATTRINIT(&nva);
1866 if (nd->nd_flag & ND_NFSV3) {
1867 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1871 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1872 nva.na_mode = nfstov_mode(*tl++);
1875 if (!nd->nd_repstat) {
1876 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1879 nfsvno_relpathbuf(&named);
1881 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1885 if (nd->nd_repstat) {
1887 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1891 if (nd->nd_flag & ND_NFSV3)
1892 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1897 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1900 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1902 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1903 &diraft_ret, NULL, NULL, p, exp);
1905 if (nd->nd_flag & ND_NFSV3) {
1906 if (!nd->nd_repstat) {
1907 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1908 nfsrv_postopattr(nd, 0, &nva);
1910 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1911 } else if (!nd->nd_repstat) {
1912 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1913 nfsrv_fillattr(nd, &nva);
1917 NFSEXITCODE2(0, nd);
1921 nfsvno_relpathbuf(&named);
1922 NFSEXITCODE2(error, nd);
1927 * Code common to mkdir for V2,3 and 4.
1930 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1931 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1932 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1933 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1934 NFSPROC_T *p, struct nfsexstuff *exp)
1939 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1940 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1941 nd->nd_cred, p, exp);
1942 if (!nd->nd_repstat) {
1944 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1945 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1946 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1947 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1949 if (vpp && !nd->nd_repstat) {
1950 NFSVOPUNLOCK(vp, 0);
1957 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1960 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1961 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1962 *tl++ = newnfs_false;
1963 txdr_hyper(dirforp->na_filerev, tl);
1965 txdr_hyper(diraftp->na_filerev, tl);
1966 (void) nfsrv_putattrbit(nd, attrbitp);
1969 NFSEXITCODE2(0, nd);
1973 * nfs commit service
1976 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1977 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1979 struct nfsvattr bfor, aft;
1981 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1984 if (nd->nd_repstat) {
1985 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1989 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
1990 if (vp->v_type != VREG) {
1991 if (nd->nd_flag & ND_NFSV3)
1992 error = NFSERR_NOTSUPP;
1994 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
1997 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2000 * XXX At this time VOP_FSYNC() does not accept offset and byte
2001 * count parameters, so these arguments are useless (someday maybe).
2003 off = fxdr_hyper(tl);
2005 cnt = fxdr_unsigned(int, *tl);
2006 if (nd->nd_flag & ND_NFSV3)
2007 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
2008 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2009 if (nd->nd_flag & ND_NFSV3) {
2010 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
2011 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2014 if (!nd->nd_repstat) {
2015 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2016 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2017 *tl = txdr_unsigned(nfsboottime.tv_usec);
2021 NFSEXITCODE2(0, nd);
2025 NFSEXITCODE2(error, nd);
2030 * nfs statfs service
2033 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2034 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2043 if (nd->nd_repstat) {
2044 nfsrv_postopattr(nd, getret, &at);
2047 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2048 nd->nd_repstat = nfsvno_statfs(vp, sf);
2049 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2051 if (nd->nd_flag & ND_NFSV3)
2052 nfsrv_postopattr(nd, getret, &at);
2055 if (nd->nd_flag & ND_NFSV2) {
2056 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2057 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2058 *tl++ = txdr_unsigned(sf->f_bsize);
2059 *tl++ = txdr_unsigned(sf->f_blocks);
2060 *tl++ = txdr_unsigned(sf->f_bfree);
2061 *tl = txdr_unsigned(sf->f_bavail);
2063 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2064 tval = (u_quad_t)sf->f_blocks;
2065 tval *= (u_quad_t)sf->f_bsize;
2066 txdr_hyper(tval, tl); tl += 2;
2067 tval = (u_quad_t)sf->f_bfree;
2068 tval *= (u_quad_t)sf->f_bsize;
2069 txdr_hyper(tval, tl); tl += 2;
2070 tval = (u_quad_t)sf->f_bavail;
2071 tval *= (u_quad_t)sf->f_bsize;
2072 txdr_hyper(tval, tl); tl += 2;
2073 tval = (u_quad_t)sf->f_files;
2074 txdr_hyper(tval, tl); tl += 2;
2075 tval = (u_quad_t)sf->f_ffree;
2076 txdr_hyper(tval, tl); tl += 2;
2077 tval = (u_quad_t)sf->f_ffree;
2078 txdr_hyper(tval, tl); tl += 2;
2084 NFSEXITCODE2(0, nd);
2089 * nfs fsinfo service
2092 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2093 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2096 struct nfsfsinfo fs;
2100 if (nd->nd_repstat) {
2101 nfsrv_postopattr(nd, getret, &at);
2104 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2105 nfsvno_getfs(&fs, isdgram);
2107 nfsrv_postopattr(nd, getret, &at);
2108 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2109 *tl++ = txdr_unsigned(fs.fs_rtmax);
2110 *tl++ = txdr_unsigned(fs.fs_rtpref);
2111 *tl++ = txdr_unsigned(fs.fs_rtmult);
2112 *tl++ = txdr_unsigned(fs.fs_wtmax);
2113 *tl++ = txdr_unsigned(fs.fs_wtpref);
2114 *tl++ = txdr_unsigned(fs.fs_wtmult);
2115 *tl++ = txdr_unsigned(fs.fs_dtpref);
2116 txdr_hyper(fs.fs_maxfilesize, tl);
2118 txdr_nfsv3time(&fs.fs_timedelta, tl);
2120 *tl = txdr_unsigned(fs.fs_properties);
2123 NFSEXITCODE2(0, nd);
2128 * nfs pathconf service
2131 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2132 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2134 struct nfsv3_pathconf *pc;
2136 register_t linkmax, namemax, chownres, notrunc;
2139 if (nd->nd_repstat) {
2140 nfsrv_postopattr(nd, getret, &at);
2143 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2145 if (!nd->nd_repstat)
2146 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2148 if (!nd->nd_repstat)
2149 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2150 &chownres, nd->nd_cred, p);
2151 if (!nd->nd_repstat)
2152 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2154 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2156 nfsrv_postopattr(nd, getret, &at);
2157 if (!nd->nd_repstat) {
2158 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2159 pc->pc_linkmax = txdr_unsigned(linkmax);
2160 pc->pc_namemax = txdr_unsigned(namemax);
2161 pc->pc_notrunc = txdr_unsigned(notrunc);
2162 pc->pc_chownrestricted = txdr_unsigned(chownres);
2165 * These should probably be supported by VOP_PATHCONF(), but
2166 * until msdosfs is exportable (why would you want to?), the
2167 * Unix defaults should be ok.
2169 pc->pc_caseinsensitive = newnfs_false;
2170 pc->pc_casepreserving = newnfs_true;
2174 NFSEXITCODE2(0, nd);
2179 * nfsv4 lock service
2182 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2183 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2187 struct nfsstate *stp = NULL;
2188 struct nfslock *lop;
2189 struct nfslockconflict cf;
2191 u_short flags = NFSLCK_LOCK, lflags;
2192 u_int64_t offset, len;
2193 nfsv4stateid_t stateid;
2196 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2197 i = fxdr_unsigned(int, *tl++);
2199 case NFSV4LOCKT_READW:
2200 flags |= NFSLCK_BLOCKING;
2201 case NFSV4LOCKT_READ:
2202 lflags = NFSLCK_READ;
2204 case NFSV4LOCKT_WRITEW:
2205 flags |= NFSLCK_BLOCKING;
2206 case NFSV4LOCKT_WRITE:
2207 lflags = NFSLCK_WRITE;
2210 nd->nd_repstat = NFSERR_BADXDR;
2213 if (*tl++ == newnfs_true)
2214 flags |= NFSLCK_RECLAIM;
2215 offset = fxdr_hyper(tl);
2217 len = fxdr_hyper(tl);
2219 if (*tl == newnfs_true)
2220 flags |= NFSLCK_OPENTOLOCK;
2221 if (flags & NFSLCK_OPENTOLOCK) {
2222 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2223 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2224 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2225 nd->nd_repstat = NFSERR_BADXDR;
2228 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2229 M_NFSDSTATE, M_WAITOK);
2230 stp->ls_ownerlen = i;
2231 stp->ls_op = nd->nd_rp;
2232 stp->ls_seq = fxdr_unsigned(int, *tl++);
2233 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2234 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2236 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2237 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2238 clientid.lval[0] = *tl++;
2239 clientid.lval[1] = *tl++;
2240 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2241 if ((nd->nd_flag & ND_NFSV41) != 0)
2242 clientid.qval = nd->nd_clientid.qval;
2243 else if (nd->nd_clientid.qval != clientid.qval)
2244 printf("EEK3 multiple clids\n");
2246 if ((nd->nd_flag & ND_NFSV41) != 0)
2247 printf("EEK! no clientid from session\n");
2248 nd->nd_flag |= ND_IMPLIEDCLID;
2249 nd->nd_clientid.qval = clientid.qval;
2251 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2255 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2256 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2257 M_NFSDSTATE, M_WAITOK);
2258 stp->ls_ownerlen = 0;
2259 stp->ls_op = nd->nd_rp;
2260 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2261 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2263 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2264 stp->ls_seq = fxdr_unsigned(int, *tl);
2265 clientid.lval[0] = stp->ls_stateid.other[0];
2266 clientid.lval[1] = stp->ls_stateid.other[1];
2267 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2268 if ((nd->nd_flag & ND_NFSV41) != 0)
2269 clientid.qval = nd->nd_clientid.qval;
2270 else if (nd->nd_clientid.qval != clientid.qval)
2271 printf("EEK4 multiple clids\n");
2273 if ((nd->nd_flag & ND_NFSV41) != 0)
2274 printf("EEK! no clientid from session\n");
2275 nd->nd_flag |= ND_IMPLIEDCLID;
2276 nd->nd_clientid.qval = clientid.qval;
2279 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2280 M_NFSDLOCK, M_WAITOK);
2281 lop->lo_first = offset;
2282 if (len == NFS64BITSSET) {
2283 lop->lo_end = NFS64BITSSET;
2285 lop->lo_end = offset + len;
2286 if (lop->lo_end <= lop->lo_first)
2287 nd->nd_repstat = NFSERR_INVAL;
2289 lop->lo_flags = lflags;
2290 stp->ls_flags = flags;
2291 stp->ls_uid = nd->nd_cred->cr_uid;
2294 * Do basic access checking.
2296 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2297 if (vnode_vtype(vp) == VDIR)
2298 nd->nd_repstat = NFSERR_ISDIR;
2300 nd->nd_repstat = NFSERR_INVAL;
2302 if (!nd->nd_repstat) {
2303 if (lflags & NFSLCK_WRITE) {
2304 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2305 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2306 NFSACCCHK_VPISLOCKED, NULL);
2308 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2309 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2310 NFSACCCHK_VPISLOCKED, NULL);
2312 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2313 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2314 NFSACCCHK_VPISLOCKED, NULL);
2319 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2320 * seqid# gets updated. nfsrv_lockctrl() will return the value
2321 * of nd_repstat, if it gets that far.
2323 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2324 &stateid, exp, nd, p);
2326 FREE((caddr_t)lop, M_NFSDLOCK);
2328 FREE((caddr_t)stp, M_NFSDSTATE);
2329 if (!nd->nd_repstat) {
2330 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2331 *tl++ = txdr_unsigned(stateid.seqid);
2332 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2333 } else if (nd->nd_repstat == NFSERR_DENIED) {
2334 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2335 txdr_hyper(cf.cl_first, tl);
2337 if (cf.cl_end == NFS64BITSSET)
2340 len = cf.cl_end - cf.cl_first;
2341 txdr_hyper(len, tl);
2343 if (cf.cl_flags == NFSLCK_WRITE)
2344 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2346 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2347 *tl++ = stateid.other[0];
2348 *tl = stateid.other[1];
2349 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2352 NFSEXITCODE2(0, nd);
2357 free((caddr_t)stp, M_NFSDSTATE);
2358 NFSEXITCODE2(error, nd);
2363 * nfsv4 lock test service
2366 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2367 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2371 struct nfsstate *stp = NULL;
2372 struct nfslock lo, *lop = &lo;
2373 struct nfslockconflict cf;
2375 nfsv4stateid_t stateid;
2379 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2380 i = fxdr_unsigned(int, *(tl + 7));
2381 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2382 nd->nd_repstat = NFSERR_BADXDR;
2385 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2386 M_NFSDSTATE, M_WAITOK);
2387 stp->ls_ownerlen = i;
2389 stp->ls_flags = NFSLCK_TEST;
2390 stp->ls_uid = nd->nd_cred->cr_uid;
2391 i = fxdr_unsigned(int, *tl++);
2393 case NFSV4LOCKT_READW:
2394 stp->ls_flags |= NFSLCK_BLOCKING;
2395 case NFSV4LOCKT_READ:
2396 lo.lo_flags = NFSLCK_READ;
2398 case NFSV4LOCKT_WRITEW:
2399 stp->ls_flags |= NFSLCK_BLOCKING;
2400 case NFSV4LOCKT_WRITE:
2401 lo.lo_flags = NFSLCK_WRITE;
2404 nd->nd_repstat = NFSERR_BADXDR;
2407 lo.lo_first = fxdr_hyper(tl);
2409 len = fxdr_hyper(tl);
2410 if (len == NFS64BITSSET) {
2411 lo.lo_end = NFS64BITSSET;
2413 lo.lo_end = lo.lo_first + len;
2414 if (lo.lo_end <= lo.lo_first)
2415 nd->nd_repstat = NFSERR_INVAL;
2418 clientid.lval[0] = *tl++;
2419 clientid.lval[1] = *tl;
2420 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2421 if ((nd->nd_flag & ND_NFSV41) != 0)
2422 clientid.qval = nd->nd_clientid.qval;
2423 else if (nd->nd_clientid.qval != clientid.qval)
2424 printf("EEK5 multiple clids\n");
2426 if ((nd->nd_flag & ND_NFSV41) != 0)
2427 printf("EEK! no clientid from session\n");
2428 nd->nd_flag |= ND_IMPLIEDCLID;
2429 nd->nd_clientid.qval = clientid.qval;
2431 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2434 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2435 if (vnode_vtype(vp) == VDIR)
2436 nd->nd_repstat = NFSERR_ISDIR;
2438 nd->nd_repstat = NFSERR_INVAL;
2440 if (!nd->nd_repstat)
2441 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2442 &stateid, exp, nd, p);
2443 if (nd->nd_repstat) {
2444 if (nd->nd_repstat == NFSERR_DENIED) {
2445 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2446 txdr_hyper(cf.cl_first, tl);
2448 if (cf.cl_end == NFS64BITSSET)
2451 len = cf.cl_end - cf.cl_first;
2452 txdr_hyper(len, tl);
2454 if (cf.cl_flags == NFSLCK_WRITE)
2455 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2457 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2458 *tl++ = stp->ls_stateid.other[0];
2459 *tl = stp->ls_stateid.other[1];
2460 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2465 FREE((caddr_t)stp, M_NFSDSTATE);
2466 NFSEXITCODE2(0, nd);
2471 free((caddr_t)stp, M_NFSDSTATE);
2472 NFSEXITCODE2(error, nd);
2477 * nfsv4 unlock service
2480 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2481 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2485 struct nfsstate *stp;
2486 struct nfslock *lop;
2488 nfsv4stateid_t stateid;
2492 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2493 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2494 M_NFSDSTATE, M_WAITOK);
2495 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2496 M_NFSDLOCK, M_WAITOK);
2497 stp->ls_flags = NFSLCK_UNLOCK;
2498 lop->lo_flags = NFSLCK_UNLOCK;
2499 stp->ls_op = nd->nd_rp;
2500 i = fxdr_unsigned(int, *tl++);
2502 case NFSV4LOCKT_READW:
2503 stp->ls_flags |= NFSLCK_BLOCKING;
2504 case NFSV4LOCKT_READ:
2506 case NFSV4LOCKT_WRITEW:
2507 stp->ls_flags |= NFSLCK_BLOCKING;
2508 case NFSV4LOCKT_WRITE:
2511 nd->nd_repstat = NFSERR_BADXDR;
2512 free(stp, M_NFSDSTATE);
2513 free(lop, M_NFSDLOCK);
2516 stp->ls_ownerlen = 0;
2517 stp->ls_uid = nd->nd_cred->cr_uid;
2518 stp->ls_seq = fxdr_unsigned(int, *tl++);
2519 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2520 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2522 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2523 lop->lo_first = fxdr_hyper(tl);
2525 len = fxdr_hyper(tl);
2526 if (len == NFS64BITSSET) {
2527 lop->lo_end = NFS64BITSSET;
2529 lop->lo_end = lop->lo_first + len;
2530 if (lop->lo_end <= lop->lo_first)
2531 nd->nd_repstat = NFSERR_INVAL;
2533 clientid.lval[0] = stp->ls_stateid.other[0];
2534 clientid.lval[1] = stp->ls_stateid.other[1];
2535 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2536 if ((nd->nd_flag & ND_NFSV41) != 0)
2537 clientid.qval = nd->nd_clientid.qval;
2538 else if (nd->nd_clientid.qval != clientid.qval)
2539 printf("EEK6 multiple clids\n");
2541 if ((nd->nd_flag & ND_NFSV41) != 0)
2542 printf("EEK! no clientid from session\n");
2543 nd->nd_flag |= ND_IMPLIEDCLID;
2544 nd->nd_clientid.qval = clientid.qval;
2546 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2547 if (vnode_vtype(vp) == VDIR)
2548 nd->nd_repstat = NFSERR_ISDIR;
2550 nd->nd_repstat = NFSERR_INVAL;
2553 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2554 * seqid# gets incremented. nfsrv_lockctrl() will return the
2555 * value of nd_repstat, if it gets that far.
2557 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2558 &stateid, exp, nd, p);
2560 FREE((caddr_t)stp, M_NFSDSTATE);
2562 free((caddr_t)lop, M_NFSDLOCK);
2563 if (!nd->nd_repstat) {
2564 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2565 *tl++ = txdr_unsigned(stateid.seqid);
2566 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2570 NFSEXITCODE2(error, nd);
2575 * nfsv4 open service
2578 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2579 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2580 struct nfsexstuff *exp)
2584 struct nfsstate *stp = NULL;
2585 int error = 0, create, claim, exclusive_flag = 0;
2586 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2587 int how = NFSCREATE_UNCHECKED;
2588 int32_t cverf[2], tverf[2] = { 0, 0 };
2589 vnode_t vp = NULL, dirp = NULL;
2590 struct nfsvattr nva, dirfor, diraft;
2591 struct nameidata named;
2592 nfsv4stateid_t stateid, delegstateid;
2593 nfsattrbit_t attrbits;
2597 NFSACL_T *aclp = NULL;
2599 #ifdef NFS4_ACL_EXTATTR_NAME
2600 aclp = acl_alloc(M_WAITOK);
2603 NFSZERO_ATTRBIT(&attrbits);
2604 named.ni_startdir = NULL;
2605 named.ni_cnd.cn_nameiop = 0;
2606 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2607 i = fxdr_unsigned(int, *(tl + 5));
2608 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2609 nd->nd_repstat = NFSERR_BADXDR;
2612 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2613 M_NFSDSTATE, M_WAITOK);
2614 stp->ls_ownerlen = i;
2615 stp->ls_op = nd->nd_rp;
2616 stp->ls_flags = NFSLCK_OPEN;
2617 stp->ls_uid = nd->nd_cred->cr_uid;
2618 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2619 i = fxdr_unsigned(int, *tl++);
2621 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2622 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2624 /* For now, ignore these. */
2625 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2626 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2627 case NFSV4OPEN_WANTANYDELEG:
2628 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2630 i &= ~NFSV4OPEN_WANTDELEGMASK;
2632 case NFSV4OPEN_WANTREADDELEG:
2633 stp->ls_flags |= NFSLCK_WANTRDELEG;
2634 i &= ~NFSV4OPEN_WANTDELEGMASK;
2636 case NFSV4OPEN_WANTWRITEDELEG:
2637 stp->ls_flags |= NFSLCK_WANTWDELEG;
2638 i &= ~NFSV4OPEN_WANTDELEGMASK;
2640 case NFSV4OPEN_WANTNODELEG:
2641 stp->ls_flags |= NFSLCK_WANTNODELEG;
2642 i &= ~NFSV4OPEN_WANTDELEGMASK;
2644 case NFSV4OPEN_WANTCANCEL:
2645 printf("NFSv4: ignore Open WantCancel\n");
2646 i &= ~NFSV4OPEN_WANTDELEGMASK;
2649 /* nd_repstat will be set to NFSERR_INVAL below. */
2654 case NFSV4OPEN_ACCESSREAD:
2655 stp->ls_flags |= NFSLCK_READACCESS;
2657 case NFSV4OPEN_ACCESSWRITE:
2658 stp->ls_flags |= NFSLCK_WRITEACCESS;
2660 case NFSV4OPEN_ACCESSBOTH:
2661 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2664 nd->nd_repstat = NFSERR_INVAL;
2666 i = fxdr_unsigned(int, *tl++);
2668 case NFSV4OPEN_DENYNONE:
2670 case NFSV4OPEN_DENYREAD:
2671 stp->ls_flags |= NFSLCK_READDENY;
2673 case NFSV4OPEN_DENYWRITE:
2674 stp->ls_flags |= NFSLCK_WRITEDENY;
2676 case NFSV4OPEN_DENYBOTH:
2677 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2680 nd->nd_repstat = NFSERR_INVAL;
2682 clientid.lval[0] = *tl++;
2683 clientid.lval[1] = *tl;
2684 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2685 if ((nd->nd_flag & ND_NFSV41) != 0)
2686 clientid.qval = nd->nd_clientid.qval;
2687 else if (nd->nd_clientid.qval != clientid.qval)
2688 printf("EEK7 multiple clids\n");
2690 if ((nd->nd_flag & ND_NFSV41) != 0)
2691 printf("EEK! no clientid from session\n");
2692 nd->nd_flag |= ND_IMPLIEDCLID;
2693 nd->nd_clientid.qval = clientid.qval;
2695 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2698 NFSVNO_ATTRINIT(&nva);
2699 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2700 create = fxdr_unsigned(int, *tl);
2701 if (!nd->nd_repstat)
2702 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2703 if (create == NFSV4OPEN_CREATE) {
2706 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2707 how = fxdr_unsigned(int, *tl);
2709 case NFSCREATE_UNCHECKED:
2710 case NFSCREATE_GUARDED:
2711 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2715 * If the na_gid being set is the same as that of
2716 * the directory it is going in, clear it, since
2717 * that is what will be set by default. This allows
2718 * a user that isn't in that group to do the create.
2720 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2721 nva.na_gid == dirfor.na_gid)
2722 NFSVNO_UNSET(&nva, gid);
2723 if (!nd->nd_repstat)
2724 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2726 case NFSCREATE_EXCLUSIVE:
2727 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2731 case NFSCREATE_EXCLUSIVE41:
2732 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2735 error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
2738 if (NFSISSET_ATTRBIT(&attrbits,
2739 NFSATTRBIT_TIMEACCESSSET))
2740 nd->nd_repstat = NFSERR_INVAL;
2742 * If the na_gid being set is the same as that of
2743 * the directory it is going in, clear it, since
2744 * that is what will be set by default. This allows
2745 * a user that isn't in that group to do the create.
2747 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2748 nva.na_gid == dirfor.na_gid)
2749 NFSVNO_UNSET(&nva, gid);
2750 if (nd->nd_repstat == 0)
2751 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2754 nd->nd_repstat = NFSERR_BADXDR;
2757 } else if (create != NFSV4OPEN_NOCREATE) {
2758 nd->nd_repstat = NFSERR_BADXDR;
2763 * Now, handle the claim, which usually includes looking up a
2764 * name in the directory referenced by dp. The exception is
2765 * NFSV4OPEN_CLAIMPREVIOUS.
2767 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2768 claim = fxdr_unsigned(int, *tl);
2769 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2770 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2771 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2772 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2773 stp->ls_flags |= NFSLCK_DELEGCUR;
2774 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2775 stp->ls_flags |= NFSLCK_DELEGPREV;
2777 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2778 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2779 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2780 claim != NFSV4OPEN_CLAIMNULL)
2781 nd->nd_repstat = NFSERR_INVAL;
2782 if (nd->nd_repstat) {
2783 nd->nd_repstat = nfsrv_opencheck(clientid,
2784 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2787 if (create == NFSV4OPEN_CREATE)
2788 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2789 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2791 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2792 LOCKLEAF | SAVESTART);
2793 nfsvno_setpathbuf(&named, &bufp, &hashp);
2794 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2797 #ifdef NFS4_ACL_EXTATTR_NAME
2800 FREE((caddr_t)stp, M_NFSDSTATE);
2801 nfsvno_relpathbuf(&named);
2802 NFSEXITCODE2(error, nd);
2805 if (!nd->nd_repstat) {
2806 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2810 nfsvno_relpathbuf(&named);
2812 if (create == NFSV4OPEN_CREATE) {
2814 case NFSCREATE_UNCHECKED:
2817 * Clear the setable attribute bits, except
2818 * for Size, if it is being truncated.
2820 NFSZERO_ATTRBIT(&attrbits);
2821 if (NFSVNO_ISSETSIZE(&nva))
2822 NFSSETBIT_ATTRBIT(&attrbits,
2826 case NFSCREATE_GUARDED:
2827 if (named.ni_vp && !nd->nd_repstat)
2828 nd->nd_repstat = EEXIST;
2830 case NFSCREATE_EXCLUSIVE:
2835 case NFSCREATE_EXCLUSIVE41:
2840 nfsvno_open(nd, &named, clientid, &stateid, stp,
2841 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2842 nd->nd_cred, p, exp, &vp);
2843 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2844 NFSV4OPEN_CLAIMFH) {
2845 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2846 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2847 i = fxdr_unsigned(int, *tl);
2849 case NFSV4OPEN_DELEGATEREAD:
2850 stp->ls_flags |= NFSLCK_DELEGREAD;
2852 case NFSV4OPEN_DELEGATEWRITE:
2853 stp->ls_flags |= NFSLCK_DELEGWRITE;
2854 case NFSV4OPEN_DELEGATENONE:
2857 nd->nd_repstat = NFSERR_BADXDR;
2860 stp->ls_flags |= NFSLCK_RECLAIM;
2863 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
2864 nd->nd_repstat = NFSERR_INVAL;
2867 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2868 if ((vp->v_iflag & VI_DOOMED) == 0)
2869 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2870 stp, vp, nd, p, nd->nd_repstat);
2872 nd->nd_repstat = NFSERR_PERM;
2874 nd->nd_repstat = NFSERR_BADXDR;
2879 * Do basic access checking.
2881 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2883 * The IETF working group decided that this is the correct
2884 * error return for all non-regular files.
2886 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
2888 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2889 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2890 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2891 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2892 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2893 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2895 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2896 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2897 NFSACCCHK_VPISLOCKED, NULL);
2900 if (!nd->nd_repstat) {
2901 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2902 if (!nd->nd_repstat) {
2903 tverf[0] = nva.na_atime.tv_sec;
2904 tverf[1] = nva.na_atime.tv_nsec;
2907 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2908 cverf[1] != tverf[1]))
2909 nd->nd_repstat = EEXIST;
2911 * Do the open locking/delegation stuff.
2913 if (!nd->nd_repstat)
2914 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2915 &delegstateid, &rflags, exp, p, nva.na_filerev);
2918 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2919 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2920 * (ie: Leave the NFSVOPUNLOCK() about here.)
2923 NFSVOPUNLOCK(vp, 0);
2925 FREE((caddr_t)stp, M_NFSDSTATE);
2926 if (!nd->nd_repstat && dirp)
2927 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2929 if (!nd->nd_repstat) {
2930 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2931 *tl++ = txdr_unsigned(stateid.seqid);
2932 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2933 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2934 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2935 *tl++ = newnfs_true;
2941 *tl++ = newnfs_false; /* Since dirp is not locked */
2942 txdr_hyper(dirfor.na_filerev, tl);
2944 txdr_hyper(diraft.na_filerev, tl);
2947 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2948 (void) nfsrv_putattrbit(nd, &attrbits);
2949 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2950 if (rflags & NFSV4OPEN_READDELEGATE)
2951 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2952 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2953 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2954 else if (retext != 0) {
2955 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
2956 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
2957 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2958 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
2960 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
2961 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2962 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
2965 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2966 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
2969 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2970 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2971 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2972 *tl++ = txdr_unsigned(delegstateid.seqid);
2973 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2975 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2976 if (rflags & NFSV4OPEN_RECALL)
2980 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2981 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2982 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2983 txdr_hyper(nva.na_size, tl);
2985 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2986 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2987 *tl++ = txdr_unsigned(0x0);
2988 acemask = NFSV4ACE_ALLFILESMASK;
2989 if (nva.na_mode & S_IRUSR)
2990 acemask |= NFSV4ACE_READMASK;
2991 if (nva.na_mode & S_IWUSR)
2992 acemask |= NFSV4ACE_WRITEMASK;
2993 if (nva.na_mode & S_IXUSR)
2994 acemask |= NFSV4ACE_EXECUTEMASK;
2995 *tl = txdr_unsigned(acemask);
2996 (void) nfsm_strtom(nd, "OWNER@", 6);
3004 #ifdef NFS4_ACL_EXTATTR_NAME
3007 NFSEXITCODE2(0, nd);
3011 #ifdef NFS4_ACL_EXTATTR_NAME
3015 FREE((caddr_t)stp, M_NFSDSTATE);
3016 NFSEXITCODE2(error, nd);
3021 * nfsv4 close service
3024 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3025 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3028 struct nfsstate st, *stp = &st;
3030 nfsv4stateid_t stateid;
3033 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3034 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3035 stp->ls_ownerlen = 0;
3036 stp->ls_op = nd->nd_rp;
3037 stp->ls_uid = nd->nd_cred->cr_uid;
3038 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3039 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3041 stp->ls_flags = NFSLCK_CLOSE;
3042 clientid.lval[0] = stp->ls_stateid.other[0];
3043 clientid.lval[1] = stp->ls_stateid.other[1];
3044 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3045 if ((nd->nd_flag & ND_NFSV41) != 0)
3046 clientid.qval = nd->nd_clientid.qval;
3047 else if (nd->nd_clientid.qval != clientid.qval)
3048 printf("EEK8 multiple clids\n");
3050 if ((nd->nd_flag & ND_NFSV41) != 0)
3051 printf("EEK! no clientid from session\n");
3052 nd->nd_flag |= ND_IMPLIEDCLID;
3053 nd->nd_clientid.qval = clientid.qval;
3055 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3057 if (!nd->nd_repstat) {
3058 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3059 *tl++ = txdr_unsigned(stateid.seqid);
3060 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3062 NFSEXITCODE2(0, nd);
3066 NFSEXITCODE2(error, nd);
3071 * nfsv4 delegpurge service
3074 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3075 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3081 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3082 nd->nd_repstat = NFSERR_WRONGSEC;
3085 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3086 clientid.lval[0] = *tl++;
3087 clientid.lval[1] = *tl;
3088 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3089 if ((nd->nd_flag & ND_NFSV41) != 0)
3090 clientid.qval = nd->nd_clientid.qval;
3091 else if (nd->nd_clientid.qval != clientid.qval)
3092 printf("EEK9 multiple clids\n");
3094 if ((nd->nd_flag & ND_NFSV41) != 0)
3095 printf("EEK! no clientid from session\n");
3096 nd->nd_flag |= ND_IMPLIEDCLID;
3097 nd->nd_clientid.qval = clientid.qval;
3099 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3100 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
3102 NFSEXITCODE2(error, nd);
3107 * nfsv4 delegreturn service
3110 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3111 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3115 nfsv4stateid_t stateid;
3118 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3119 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3120 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3121 clientid.lval[0] = stateid.other[0];
3122 clientid.lval[1] = stateid.other[1];
3123 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3124 if ((nd->nd_flag & ND_NFSV41) != 0)
3125 clientid.qval = nd->nd_clientid.qval;
3126 else if (nd->nd_clientid.qval != clientid.qval)
3127 printf("EEK10 multiple clids\n");
3129 if ((nd->nd_flag & ND_NFSV41) != 0)
3130 printf("EEK! no clientid from session\n");
3131 nd->nd_flag |= ND_IMPLIEDCLID;
3132 nd->nd_clientid.qval = clientid.qval;
3134 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3135 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
3138 NFSEXITCODE2(error, nd);
3143 * nfsv4 get file handle service
3146 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3147 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3151 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3153 if (!nd->nd_repstat)
3154 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3155 NFSEXITCODE2(0, nd);
3160 * nfsv4 open confirm service
3163 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3164 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3167 struct nfsstate st, *stp = &st;
3169 nfsv4stateid_t stateid;
3172 if ((nd->nd_flag & ND_NFSV41) != 0) {
3173 nd->nd_repstat = NFSERR_NOTSUPP;
3176 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3177 stp->ls_ownerlen = 0;
3178 stp->ls_op = nd->nd_rp;
3179 stp->ls_uid = nd->nd_cred->cr_uid;
3180 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3181 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3183 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3184 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3185 stp->ls_flags = NFSLCK_CONFIRM;
3186 clientid.lval[0] = stp->ls_stateid.other[0];
3187 clientid.lval[1] = stp->ls_stateid.other[1];
3188 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3189 if ((nd->nd_flag & ND_NFSV41) != 0)
3190 clientid.qval = nd->nd_clientid.qval;
3191 else if (nd->nd_clientid.qval != clientid.qval)
3192 printf("EEK11 multiple clids\n");
3194 if ((nd->nd_flag & ND_NFSV41) != 0)
3195 printf("EEK! no clientid from session\n");
3196 nd->nd_flag |= ND_IMPLIEDCLID;
3197 nd->nd_clientid.qval = clientid.qval;
3199 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3200 if (!nd->nd_repstat) {
3201 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3202 *tl++ = txdr_unsigned(stateid.seqid);
3203 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3207 NFSEXITCODE2(error, nd);
3212 * nfsv4 open downgrade service
3215 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3216 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3220 struct nfsstate st, *stp = &st;
3222 nfsv4stateid_t stateid;
3225 /* opendowngrade can only work on a file object.*/
3226 if (vp->v_type != VREG) {
3227 error = NFSERR_INVAL;
3230 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3231 stp->ls_ownerlen = 0;
3232 stp->ls_op = nd->nd_rp;
3233 stp->ls_uid = nd->nd_cred->cr_uid;
3234 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3235 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3237 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3238 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3239 i = fxdr_unsigned(int, *tl++);
3241 case NFSV4OPEN_ACCESSREAD:
3242 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3244 case NFSV4OPEN_ACCESSWRITE:
3245 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3247 case NFSV4OPEN_ACCESSBOTH:
3248 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3252 nd->nd_repstat = NFSERR_BADXDR;
3254 i = fxdr_unsigned(int, *tl);
3256 case NFSV4OPEN_DENYNONE:
3258 case NFSV4OPEN_DENYREAD:
3259 stp->ls_flags |= NFSLCK_READDENY;
3261 case NFSV4OPEN_DENYWRITE:
3262 stp->ls_flags |= NFSLCK_WRITEDENY;
3264 case NFSV4OPEN_DENYBOTH:
3265 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3268 nd->nd_repstat = NFSERR_BADXDR;
3271 clientid.lval[0] = stp->ls_stateid.other[0];
3272 clientid.lval[1] = stp->ls_stateid.other[1];
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("EEK12 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 if (!nd->nd_repstat)
3285 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3287 if (!nd->nd_repstat) {
3288 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3289 *tl++ = txdr_unsigned(stateid.seqid);
3290 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3294 NFSEXITCODE2(error, nd);
3299 * nfsv4 renew lease service
3302 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3303 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3309 if ((nd->nd_flag & ND_NFSV41) != 0) {
3310 nd->nd_repstat = NFSERR_NOTSUPP;
3313 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3314 nd->nd_repstat = NFSERR_WRONGSEC;
3317 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3318 clientid.lval[0] = *tl++;
3319 clientid.lval[1] = *tl;
3320 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3321 if ((nd->nd_flag & ND_NFSV41) != 0)
3322 clientid.qval = nd->nd_clientid.qval;
3323 else if (nd->nd_clientid.qval != clientid.qval)
3324 printf("EEK13 multiple clids\n");
3326 if ((nd->nd_flag & ND_NFSV41) != 0)
3327 printf("EEK! no clientid from session\n");
3328 nd->nd_flag |= ND_IMPLIEDCLID;
3329 nd->nd_clientid.qval = clientid.qval;
3331 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3332 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3334 NFSEXITCODE2(error, nd);
3339 * nfsv4 security info service
3342 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3343 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3347 struct nameidata named;
3348 vnode_t dirp = NULL, vp;
3350 struct nfsexstuff retnes;
3352 int error = 0, savflag, i;
3357 * All this just to get the export flags for the name.
3359 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3360 LOCKLEAF | SAVESTART);
3361 nfsvno_setpathbuf(&named, &bufp, &hashp);
3362 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3365 nfsvno_relpathbuf(&named);
3368 if (!nd->nd_repstat) {
3369 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3372 nfsvno_relpathbuf(&named);
3378 vrele(named.ni_startdir);
3379 nfsvno_relpathbuf(&named);
3380 fh.nfsrvfh_len = NFSX_MYFH;
3382 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3384 savflag = nd->nd_flag;
3385 if (!nd->nd_repstat) {
3386 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3390 nd->nd_flag = savflag;
3395 * Finally have the export flags for name, so we can create
3396 * the security info.
3399 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3400 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3401 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3402 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3403 *tl = txdr_unsigned(RPCAUTH_UNIX);
3405 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3406 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3407 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3408 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3409 nfsgss_mechlist[KERBV_MECH].len);
3410 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3411 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3412 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3414 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3415 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3416 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3417 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3418 nfsgss_mechlist[KERBV_MECH].len);
3419 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3420 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3421 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3423 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3424 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3425 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3426 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3427 nfsgss_mechlist[KERBV_MECH].len);
3428 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3429 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3430 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3434 *sizp = txdr_unsigned(len);
3437 NFSEXITCODE2(error, nd);
3442 * nfsv4 set client id service
3445 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3446 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3450 int error = 0, idlen;
3451 struct nfsclient *clp = NULL;
3452 struct sockaddr_in *rad;
3453 u_char *verf, *ucp, *ucp2, addrbuf[24];
3454 nfsquad_t clientid, confirm;
3456 if ((nd->nd_flag & ND_NFSV41) != 0) {
3457 nd->nd_repstat = NFSERR_NOTSUPP;
3460 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3461 nd->nd_repstat = NFSERR_WRONGSEC;
3464 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3465 verf = (u_char *)tl;
3466 tl += (NFSX_VERF / NFSX_UNSIGNED);
3467 i = fxdr_unsigned(int, *tl);
3468 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3469 nd->nd_repstat = NFSERR_BADXDR;
3473 if (nd->nd_flag & ND_GSS)
3474 i += nd->nd_princlen;
3475 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3477 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3478 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3479 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3480 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3481 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3482 clp->lc_req.nr_cred = NULL;
3483 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3484 clp->lc_idlen = idlen;
3485 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3488 if (nd->nd_flag & ND_GSS) {
3489 clp->lc_flags = LCL_GSS;
3490 if (nd->nd_flag & ND_GSSINTEGRITY)
3491 clp->lc_flags |= LCL_GSSINTEGRITY;
3492 else if (nd->nd_flag & ND_GSSPRIVACY)
3493 clp->lc_flags |= LCL_GSSPRIVACY;
3497 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3498 clp->lc_flags |= LCL_NAME;
3499 clp->lc_namelen = nd->nd_princlen;
3500 clp->lc_name = &clp->lc_id[idlen];
3501 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3503 clp->lc_uid = nd->nd_cred->cr_uid;
3504 clp->lc_gid = nd->nd_cred->cr_gid;
3506 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3507 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3508 error = nfsrv_getclientipaddr(nd, clp);
3511 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3512 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3515 * nfsrv_setclient() does the actual work of adding it to the
3516 * client list. If there is no error, the structure has been
3517 * linked into the client list and clp should no longer be used
3518 * here. When an error is returned, it has not been linked in,
3519 * so it should be free'd.
3521 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3522 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3523 if (clp->lc_flags & LCL_TCPCALLBACK)
3524 (void) nfsm_strtom(nd, "tcp", 3);
3526 (void) nfsm_strtom(nd, "udp", 3);
3527 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3528 ucp = (u_char *)&rad->sin_addr.s_addr;
3529 ucp2 = (u_char *)&rad->sin_port;
3530 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3531 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3532 ucp2[0] & 0xff, ucp2[1] & 0xff);
3533 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3536 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3537 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3538 free(clp->lc_stateid, M_NFSDCLIENT);
3539 free(clp, M_NFSDCLIENT);
3541 if (!nd->nd_repstat) {
3542 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3543 *tl++ = clientid.lval[0];
3544 *tl++ = clientid.lval[1];
3545 *tl++ = confirm.lval[0];
3546 *tl = confirm.lval[1];
3550 NFSEXITCODE2(0, nd);
3554 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3555 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3556 free(clp->lc_stateid, M_NFSDCLIENT);
3557 free(clp, M_NFSDCLIENT);
3559 NFSEXITCODE2(error, nd);
3564 * nfsv4 set client id confirm service
3567 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3568 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3569 __unused struct nfsexstuff *exp)
3573 nfsquad_t clientid, confirm;
3575 if ((nd->nd_flag & ND_NFSV41) != 0) {
3576 nd->nd_repstat = NFSERR_NOTSUPP;
3579 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3580 nd->nd_repstat = NFSERR_WRONGSEC;
3583 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3584 clientid.lval[0] = *tl++;
3585 clientid.lval[1] = *tl++;
3586 confirm.lval[0] = *tl++;
3587 confirm.lval[1] = *tl;
3590 * nfsrv_getclient() searches the client list for a match and
3591 * returns the appropriate NFSERR status.
3593 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3594 NULL, NULL, confirm, 0, nd, p);
3596 NFSEXITCODE2(error, nd);
3601 * nfsv4 verify service
3604 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3605 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3607 int error = 0, ret, fhsize = NFSX_MYFH;
3608 struct nfsvattr nva;
3610 struct nfsfsinfo fs;
3613 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3614 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3615 if (!nd->nd_repstat)
3616 nd->nd_repstat = nfsvno_statfs(vp, sf);
3617 if (!nd->nd_repstat)
3618 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3619 if (!nd->nd_repstat) {
3620 nfsvno_getfs(&fs, isdgram);
3621 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3622 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3624 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3626 nd->nd_repstat = NFSERR_SAME;
3627 else if (ret != NFSERR_NOTSAME)
3628 nd->nd_repstat = ret;
3630 nd->nd_repstat = ret;
3635 NFSEXITCODE2(error, nd);
3643 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3644 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3645 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3648 int error = 0, createdir;
3650 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3651 createdir = fxdr_unsigned(int, *tl);
3652 nd->nd_repstat = NFSERR_NOTSUPP;
3655 NFSEXITCODE2(error, nd);
3660 * nfsv4 release lock owner service
3663 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3664 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3667 struct nfsstate *stp = NULL;
3671 if ((nd->nd_flag & ND_NFSV41) != 0) {
3672 nd->nd_repstat = NFSERR_NOTSUPP;
3675 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3676 nd->nd_repstat = NFSERR_WRONGSEC;
3679 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3680 len = fxdr_unsigned(int, *(tl + 2));
3681 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3682 nd->nd_repstat = NFSERR_BADXDR;
3685 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3686 M_NFSDSTATE, M_WAITOK);
3687 stp->ls_ownerlen = len;
3689 stp->ls_flags = NFSLCK_RELEASE;
3690 stp->ls_uid = nd->nd_cred->cr_uid;
3691 clientid.lval[0] = *tl++;
3692 clientid.lval[1] = *tl;
3693 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3694 if ((nd->nd_flag & ND_NFSV41) != 0)
3695 clientid.qval = nd->nd_clientid.qval;
3696 else if (nd->nd_clientid.qval != clientid.qval)
3697 printf("EEK14 multiple clids\n");
3699 if ((nd->nd_flag & ND_NFSV41) != 0)
3700 printf("EEK! no clientid from session\n");
3701 nd->nd_flag |= ND_IMPLIEDCLID;
3702 nd->nd_clientid.qval = clientid.qval;
3704 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3707 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3708 FREE((caddr_t)stp, M_NFSDSTATE);
3710 NFSEXITCODE2(0, nd);
3714 free((caddr_t)stp, M_NFSDSTATE);
3715 NFSEXITCODE2(error, nd);
3720 * nfsv4 exchange_id service
3723 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3724 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3727 int error = 0, i, idlen;
3728 struct nfsclient *clp = NULL;
3729 nfsquad_t clientid, confirm;
3731 uint32_t sp4type, v41flags;
3732 uint64_t owner_minor;
3733 struct timespec verstime;
3734 struct sockaddr_in *sad, *rad;
3736 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3737 nd->nd_repstat = NFSERR_WRONGSEC;
3740 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3741 verf = (uint8_t *)tl;
3742 tl += (NFSX_VERF / NFSX_UNSIGNED);
3743 i = fxdr_unsigned(int, *tl);
3744 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3745 nd->nd_repstat = NFSERR_BADXDR;
3749 if (nd->nd_flag & ND_GSS)
3750 i += nd->nd_princlen;
3751 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3753 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3754 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3755 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3756 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3757 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3758 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
3759 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3760 rad->sin_family = AF_INET;
3761 rad->sin_addr.s_addr = 0;
3763 if (sad->sin_family == AF_INET)
3764 rad->sin_addr.s_addr = sad->sin_addr.s_addr;
3765 clp->lc_req.nr_cred = NULL;
3766 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3767 clp->lc_idlen = idlen;
3768 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3771 if ((nd->nd_flag & ND_GSS) != 0) {
3772 clp->lc_flags = LCL_GSS | LCL_NFSV41;
3773 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
3774 clp->lc_flags |= LCL_GSSINTEGRITY;
3775 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
3776 clp->lc_flags |= LCL_GSSPRIVACY;
3778 clp->lc_flags = LCL_NFSV41;
3779 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
3780 clp->lc_flags |= LCL_NAME;
3781 clp->lc_namelen = nd->nd_princlen;
3782 clp->lc_name = &clp->lc_id[idlen];
3783 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3785 clp->lc_uid = nd->nd_cred->cr_uid;
3786 clp->lc_gid = nd->nd_cred->cr_gid;
3788 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3789 v41flags = fxdr_unsigned(uint32_t, *tl++);
3790 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
3791 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
3792 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
3793 nd->nd_repstat = NFSERR_INVAL;
3796 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
3797 confirm.lval[1] = 1;
3799 confirm.lval[1] = 0;
3800 v41flags = NFSV4EXCH_USENONPNFS;
3801 sp4type = fxdr_unsigned(uint32_t, *tl);
3802 if (sp4type != NFSV4EXCH_SP4NONE) {
3803 nd->nd_repstat = NFSERR_NOTSUPP;
3808 * nfsrv_setclient() does the actual work of adding it to the
3809 * client list. If there is no error, the structure has been
3810 * linked into the client list and clp should no longer be used
3811 * here. When an error is returned, it has not been linked in,
3812 * so it should be free'd.
3814 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3816 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3817 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3818 free(clp->lc_stateid, M_NFSDCLIENT);
3819 free(clp, M_NFSDCLIENT);
3821 if (nd->nd_repstat == 0) {
3822 if (confirm.lval[1] != 0)
3823 v41flags |= NFSV4EXCH_CONFIRMEDR;
3824 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
3825 *tl++ = clientid.lval[0]; /* ClientID */
3826 *tl++ = clientid.lval[1];
3827 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
3828 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
3829 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
3830 owner_minor = 0; /* Owner */
3831 txdr_hyper(owner_minor, tl); /* Minor */
3832 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
3833 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
3834 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3835 *tl++ = txdr_unsigned(NFSX_UNSIGNED);
3836 *tl++ = time_uptime; /* Make scope a unique value. */
3837 *tl = txdr_unsigned(1);
3838 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
3839 (void)nfsm_strtom(nd, version, strlen(version));
3840 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
3841 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
3842 verstime.tv_nsec = 0;
3843 txdr_nfsv4time(&verstime, tl);
3845 NFSEXITCODE2(0, nd);
3849 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3850 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3851 free(clp->lc_stateid, M_NFSDCLIENT);
3852 free(clp, M_NFSDCLIENT);
3854 NFSEXITCODE2(error, nd);
3859 * nfsv4 create session service
3862 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
3863 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3867 nfsquad_t clientid, confirm;
3868 struct nfsdsession *sep = NULL;
3871 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3872 nd->nd_repstat = NFSERR_WRONGSEC;
3875 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
3876 M_NFSDSESSION, M_WAITOK | M_ZERO);
3877 sep->sess_refcnt = 1;
3878 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
3879 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
3880 clientid.lval[0] = *tl++;
3881 clientid.lval[1] = *tl++;
3882 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
3883 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
3884 /* Persistent sessions and RDMA are not supported. */
3885 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
3887 /* Fore channel attributes. */
3888 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3889 tl++; /* Header pad always 0. */
3890 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
3891 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
3892 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
3893 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
3894 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
3895 if (sep->sess_maxslots > NFSV4_SLOTS)
3896 sep->sess_maxslots = NFSV4_SLOTS;
3897 rdmacnt = fxdr_unsigned(uint32_t, *tl);
3899 nd->nd_repstat = NFSERR_BADXDR;
3901 } else if (rdmacnt == 1)
3902 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3904 /* Back channel attributes. */
3905 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3906 tl++; /* Header pad always 0. */
3907 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
3908 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
3909 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
3910 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
3911 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
3912 rdmacnt = fxdr_unsigned(uint32_t, *tl);
3914 nd->nd_repstat = NFSERR_BADXDR;
3916 } else if (rdmacnt == 1)
3917 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3919 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3920 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
3923 * nfsrv_getclient() searches the client list for a match and
3924 * returns the appropriate NFSERR status.
3926 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
3927 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
3928 if (nd->nd_repstat == 0) {
3929 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3930 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
3931 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
3932 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
3933 *tl++ = txdr_unsigned(sep->sess_crflags);
3935 /* Fore channel attributes. */
3937 *tl++ = txdr_unsigned(sep->sess_maxreq);
3938 *tl++ = txdr_unsigned(sep->sess_maxresp);
3939 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
3940 *tl++ = txdr_unsigned(sep->sess_maxops);
3941 *tl++ = txdr_unsigned(sep->sess_maxslots);
3942 *tl++ = txdr_unsigned(1);
3943 *tl++ = txdr_unsigned(0); /* No RDMA. */
3945 /* Back channel attributes. */
3947 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
3948 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
3949 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
3950 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
3951 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
3952 *tl++ = txdr_unsigned(1);
3953 *tl = txdr_unsigned(0); /* No RDMA. */
3956 if (nd->nd_repstat != 0 && sep != NULL)
3957 free(sep, M_NFSDSESSION);
3958 NFSEXITCODE2(error, nd);
3963 * nfsv4 sequence service
3966 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
3967 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3970 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
3971 int cache_this, error = 0;
3973 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3974 nd->nd_repstat = NFSERR_WRONGSEC;
3977 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
3978 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
3979 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
3980 sequenceid = fxdr_unsigned(uint32_t, *tl++);
3981 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
3982 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
3983 if (*tl == newnfs_true)
3987 nd->nd_flag |= ND_HASSEQUENCE;
3988 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
3989 &target_highest_slotid, cache_this, &sflags, p);
3990 if (nd->nd_repstat == 0) {
3991 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3992 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
3993 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
3994 *tl++ = txdr_unsigned(sequenceid);
3995 *tl++ = txdr_unsigned(nd->nd_slotid);
3996 *tl++ = txdr_unsigned(highest_slotid);
3997 *tl++ = txdr_unsigned(target_highest_slotid);
3998 *tl = txdr_unsigned(sflags);
4001 NFSEXITCODE2(error, nd);
4006 * nfsv4 reclaim complete service
4009 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4010 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4015 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4016 nd->nd_repstat = NFSERR_WRONGSEC;
4019 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4020 if (*tl == newnfs_true)
4021 nd->nd_repstat = NFSERR_NOTSUPP;
4023 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
4025 NFSEXITCODE2(error, nd);
4030 * nfsv4 destroy clientid service
4033 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4034 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4040 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4041 nd->nd_repstat = NFSERR_WRONGSEC;
4044 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4045 clientid.lval[0] = *tl++;
4046 clientid.lval[1] = *tl;
4047 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4049 NFSEXITCODE2(error, nd);
4054 * nfsv4 destroy session service
4057 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4058 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4060 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4063 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4064 nd->nd_repstat = NFSERR_WRONGSEC;
4067 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4068 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4069 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4071 NFSEXITCODE2(error, nd);
4076 * nfsv4 free stateid service
4079 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4080 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4083 nfsv4stateid_t stateid;
4086 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4087 nd->nd_repstat = NFSERR_WRONGSEC;
4090 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4091 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4092 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4093 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4095 NFSEXITCODE2(error, nd);
4100 * nfsv4 service not supported
4103 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4104 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4107 nd->nd_repstat = NFSERR_NOTSUPP;
4108 NFSEXITCODE2(0, nd);