2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * nfs version 2, 3 and 4 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42 * function in nfsd_port.c
43 * 3 - build the rpc reply in an mbuf list
44 * For nfsv4, these functions are called for each Op within the Compound RPC.
48 #include <fs/nfs/nfsport.h>
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset;
55 extern int nfsrv_enable_crossmntpt;
56 #endif /* !APPLEKEXT */
58 static int nfs_async = 0;
59 SYSCTL_DECL(_vfs_nfsd);
60 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
61 "Tell client that writes were synced even though they were not");
64 * This list defines the GSS mechanisms supported.
65 * (Don't ask me how you get these strings from the RFC stuff like
66 * iso(1), org(3)... but someone did it, so I don't need to know.)
68 static struct nfsgss_mechlist nfsgss_mechlist[] = {
69 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
74 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
75 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
76 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
77 int *diraft_retp, nfsattrbit_t *attrbitp,
78 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
80 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
81 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
82 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
83 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
84 NFSPROC_T *p, struct nfsexstuff *exp);
87 * nfs access service (not a part of NFS V2)
90 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
91 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
94 int getret, error = 0;
96 u_int32_t testmode, nfsmode, supported = 0;
100 nfsrv_postopattr(nd, 1, &nva);
103 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
104 nfsmode = fxdr_unsigned(u_int32_t, *tl);
105 if ((nd->nd_flag & ND_NFSV4) &&
106 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
107 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
108 NFSACCESS_EXECUTE))) {
109 nd->nd_repstat = NFSERR_INVAL;
113 if (nfsmode & NFSACCESS_READ) {
114 supported |= NFSACCESS_READ;
115 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
116 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
117 nfsmode &= ~NFSACCESS_READ;
119 if (nfsmode & NFSACCESS_MODIFY) {
120 supported |= NFSACCESS_MODIFY;
121 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
122 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
123 nfsmode &= ~NFSACCESS_MODIFY;
125 if (nfsmode & NFSACCESS_EXTEND) {
126 supported |= NFSACCESS_EXTEND;
127 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
128 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
129 nfsmode &= ~NFSACCESS_EXTEND;
131 if (nfsmode & NFSACCESS_DELETE) {
132 supported |= NFSACCESS_DELETE;
133 if (vp->v_type == VDIR)
134 deletebit = VDELETE_CHILD;
137 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
138 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
139 nfsmode &= ~NFSACCESS_DELETE;
141 if (vnode_vtype(vp) == VDIR)
142 testmode = NFSACCESS_LOOKUP;
144 testmode = NFSACCESS_EXECUTE;
145 if (nfsmode & testmode) {
146 supported |= (nfsmode & testmode);
147 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
148 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
149 nfsmode &= ~testmode;
151 nfsmode &= supported;
152 if (nd->nd_flag & ND_NFSV3) {
153 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
154 nfsrv_postopattr(nd, getret, &nva);
157 if (nd->nd_flag & ND_NFSV4) {
158 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
159 *tl++ = txdr_unsigned(supported);
161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
162 *tl = txdr_unsigned(nfsmode);
169 NFSEXITCODE2(error, nd);
174 * nfs getattr service
177 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
178 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
182 int at_root = 0, error = 0, supports_nfsv4acls;
183 struct nfsreferral *refp;
184 nfsattrbit_t attrbits, tmpbits;
186 struct vnode *tvp = NULL;
188 uint64_t mounted_on_fileno = 0;
193 if (nd->nd_flag & ND_NFSV4) {
194 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
201 * Check for a referral.
203 refp = nfsv4root_getreferral(vp, NULL, 0);
205 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
210 if (nd->nd_repstat == 0) {
212 NFSSET_ATTRBIT(&tmpbits, &attrbits);
213 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
214 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
215 accmode |= VREAD_ACL;
217 if (NFSNONZERO_ATTRBIT(&tmpbits))
218 accmode |= VREAD_ATTRIBUTES;
220 nd->nd_repstat = nfsvno_accchk(vp, accmode,
221 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
222 NFSACCCHK_VPISLOCKED, NULL);
226 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
227 if (!nd->nd_repstat) {
228 if (nd->nd_flag & ND_NFSV4) {
229 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
230 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
232 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
233 &nva, &attrbits, nd->nd_cred, p);
234 if (nd->nd_repstat == 0) {
235 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
237 if (nfsrv_enable_crossmntpt != 0 &&
238 vp->v_type == VDIR &&
239 (vp->v_vflag & VV_ROOT) != 0 &&
241 tvp = mp->mnt_vnodecovered;
249 if ((nd->nd_repstat =
250 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
251 nd->nd_repstat = VOP_GETATTR(
252 tvp, &va, nd->nd_cred);
256 if (nd->nd_repstat == 0)
257 mounted_on_fileno = (uint64_t)
262 if (nd->nd_repstat == 0)
263 nd->nd_repstat = vfs_busy(mp, 0);
265 if (nd->nd_repstat == 0) {
266 (void)nfsvno_fillattr(nd, mp, vp, &nva,
267 &fh, 0, &attrbits, nd->nd_cred, p,
268 isdgram, 1, supports_nfsv4acls,
269 at_root, mounted_on_fileno);
276 nfsrv_fillattr(nd, &nva);
284 NFSEXITCODE2(error, nd);
289 * nfs setattr service
292 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
293 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
295 struct nfsvattr nva, nva2;
297 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
298 struct timespec guard = { 0, 0 };
299 nfsattrbit_t attrbits, retbits;
300 nfsv4stateid_t stateid;
301 NFSACL_T *aclp = NULL;
303 if (nd->nd_repstat) {
304 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
307 #ifdef NFS4_ACL_EXTATTR_NAME
308 aclp = acl_alloc(M_WAITOK);
311 NFSVNO_ATTRINIT(&nva);
312 NFSZERO_ATTRBIT(&retbits);
313 if (nd->nd_flag & ND_NFSV4) {
314 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
315 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
316 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
318 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
321 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
323 nd->nd_repstat = preat_ret;
324 if (nd->nd_flag & ND_NFSV3) {
325 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
326 gcheck = fxdr_unsigned(int, *tl);
328 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
329 fxdr_nfsv3time(tl, &guard);
331 if (!nd->nd_repstat && gcheck &&
332 (nva2.na_ctime.tv_sec != guard.tv_sec ||
333 nva2.na_ctime.tv_nsec != guard.tv_nsec))
334 nd->nd_repstat = NFSERR_NOT_SYNC;
335 if (nd->nd_repstat) {
337 #ifdef NFS4_ACL_EXTATTR_NAME
340 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
343 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
344 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
347 * Now that we have all the fields, lets do it.
348 * If the size is being changed write access is required, otherwise
349 * just check for a read only file system.
351 if (!nd->nd_repstat) {
352 if (NFSVNO_NOTSETSIZE(&nva)) {
353 if (NFSVNO_EXRDONLY(exp) ||
354 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
355 nd->nd_repstat = EROFS;
357 if (vnode_vtype(vp) != VREG)
358 nd->nd_repstat = EINVAL;
359 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
360 NFSVNO_EXSTRICTACCESS(exp))
361 nd->nd_repstat = nfsvno_accchk(vp,
362 VWRITE, nd->nd_cred, exp, p,
363 NFSACCCHK_NOOVERRIDE,
364 NFSACCCHK_VPISLOCKED, NULL);
367 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
368 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
369 &nva, &attrbits, exp, p);
371 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
373 * For V4, try setting the attrbutes in sets, so that the
374 * reply bitmap will be correct for an error case.
376 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
377 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
378 NFSVNO_ATTRINIT(&nva2);
379 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
380 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
381 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
383 if (!nd->nd_repstat) {
384 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
385 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
386 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
387 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
390 if (!nd->nd_repstat &&
391 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
392 NFSVNO_ATTRINIT(&nva2);
393 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
394 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
397 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
399 if (!nd->nd_repstat &&
400 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
401 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
402 NFSVNO_ATTRINIT(&nva2);
403 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
404 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
405 if (nva.na_vaflags & VA_UTIMES_NULL) {
406 nva2.na_vaflags |= VA_UTIMES_NULL;
407 NFSVNO_SETACTIVE(&nva2, vaflags);
409 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
411 if (!nd->nd_repstat) {
412 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
413 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
414 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
415 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
418 if (!nd->nd_repstat &&
419 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
420 NFSVNO_ATTRINIT(&nva2);
421 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
422 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
425 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
428 #ifdef NFS4_ACL_EXTATTR_NAME
429 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
430 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
431 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
433 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
436 } else if (!nd->nd_repstat) {
437 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
440 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
441 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
443 nd->nd_repstat = postat_ret;
446 #ifdef NFS4_ACL_EXTATTR_NAME
449 if (nd->nd_flag & ND_NFSV3)
450 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
451 else if (nd->nd_flag & ND_NFSV4)
452 (void) nfsrv_putattrbit(nd, &retbits);
453 else if (!nd->nd_repstat)
454 nfsrv_fillattr(nd, &nva);
461 #ifdef NFS4_ACL_EXTATTR_NAME
464 if (nd->nd_flag & ND_NFSV4) {
466 * For all nd_repstat, the V4 reply includes a bitmap,
467 * even NFSERR_BADXDR, which is what this will end up
470 (void) nfsrv_putattrbit(nd, &retbits);
472 NFSEXITCODE2(error, nd);
478 * (Also performs lookup parent for v4)
481 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
482 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
483 struct nfsexstuff *exp)
485 struct nameidata named;
486 vnode_t vp, dirp = NULL;
487 int error = 0, dattr_ret = 1;
488 struct nfsvattr nva, dattr;
492 if (nd->nd_repstat) {
493 nfsrv_postopattr(nd, dattr_ret, &dattr);
498 * For some reason, if dp is a symlink, the error
499 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
501 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
502 nd->nd_repstat = NFSERR_SYMLINK;
507 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
508 LOCKLEAF | SAVESTART);
509 nfsvno_setpathbuf(&named, &bufp, &hashp);
510 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
513 nfsvno_relpathbuf(&named);
516 if (!nd->nd_repstat) {
517 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
520 nfsvno_relpathbuf(&named);
522 if (nd->nd_repstat) {
524 if (nd->nd_flag & ND_NFSV3)
525 dattr_ret = nfsvno_getattr(dirp, &dattr,
529 if (nd->nd_flag & ND_NFSV3)
530 nfsrv_postopattr(nd, dattr_ret, &dattr);
533 if (named.ni_startdir)
534 vrele(named.ni_startdir);
535 nfsvno_relpathbuf(&named);
537 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
538 vp->v_type != VDIR && vp->v_type != VLNK)
540 * Only allow lookup of VDIR and VLNK for traversal of
541 * non-exported volumes during NFSv4 mounting.
543 nd->nd_repstat = ENOENT;
544 if (nd->nd_repstat == 0)
545 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
546 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
547 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
548 if (vpp != NULL && nd->nd_repstat == 0)
553 if (nd->nd_flag & ND_NFSV3)
554 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
558 if (nd->nd_repstat) {
559 if (nd->nd_flag & ND_NFSV3)
560 nfsrv_postopattr(nd, dattr_ret, &dattr);
563 if (nd->nd_flag & ND_NFSV2) {
564 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
565 nfsrv_fillattr(nd, &nva);
566 } else if (nd->nd_flag & ND_NFSV3) {
567 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
568 nfsrv_postopattr(nd, 0, &nva);
569 nfsrv_postopattr(nd, dattr_ret, &dattr);
573 NFSEXITCODE2(error, nd);
578 * nfs readlink service
581 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
582 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
585 mbuf_t mp = NULL, mpend = NULL;
589 if (nd->nd_repstat) {
590 nfsrv_postopattr(nd, getret, &nva);
593 if (vnode_vtype(vp) != VLNK) {
594 if (nd->nd_flag & ND_NFSV2)
595 nd->nd_repstat = ENXIO;
597 nd->nd_repstat = EINVAL;
600 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
602 if (nd->nd_flag & ND_NFSV3)
603 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
605 if (nd->nd_flag & ND_NFSV3)
606 nfsrv_postopattr(nd, getret, &nva);
609 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
610 *tl = txdr_unsigned(len);
611 mbuf_setnext(nd->nd_mb, mp);
613 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
624 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
625 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
628 int error = 0, cnt, getret = 1, reqlen, eof = 0;
632 struct nfsstate st, *stp = &st;
633 struct nfslock lo, *lop = &lo;
634 nfsv4stateid_t stateid;
637 if (nd->nd_repstat) {
638 nfsrv_postopattr(nd, getret, &nva);
641 if (nd->nd_flag & ND_NFSV2) {
642 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
643 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
644 reqlen = fxdr_unsigned(int, *tl);
645 } else if (nd->nd_flag & ND_NFSV3) {
646 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
647 off = fxdr_hyper(tl);
649 reqlen = fxdr_unsigned(int, *tl);
651 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
652 reqlen = fxdr_unsigned(int, *(tl + 6));
654 if (reqlen > NFS_SRVMAXDATA(nd)) {
655 reqlen = NFS_SRVMAXDATA(nd);
656 } else if (reqlen < 0) {
660 if (nd->nd_flag & ND_NFSV4) {
661 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
662 lop->lo_flags = NFSLCK_READ;
663 stp->ls_ownerlen = 0;
665 stp->ls_uid = nd->nd_cred->cr_uid;
666 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
667 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
668 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
669 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
670 if ((nd->nd_flag & ND_NFSV41) != 0)
671 clientid.qval = nd->nd_clientid.qval;
672 else if (nd->nd_clientid.qval != clientid.qval)
673 printf("EEK1 multiple clids\n");
675 if ((nd->nd_flag & ND_NFSV41) != 0)
676 printf("EEK! no clientid from session\n");
677 nd->nd_flag |= ND_IMPLIEDCLID;
678 nd->nd_clientid.qval = clientid.qval;
680 stp->ls_stateid.other[2] = *tl++;
681 off = fxdr_hyper(tl);
684 lop->lo_end = off + reqlen;
686 * Paranoia, just in case it wraps around.
688 if (lop->lo_end < off)
689 lop->lo_end = NFS64BITSSET;
691 if (vnode_vtype(vp) != VREG) {
692 if (nd->nd_flag & ND_NFSV3)
693 nd->nd_repstat = EINVAL;
695 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
698 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
700 nd->nd_repstat = getret;
701 if (!nd->nd_repstat &&
702 (nva.na_uid != nd->nd_cred->cr_uid ||
703 NFSVNO_EXSTRICTACCESS(exp))) {
704 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
706 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
708 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
709 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
710 NFSACCCHK_VPISLOCKED, NULL);
712 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
713 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
714 &stateid, exp, nd, p);
715 if (nd->nd_repstat) {
717 if (nd->nd_flag & ND_NFSV3)
718 nfsrv_postopattr(nd, getret, &nva);
721 if (off >= nva.na_size) {
724 } else if (reqlen == 0)
726 else if ((off + reqlen) >= nva.na_size) {
727 cnt = nva.na_size - off;
733 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
735 if (!(nd->nd_flag & ND_NFSV4)) {
736 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
738 nd->nd_repstat = getret;
740 if (nd->nd_repstat) {
744 if (nd->nd_flag & ND_NFSV3)
745 nfsrv_postopattr(nd, getret, &nva);
750 if (nd->nd_flag & ND_NFSV2) {
751 nfsrv_fillattr(nd, &nva);
752 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
754 if (nd->nd_flag & ND_NFSV3) {
755 nfsrv_postopattr(nd, getret, &nva);
756 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
757 *tl++ = txdr_unsigned(cnt);
759 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
763 *tl++ = newnfs_false;
765 *tl = txdr_unsigned(cnt);
767 mbuf_setnext(nd->nd_mb, m3);
769 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
777 NFSEXITCODE2(error, nd);
785 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
786 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
791 struct nfsvattr nva, forat;
792 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
793 int stable = NFSWRITE_FILESYNC;
795 struct nfsstate st, *stp = &st;
796 struct nfslock lo, *lop = &lo;
797 nfsv4stateid_t stateid;
800 if (nd->nd_repstat) {
801 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
804 if (nd->nd_flag & ND_NFSV2) {
805 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
806 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
808 retlen = len = fxdr_unsigned(int32_t, *tl);
809 } else if (nd->nd_flag & ND_NFSV3) {
810 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
811 off = fxdr_hyper(tl);
813 stable = fxdr_unsigned(int, *tl++);
814 retlen = len = fxdr_unsigned(int32_t, *tl);
816 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
817 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
818 lop->lo_flags = NFSLCK_WRITE;
819 stp->ls_ownerlen = 0;
821 stp->ls_uid = nd->nd_cred->cr_uid;
822 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
823 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
824 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
825 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
826 if ((nd->nd_flag & ND_NFSV41) != 0)
827 clientid.qval = nd->nd_clientid.qval;
828 else if (nd->nd_clientid.qval != clientid.qval)
829 printf("EEK2 multiple clids\n");
831 if ((nd->nd_flag & ND_NFSV41) != 0)
832 printf("EEK! no clientid from session\n");
833 nd->nd_flag |= ND_IMPLIEDCLID;
834 nd->nd_clientid.qval = clientid.qval;
836 stp->ls_stateid.other[2] = *tl++;
837 off = fxdr_hyper(tl);
840 stable = fxdr_unsigned(int, *tl++);
841 retlen = len = fxdr_unsigned(int32_t, *tl);
842 lop->lo_end = off + len;
844 * Paranoia, just in case it wraps around, which shouldn't
845 * ever happen anyhow.
847 if (lop->lo_end < lop->lo_first)
848 lop->lo_end = NFS64BITSSET;
852 * Loop through the mbuf chain, counting how many mbufs are a
853 * part of this write operation, so the iovec size is known.
857 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
873 if (retlen > NFS_MAXDATA || retlen < 0)
874 nd->nd_repstat = EIO;
875 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
876 if (nd->nd_flag & ND_NFSV3)
877 nd->nd_repstat = EINVAL;
879 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
882 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
884 nd->nd_repstat = forat_ret;
885 if (!nd->nd_repstat &&
886 (forat.na_uid != nd->nd_cred->cr_uid ||
887 NFSVNO_EXSTRICTACCESS(exp)))
888 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
890 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
891 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
892 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
893 &stateid, exp, nd, p);
895 if (nd->nd_repstat) {
897 if (nd->nd_flag & ND_NFSV3)
898 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
903 * For NFS Version 2, it is not obvious what a write of zero length
904 * should do, but I might as well be consistent with Version 3,
905 * which is to return ok so long as there are no permission problems.
908 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
909 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
910 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
912 panic("nfsrv_write mbuf");
914 if (nd->nd_flag & ND_NFSV4)
917 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
920 nd->nd_repstat = aftat_ret;
921 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
922 if (nd->nd_flag & ND_NFSV3)
923 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
926 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
927 *tl++ = txdr_unsigned(retlen);
929 * If nfs_async is set, then pretend the write was FILESYNC.
930 * Warning: Doing this violates RFC1813 and runs a risk
931 * of data written by a client being lost when the server
934 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
935 *tl++ = txdr_unsigned(stable);
937 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
939 * Actually, there is no need to txdr these fields,
940 * but it may make the values more human readable,
941 * for debugging purposes.
943 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
944 *tl = txdr_unsigned(nfsboottime.tv_usec);
945 } else if (!nd->nd_repstat)
946 nfsrv_fillattr(nd, &nva);
953 NFSEXITCODE2(error, nd);
958 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
959 * now does a truncate to 0 length via. setattr if it already exists
960 * The core creation routine has been extracted out into nfsrv_creatsub(),
961 * so it can also be used by nfsrv_open() for V4.
964 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
965 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
967 struct nfsvattr nva, dirfor, diraft;
968 struct nfsv2_sattr *sp;
969 struct nameidata named;
971 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
972 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
974 vnode_t vp = NULL, dirp = NULL;
979 int32_t cverf[2], tverf[2] = { 0, 0 };
981 if (nd->nd_repstat) {
982 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
985 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
986 LOCKPARENT | LOCKLEAF | SAVESTART);
987 nfsvno_setpathbuf(&named, &bufp, &hashp);
988 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
991 if (!nd->nd_repstat) {
992 NFSVNO_ATTRINIT(&nva);
993 if (nd->nd_flag & ND_NFSV2) {
994 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
995 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
998 NFSVNO_SETATTRVAL(&nva, type, vtyp);
999 NFSVNO_SETATTRVAL(&nva, mode,
1000 nfstov_mode(sp->sa_mode));
1001 switch (nva.na_type) {
1003 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1005 NFSVNO_SETATTRVAL(&nva, size,
1011 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1017 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1018 how = fxdr_unsigned(int, *tl);
1020 case NFSCREATE_GUARDED:
1021 case NFSCREATE_UNCHECKED:
1022 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1026 case NFSCREATE_EXCLUSIVE:
1027 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1033 NFSVNO_SETATTRVAL(&nva, type, VREG);
1036 if (nd->nd_repstat) {
1037 nfsvno_relpathbuf(&named);
1038 if (nd->nd_flag & ND_NFSV3) {
1039 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1041 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1048 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1050 if (nd->nd_flag & ND_NFSV2) {
1054 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1058 if (nd->nd_repstat) {
1059 if (nd->nd_flag & ND_NFSV3)
1060 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1067 if (!(nd->nd_flag & ND_NFSV2)) {
1069 case NFSCREATE_GUARDED:
1071 nd->nd_repstat = EEXIST;
1073 case NFSCREATE_UNCHECKED:
1075 case NFSCREATE_EXCLUSIVE:
1076 if (named.ni_vp == NULL)
1077 NFSVNO_SETATTRVAL(&nva, mode, 0);
1083 * Iff doesn't exist, create it
1084 * otherwise just truncate to 0 length
1085 * should I set the mode too ?
1087 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1088 &exclusive_flag, cverf, rdev, p, exp);
1090 if (!nd->nd_repstat) {
1091 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1092 if (!nd->nd_repstat)
1093 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1096 if (!nd->nd_repstat) {
1097 tverf[0] = nva.na_atime.tv_sec;
1098 tverf[1] = nva.na_atime.tv_nsec;
1101 if (nd->nd_flag & ND_NFSV2) {
1102 if (!nd->nd_repstat) {
1103 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1104 nfsrv_fillattr(nd, &nva);
1107 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1108 || cverf[1] != tverf[1]))
1109 nd->nd_repstat = EEXIST;
1110 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1112 if (!nd->nd_repstat) {
1113 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1114 nfsrv_postopattr(nd, 0, &nva);
1116 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1120 NFSEXITCODE2(0, nd);
1124 nfsvno_relpathbuf(&named);
1125 NFSEXITCODE2(error, nd);
1130 * nfs v3 mknod service (and v4 create)
1133 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1134 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1135 struct nfsexstuff *exp)
1137 struct nfsvattr nva, dirfor, diraft;
1139 struct nameidata named;
1140 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1141 u_int32_t major, minor;
1142 enum vtype vtyp = VNON;
1143 nfstype nfs4type = NFNON;
1144 vnode_t vp, dirp = NULL;
1145 nfsattrbit_t attrbits;
1146 char *bufp = NULL, *pathcp = NULL;
1147 u_long *hashp, cnflags;
1148 NFSACL_T *aclp = NULL;
1150 NFSVNO_ATTRINIT(&nva);
1151 cnflags = (LOCKPARENT | SAVESTART);
1152 if (nd->nd_repstat) {
1153 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1156 #ifdef NFS4_ACL_EXTATTR_NAME
1157 aclp = acl_alloc(M_WAITOK);
1162 * For V4, the creation stuff is here, Yuck!
1164 if (nd->nd_flag & ND_NFSV4) {
1165 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1166 vtyp = nfsv34tov_type(*tl);
1167 nfs4type = fxdr_unsigned(nfstype, *tl);
1170 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1177 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1178 major = fxdr_unsigned(u_int32_t, *tl++);
1179 minor = fxdr_unsigned(u_int32_t, *tl);
1180 nva.na_rdev = NFSMAKEDEV(major, minor);
1186 cnflags = (LOCKPARENT | SAVENAME);
1189 nd->nd_repstat = NFSERR_BADTYPE;
1191 #ifdef NFS4_ACL_EXTATTR_NAME
1197 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1198 nfsvno_setpathbuf(&named, &bufp, &hashp);
1199 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1202 if (!nd->nd_repstat) {
1203 if (nd->nd_flag & ND_NFSV3) {
1204 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1205 vtyp = nfsv34tov_type(*tl);
1207 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1211 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1212 (vtyp == VCHR || vtyp == VBLK)) {
1213 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1214 major = fxdr_unsigned(u_int32_t, *tl++);
1215 minor = fxdr_unsigned(u_int32_t, *tl);
1216 nva.na_rdev = NFSMAKEDEV(major, minor);
1220 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1221 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1222 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1223 dirfor.na_gid == nva.na_gid)
1224 NFSVNO_UNSET(&nva, gid);
1225 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1227 if (nd->nd_repstat) {
1229 #ifdef NFS4_ACL_EXTATTR_NAME
1232 nfsvno_relpathbuf(&named);
1234 FREE(pathcp, M_TEMP);
1235 if (nd->nd_flag & ND_NFSV3)
1236 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1242 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1243 * in va_mode, so we'll have to set a default here.
1245 if (NFSVNO_NOTSETMODE(&nva)) {
1253 named.ni_cnd.cn_flags |= WILLBEDIR;
1254 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1255 if (nd->nd_repstat) {
1257 if (nd->nd_flag & ND_NFSV3)
1258 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1262 #ifdef NFS4_ACL_EXTATTR_NAME
1265 if (nd->nd_flag & ND_NFSV3)
1266 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1271 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1273 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1275 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1276 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1278 #ifdef NFS4_ACL_EXTATTR_NAME
1282 } else if (vtyp == VLNK) {
1283 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1284 &dirfor, &diraft, &diraft_ret, &attrbits,
1285 aclp, p, exp, pathcp, pathlen);
1286 #ifdef NFS4_ACL_EXTATTR_NAME
1289 FREE(pathcp, M_TEMP);
1294 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1295 if (!nd->nd_repstat) {
1297 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1298 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1299 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1300 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1302 if (vpp != NULL && nd->nd_repstat == 0) {
1303 NFSVOPUNLOCK(vp, 0);
1309 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1311 if (!nd->nd_repstat) {
1312 if (nd->nd_flag & ND_NFSV3) {
1313 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1314 nfsrv_postopattr(nd, 0, &nva);
1316 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1317 *tl++ = newnfs_false;
1318 txdr_hyper(dirfor.na_filerev, tl);
1320 txdr_hyper(diraft.na_filerev, tl);
1321 (void) nfsrv_putattrbit(nd, &attrbits);
1324 if (nd->nd_flag & ND_NFSV3)
1325 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1326 #ifdef NFS4_ACL_EXTATTR_NAME
1331 NFSEXITCODE2(0, nd);
1335 #ifdef NFS4_ACL_EXTATTR_NAME
1339 nfsvno_relpathbuf(&named);
1341 FREE(pathcp, M_TEMP);
1343 NFSEXITCODE2(error, nd);
1348 * nfs remove service
1351 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1352 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1354 struct nameidata named;
1356 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1357 vnode_t dirp = NULL;
1358 struct nfsvattr dirfor, diraft;
1362 if (nd->nd_repstat) {
1363 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1366 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1367 LOCKPARENT | LOCKLEAF);
1368 nfsvno_setpathbuf(&named, &bufp, &hashp);
1369 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1372 nfsvno_relpathbuf(&named);
1375 if (!nd->nd_repstat) {
1376 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1379 nfsvno_relpathbuf(&named);
1382 if (!(nd->nd_flag & ND_NFSV2)) {
1383 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1390 if (!nd->nd_repstat) {
1391 if (nd->nd_flag & ND_NFSV4) {
1392 if (vnode_vtype(named.ni_vp) == VDIR)
1393 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1394 nd->nd_cred, p, exp);
1396 nd->nd_repstat = nfsvno_removesub(&named, 1,
1397 nd->nd_cred, p, exp);
1398 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1399 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1400 nd->nd_cred, p, exp);
1402 nd->nd_repstat = nfsvno_removesub(&named, 0,
1403 nd->nd_cred, p, exp);
1406 if (!(nd->nd_flag & ND_NFSV2)) {
1408 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1412 if (nd->nd_flag & ND_NFSV3) {
1413 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1415 } else if (!nd->nd_repstat) {
1416 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1417 *tl++ = newnfs_false;
1418 txdr_hyper(dirfor.na_filerev, tl);
1420 txdr_hyper(diraft.na_filerev, tl);
1425 NFSEXITCODE2(error, nd);
1430 * nfs rename service
1433 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1434 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1435 struct nfsexstuff *toexp)
1438 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1439 int tdirfor_ret = 1, tdiraft_ret = 1;
1440 struct nameidata fromnd, tond;
1441 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1442 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1443 struct nfsexstuff tnes;
1445 char *bufp, *tbufp = NULL;
1449 if (nd->nd_repstat) {
1450 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1451 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1454 if (!(nd->nd_flag & ND_NFSV2))
1455 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1456 tond.ni_cnd.cn_nameiop = 0;
1457 tond.ni_startdir = NULL;
1458 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1459 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1460 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1465 nfsvno_relpathbuf(&fromnd);
1469 * Unlock dp in this code section, so it is unlocked before
1470 * tdp gets locked. This avoids a potential LOR if tdp is the
1471 * parent directory of dp.
1473 if (nd->nd_flag & ND_NFSV4) {
1477 NFSVOPUNLOCK(dp, 0);
1478 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1479 p, 0); /* Might lock tdp. */
1481 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1483 NFSVOPUNLOCK(dp, 0);
1486 tfh.nfsrvfh_len = 0;
1487 error = nfsrv_mtofh(nd, &tfh);
1489 error = nfsvno_getfh(dp, &fh, p);
1492 /* todp is always NULL except NFSv4 */
1493 nfsvno_relpathbuf(&fromnd);
1497 /* If this is the same file handle, just VREF() the vnode. */
1498 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1499 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1503 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1505 NFSVOPUNLOCK(dp, 0);
1507 NFSVOPUNLOCK(dp, 0);
1508 nd->nd_cred->cr_uid = nd->nd_saveduid;
1509 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1510 0, p); /* Locks tdp. */
1512 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1514 NFSVOPUNLOCK(tdp, 0);
1518 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1519 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1520 if (!nd->nd_repstat) {
1521 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1526 nfsvno_relpathbuf(&fromnd);
1527 nfsvno_relpathbuf(&tond);
1531 if (nd->nd_repstat) {
1532 if (nd->nd_flag & ND_NFSV3) {
1533 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1535 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1541 nfsvno_relpathbuf(&fromnd);
1542 nfsvno_relpathbuf(&tond);
1547 * Done parsing, now down to business.
1549 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1550 if (nd->nd_repstat) {
1551 if (nd->nd_flag & ND_NFSV3) {
1552 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1554 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1561 nfsvno_relpathbuf(&tond);
1564 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1565 tond.ni_cnd.cn_flags |= WILLBEDIR;
1566 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1567 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1568 nd->nd_flag, nd->nd_cred, p);
1570 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1573 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1579 if (nd->nd_flag & ND_NFSV3) {
1580 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1581 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1582 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1583 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1584 *tl++ = newnfs_false;
1585 txdr_hyper(fdirfor.na_filerev, tl);
1587 txdr_hyper(fdiraft.na_filerev, tl);
1589 *tl++ = newnfs_false;
1590 txdr_hyper(tdirfor.na_filerev, tl);
1592 txdr_hyper(tdiraft.na_filerev, tl);
1596 NFSEXITCODE2(error, nd);
1604 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1605 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1606 struct nfsexstuff *toexp)
1608 struct nameidata named;
1610 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1611 vnode_t dirp = NULL, dp = NULL;
1612 struct nfsvattr dirfor, diraft, at;
1613 struct nfsexstuff tnes;
1618 if (nd->nd_repstat) {
1619 nfsrv_postopattr(nd, getret, &at);
1620 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1623 NFSVOPUNLOCK(vp, 0);
1624 if (vnode_vtype(vp) == VDIR) {
1625 if (nd->nd_flag & ND_NFSV4)
1626 nd->nd_repstat = NFSERR_ISDIR;
1628 nd->nd_repstat = NFSERR_INVAL;
1632 if (!nd->nd_repstat) {
1633 if (nd->nd_flag & ND_NFSV4) {
1637 error = nfsrv_mtofh(nd, &dfh);
1640 /* tovp is always NULL unless NFSv4 */
1643 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1646 NFSVOPUNLOCK(dp, 0);
1649 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1650 LOCKPARENT | SAVENAME);
1651 if (!nd->nd_repstat) {
1652 nfsvno_setpathbuf(&named, &bufp, &hashp);
1653 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1658 nfsvno_relpathbuf(&named);
1661 if (!nd->nd_repstat) {
1662 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1667 nfsvno_relpathbuf(&named);
1671 if (nd->nd_flag & ND_NFSV2) {
1675 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1679 if (!nd->nd_repstat)
1680 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1681 if (nd->nd_flag & ND_NFSV3)
1682 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1684 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1688 if (nd->nd_flag & ND_NFSV3) {
1689 nfsrv_postopattr(nd, getret, &at);
1690 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1691 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1692 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1693 *tl++ = newnfs_false;
1694 txdr_hyper(dirfor.na_filerev, tl);
1696 txdr_hyper(diraft.na_filerev, tl);
1700 NFSEXITCODE2(error, nd);
1705 * nfs symbolic link service
1708 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1709 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1710 struct nfsexstuff *exp)
1712 struct nfsvattr nva, dirfor, diraft;
1713 struct nameidata named;
1714 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1715 vnode_t dirp = NULL;
1716 char *bufp, *pathcp = NULL;
1719 if (nd->nd_repstat) {
1720 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1725 NFSVNO_ATTRINIT(&nva);
1726 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1727 LOCKPARENT | SAVESTART);
1728 nfsvno_setpathbuf(&named, &bufp, &hashp);
1729 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1730 if (!error && !nd->nd_repstat)
1731 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1734 nfsvno_relpathbuf(&named);
1737 if (!nd->nd_repstat) {
1738 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1741 nfsvno_relpathbuf(&named);
1743 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1749 * And call nfsrvd_symlinksub() to do the common code. It will
1750 * return EBADRPC upon a parsing error, 0 otherwise.
1752 if (!nd->nd_repstat) {
1754 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1756 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1757 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1759 } else if (dirp != NULL) {
1760 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1764 FREE(pathcp, M_TEMP);
1766 if (nd->nd_flag & ND_NFSV3) {
1767 if (!nd->nd_repstat) {
1768 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1769 nfsrv_postopattr(nd, 0, &nva);
1771 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1775 NFSEXITCODE2(error, nd);
1780 * Common code for creating a symbolic link.
1783 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1784 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1785 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1786 int *diraft_retp, nfsattrbit_t *attrbitp,
1787 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1792 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1793 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1794 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1795 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1796 if (nd->nd_flag & ND_NFSV3) {
1797 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1798 if (!nd->nd_repstat)
1799 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1800 nvap, nd->nd_cred, p, 1);
1802 if (vpp != NULL && nd->nd_repstat == 0) {
1803 NFSVOPUNLOCK(ndp->ni_vp, 0);
1809 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1812 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1813 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1814 *tl++ = newnfs_false;
1815 txdr_hyper(dirforp->na_filerev, tl);
1817 txdr_hyper(diraftp->na_filerev, tl);
1818 (void) nfsrv_putattrbit(nd, attrbitp);
1821 NFSEXITCODE2(0, nd);
1828 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1829 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1830 struct nfsexstuff *exp)
1832 struct nfsvattr nva, dirfor, diraft;
1833 struct nameidata named;
1835 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1836 vnode_t dirp = NULL;
1840 if (nd->nd_repstat) {
1841 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1844 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1845 LOCKPARENT | SAVENAME);
1846 nfsvno_setpathbuf(&named, &bufp, &hashp);
1847 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1850 if (!nd->nd_repstat) {
1851 NFSVNO_ATTRINIT(&nva);
1852 if (nd->nd_flag & ND_NFSV3) {
1853 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1857 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1858 nva.na_mode = nfstov_mode(*tl++);
1861 if (!nd->nd_repstat) {
1862 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1865 nfsvno_relpathbuf(&named);
1867 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1871 if (nd->nd_repstat) {
1873 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1877 if (nd->nd_flag & ND_NFSV3)
1878 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1883 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1886 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1888 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1889 &diraft_ret, NULL, NULL, p, exp);
1891 if (nd->nd_flag & ND_NFSV3) {
1892 if (!nd->nd_repstat) {
1893 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1894 nfsrv_postopattr(nd, 0, &nva);
1896 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1897 } else if (!nd->nd_repstat) {
1898 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1899 nfsrv_fillattr(nd, &nva);
1903 NFSEXITCODE2(0, nd);
1907 nfsvno_relpathbuf(&named);
1908 NFSEXITCODE2(error, nd);
1913 * Code common to mkdir for V2,3 and 4.
1916 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1917 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1918 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1919 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1920 NFSPROC_T *p, struct nfsexstuff *exp)
1925 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1926 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1927 nd->nd_cred, p, exp);
1928 if (!nd->nd_repstat) {
1930 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1931 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1932 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1933 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1935 if (vpp && !nd->nd_repstat) {
1936 NFSVOPUNLOCK(vp, 0);
1943 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1946 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1947 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1948 *tl++ = newnfs_false;
1949 txdr_hyper(dirforp->na_filerev, tl);
1951 txdr_hyper(diraftp->na_filerev, tl);
1952 (void) nfsrv_putattrbit(nd, attrbitp);
1955 NFSEXITCODE2(0, nd);
1959 * nfs commit service
1962 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1963 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1965 struct nfsvattr bfor, aft;
1967 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1970 if (nd->nd_repstat) {
1971 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1974 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1976 * XXX At this time VOP_FSYNC() does not accept offset and byte
1977 * count parameters, so these arguments are useless (someday maybe).
1979 off = fxdr_hyper(tl);
1981 cnt = fxdr_unsigned(int, *tl);
1982 if (nd->nd_flag & ND_NFSV3)
1983 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1984 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1985 if (nd->nd_flag & ND_NFSV3) {
1986 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1987 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1990 if (!nd->nd_repstat) {
1991 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1992 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1993 *tl = txdr_unsigned(nfsboottime.tv_usec);
1997 NFSEXITCODE2(0, nd);
2001 NFSEXITCODE2(error, nd);
2006 * nfs statfs service
2009 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2010 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2019 if (nd->nd_repstat) {
2020 nfsrv_postopattr(nd, getret, &at);
2024 nd->nd_repstat = nfsvno_statfs(vp, sf);
2025 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2027 if (nd->nd_flag & ND_NFSV3)
2028 nfsrv_postopattr(nd, getret, &at);
2031 if (nd->nd_flag & ND_NFSV2) {
2032 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2033 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2034 *tl++ = txdr_unsigned(sf->f_bsize);
2035 *tl++ = txdr_unsigned(sf->f_blocks);
2036 *tl++ = txdr_unsigned(sf->f_bfree);
2037 *tl = txdr_unsigned(sf->f_bavail);
2039 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2040 tval = (u_quad_t)sf->f_blocks;
2041 tval *= (u_quad_t)sf->f_bsize;
2042 txdr_hyper(tval, tl); tl += 2;
2043 tval = (u_quad_t)sf->f_bfree;
2044 tval *= (u_quad_t)sf->f_bsize;
2045 txdr_hyper(tval, tl); tl += 2;
2046 tval = (u_quad_t)sf->f_bavail;
2047 tval *= (u_quad_t)sf->f_bsize;
2048 txdr_hyper(tval, tl); tl += 2;
2049 tval = (u_quad_t)sf->f_files;
2050 txdr_hyper(tval, tl); tl += 2;
2051 tval = (u_quad_t)sf->f_ffree;
2052 txdr_hyper(tval, tl); tl += 2;
2053 tval = (u_quad_t)sf->f_ffree;
2054 txdr_hyper(tval, tl); tl += 2;
2059 NFSEXITCODE2(0, nd);
2064 * nfs fsinfo service
2067 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2068 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2071 struct nfsfsinfo fs;
2075 if (nd->nd_repstat) {
2076 nfsrv_postopattr(nd, getret, &at);
2079 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2080 nfsvno_getfs(&fs, isdgram);
2082 nfsrv_postopattr(nd, getret, &at);
2083 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2084 *tl++ = txdr_unsigned(fs.fs_rtmax);
2085 *tl++ = txdr_unsigned(fs.fs_rtpref);
2086 *tl++ = txdr_unsigned(fs.fs_rtmult);
2087 *tl++ = txdr_unsigned(fs.fs_wtmax);
2088 *tl++ = txdr_unsigned(fs.fs_wtpref);
2089 *tl++ = txdr_unsigned(fs.fs_wtmult);
2090 *tl++ = txdr_unsigned(fs.fs_dtpref);
2091 txdr_hyper(fs.fs_maxfilesize, tl);
2093 txdr_nfsv3time(&fs.fs_timedelta, tl);
2095 *tl = txdr_unsigned(fs.fs_properties);
2098 NFSEXITCODE2(0, nd);
2103 * nfs pathconf service
2106 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2107 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2109 struct nfsv3_pathconf *pc;
2111 register_t linkmax, namemax, chownres, notrunc;
2114 if (nd->nd_repstat) {
2115 nfsrv_postopattr(nd, getret, &at);
2118 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2120 if (!nd->nd_repstat)
2121 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2123 if (!nd->nd_repstat)
2124 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2125 &chownres, nd->nd_cred, p);
2126 if (!nd->nd_repstat)
2127 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2129 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2131 nfsrv_postopattr(nd, getret, &at);
2132 if (!nd->nd_repstat) {
2133 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2134 pc->pc_linkmax = txdr_unsigned(linkmax);
2135 pc->pc_namemax = txdr_unsigned(namemax);
2136 pc->pc_notrunc = txdr_unsigned(notrunc);
2137 pc->pc_chownrestricted = txdr_unsigned(chownres);
2140 * These should probably be supported by VOP_PATHCONF(), but
2141 * until msdosfs is exportable (why would you want to?), the
2142 * Unix defaults should be ok.
2144 pc->pc_caseinsensitive = newnfs_false;
2145 pc->pc_casepreserving = newnfs_true;
2149 NFSEXITCODE2(0, nd);
2154 * nfsv4 lock service
2157 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2158 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2162 struct nfsstate *stp = NULL;
2163 struct nfslock *lop;
2164 struct nfslockconflict cf;
2166 u_short flags = NFSLCK_LOCK, lflags;
2167 u_int64_t offset, len;
2168 nfsv4stateid_t stateid;
2171 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2172 i = fxdr_unsigned(int, *tl++);
2174 case NFSV4LOCKT_READW:
2175 flags |= NFSLCK_BLOCKING;
2176 case NFSV4LOCKT_READ:
2177 lflags = NFSLCK_READ;
2179 case NFSV4LOCKT_WRITEW:
2180 flags |= NFSLCK_BLOCKING;
2181 case NFSV4LOCKT_WRITE:
2182 lflags = NFSLCK_WRITE;
2185 nd->nd_repstat = NFSERR_BADXDR;
2188 if (*tl++ == newnfs_true)
2189 flags |= NFSLCK_RECLAIM;
2190 offset = fxdr_hyper(tl);
2192 len = fxdr_hyper(tl);
2194 if (*tl == newnfs_true)
2195 flags |= NFSLCK_OPENTOLOCK;
2196 if (flags & NFSLCK_OPENTOLOCK) {
2197 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2198 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2199 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2200 nd->nd_repstat = NFSERR_BADXDR;
2203 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2204 M_NFSDSTATE, M_WAITOK);
2205 stp->ls_ownerlen = i;
2206 stp->ls_op = nd->nd_rp;
2207 stp->ls_seq = fxdr_unsigned(int, *tl++);
2208 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2209 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2211 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2212 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2213 clientid.lval[0] = *tl++;
2214 clientid.lval[1] = *tl++;
2215 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2216 if ((nd->nd_flag & ND_NFSV41) != 0)
2217 clientid.qval = nd->nd_clientid.qval;
2218 else if (nd->nd_clientid.qval != clientid.qval)
2219 printf("EEK3 multiple clids\n");
2221 if ((nd->nd_flag & ND_NFSV41) != 0)
2222 printf("EEK! no clientid from session\n");
2223 nd->nd_flag |= ND_IMPLIEDCLID;
2224 nd->nd_clientid.qval = clientid.qval;
2226 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2230 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2231 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2232 M_NFSDSTATE, M_WAITOK);
2233 stp->ls_ownerlen = 0;
2234 stp->ls_op = nd->nd_rp;
2235 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2236 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2238 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2239 stp->ls_seq = fxdr_unsigned(int, *tl);
2240 clientid.lval[0] = stp->ls_stateid.other[0];
2241 clientid.lval[1] = stp->ls_stateid.other[1];
2242 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2243 if ((nd->nd_flag & ND_NFSV41) != 0)
2244 clientid.qval = nd->nd_clientid.qval;
2245 else if (nd->nd_clientid.qval != clientid.qval)
2246 printf("EEK4 multiple clids\n");
2248 if ((nd->nd_flag & ND_NFSV41) != 0)
2249 printf("EEK! no clientid from session\n");
2250 nd->nd_flag |= ND_IMPLIEDCLID;
2251 nd->nd_clientid.qval = clientid.qval;
2254 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2255 M_NFSDLOCK, M_WAITOK);
2256 lop->lo_first = offset;
2257 if (len == NFS64BITSSET) {
2258 lop->lo_end = NFS64BITSSET;
2260 lop->lo_end = offset + len;
2261 if (lop->lo_end <= lop->lo_first)
2262 nd->nd_repstat = NFSERR_INVAL;
2264 lop->lo_flags = lflags;
2265 stp->ls_flags = flags;
2266 stp->ls_uid = nd->nd_cred->cr_uid;
2269 * Do basic access checking.
2271 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2272 if (vnode_vtype(vp) == VDIR)
2273 nd->nd_repstat = NFSERR_ISDIR;
2275 nd->nd_repstat = NFSERR_INVAL;
2277 if (!nd->nd_repstat) {
2278 if (lflags & NFSLCK_WRITE) {
2279 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2280 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2281 NFSACCCHK_VPISLOCKED, NULL);
2283 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2284 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2285 NFSACCCHK_VPISLOCKED, NULL);
2287 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2288 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2289 NFSACCCHK_VPISLOCKED, NULL);
2294 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2295 * seqid# gets updated. nfsrv_lockctrl() will return the value
2296 * of nd_repstat, if it gets that far.
2298 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2299 &stateid, exp, nd, p);
2301 FREE((caddr_t)lop, M_NFSDLOCK);
2303 FREE((caddr_t)stp, M_NFSDSTATE);
2304 if (!nd->nd_repstat) {
2305 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2306 *tl++ = txdr_unsigned(stateid.seqid);
2307 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2308 } else if (nd->nd_repstat == NFSERR_DENIED) {
2309 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2310 txdr_hyper(cf.cl_first, tl);
2312 if (cf.cl_end == NFS64BITSSET)
2315 len = cf.cl_end - cf.cl_first;
2316 txdr_hyper(len, tl);
2318 if (cf.cl_flags == NFSLCK_WRITE)
2319 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2321 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2322 *tl++ = stateid.other[0];
2323 *tl = stateid.other[1];
2324 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2327 NFSEXITCODE2(0, nd);
2332 free((caddr_t)stp, M_NFSDSTATE);
2333 NFSEXITCODE2(error, nd);
2338 * nfsv4 lock test service
2341 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2342 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2346 struct nfsstate *stp = NULL;
2347 struct nfslock lo, *lop = &lo;
2348 struct nfslockconflict cf;
2350 nfsv4stateid_t stateid;
2354 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2355 i = fxdr_unsigned(int, *(tl + 7));
2356 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2357 nd->nd_repstat = NFSERR_BADXDR;
2360 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2361 M_NFSDSTATE, M_WAITOK);
2362 stp->ls_ownerlen = i;
2364 stp->ls_flags = NFSLCK_TEST;
2365 stp->ls_uid = nd->nd_cred->cr_uid;
2366 i = fxdr_unsigned(int, *tl++);
2368 case NFSV4LOCKT_READW:
2369 stp->ls_flags |= NFSLCK_BLOCKING;
2370 case NFSV4LOCKT_READ:
2371 lo.lo_flags = NFSLCK_READ;
2373 case NFSV4LOCKT_WRITEW:
2374 stp->ls_flags |= NFSLCK_BLOCKING;
2375 case NFSV4LOCKT_WRITE:
2376 lo.lo_flags = NFSLCK_WRITE;
2379 nd->nd_repstat = NFSERR_BADXDR;
2382 lo.lo_first = fxdr_hyper(tl);
2384 len = fxdr_hyper(tl);
2385 if (len == NFS64BITSSET) {
2386 lo.lo_end = NFS64BITSSET;
2388 lo.lo_end = lo.lo_first + len;
2389 if (lo.lo_end <= lo.lo_first)
2390 nd->nd_repstat = NFSERR_INVAL;
2393 clientid.lval[0] = *tl++;
2394 clientid.lval[1] = *tl;
2395 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2396 if ((nd->nd_flag & ND_NFSV41) != 0)
2397 clientid.qval = nd->nd_clientid.qval;
2398 else if (nd->nd_clientid.qval != clientid.qval)
2399 printf("EEK5 multiple clids\n");
2401 if ((nd->nd_flag & ND_NFSV41) != 0)
2402 printf("EEK! no clientid from session\n");
2403 nd->nd_flag |= ND_IMPLIEDCLID;
2404 nd->nd_clientid.qval = clientid.qval;
2406 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2409 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2410 if (vnode_vtype(vp) == VDIR)
2411 nd->nd_repstat = NFSERR_ISDIR;
2413 nd->nd_repstat = NFSERR_INVAL;
2415 if (!nd->nd_repstat)
2416 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2417 &stateid, exp, nd, p);
2419 FREE((caddr_t)stp, M_NFSDSTATE);
2420 if (nd->nd_repstat) {
2421 if (nd->nd_repstat == NFSERR_DENIED) {
2422 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2423 txdr_hyper(cf.cl_first, tl);
2425 if (cf.cl_end == NFS64BITSSET)
2428 len = cf.cl_end - cf.cl_first;
2429 txdr_hyper(len, tl);
2431 if (cf.cl_flags == NFSLCK_WRITE)
2432 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2434 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2435 *tl++ = stp->ls_stateid.other[0];
2436 *tl = stp->ls_stateid.other[1];
2437 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2441 NFSEXITCODE2(0, nd);
2446 free((caddr_t)stp, M_NFSDSTATE);
2447 NFSEXITCODE2(error, nd);
2452 * nfsv4 unlock service
2455 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2456 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2460 struct nfsstate *stp;
2461 struct nfslock *lop;
2463 nfsv4stateid_t stateid;
2467 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2468 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2469 M_NFSDSTATE, M_WAITOK);
2470 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2471 M_NFSDLOCK, M_WAITOK);
2472 stp->ls_flags = NFSLCK_UNLOCK;
2473 lop->lo_flags = NFSLCK_UNLOCK;
2474 stp->ls_op = nd->nd_rp;
2475 i = fxdr_unsigned(int, *tl++);
2477 case NFSV4LOCKT_READW:
2478 stp->ls_flags |= NFSLCK_BLOCKING;
2479 case NFSV4LOCKT_READ:
2481 case NFSV4LOCKT_WRITEW:
2482 stp->ls_flags |= NFSLCK_BLOCKING;
2483 case NFSV4LOCKT_WRITE:
2486 nd->nd_repstat = NFSERR_BADXDR;
2487 free(stp, M_NFSDSTATE);
2488 free(lop, M_NFSDLOCK);
2491 stp->ls_ownerlen = 0;
2492 stp->ls_uid = nd->nd_cred->cr_uid;
2493 stp->ls_seq = fxdr_unsigned(int, *tl++);
2494 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2495 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2497 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2498 lop->lo_first = fxdr_hyper(tl);
2500 len = fxdr_hyper(tl);
2501 if (len == NFS64BITSSET) {
2502 lop->lo_end = NFS64BITSSET;
2504 lop->lo_end = lop->lo_first + len;
2505 if (lop->lo_end <= lop->lo_first)
2506 nd->nd_repstat = NFSERR_INVAL;
2508 clientid.lval[0] = stp->ls_stateid.other[0];
2509 clientid.lval[1] = stp->ls_stateid.other[1];
2510 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2511 if ((nd->nd_flag & ND_NFSV41) != 0)
2512 clientid.qval = nd->nd_clientid.qval;
2513 else if (nd->nd_clientid.qval != clientid.qval)
2514 printf("EEK6 multiple clids\n");
2516 if ((nd->nd_flag & ND_NFSV41) != 0)
2517 printf("EEK! no clientid from session\n");
2518 nd->nd_flag |= ND_IMPLIEDCLID;
2519 nd->nd_clientid.qval = clientid.qval;
2521 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2522 if (vnode_vtype(vp) == VDIR)
2523 nd->nd_repstat = NFSERR_ISDIR;
2525 nd->nd_repstat = NFSERR_INVAL;
2528 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2529 * seqid# gets incremented. nfsrv_lockctrl() will return the
2530 * value of nd_repstat, if it gets that far.
2532 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2533 &stateid, exp, nd, p);
2535 FREE((caddr_t)stp, M_NFSDSTATE);
2537 free((caddr_t)lop, M_NFSDLOCK);
2538 if (!nd->nd_repstat) {
2539 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2540 *tl++ = txdr_unsigned(stateid.seqid);
2541 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2545 NFSEXITCODE2(error, nd);
2550 * nfsv4 open service
2553 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2554 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2555 struct nfsexstuff *exp)
2559 struct nfsstate *stp = NULL;
2560 int error = 0, create, claim, exclusive_flag = 0;
2561 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2562 int how = NFSCREATE_UNCHECKED;
2563 int32_t cverf[2], tverf[2] = { 0, 0 };
2564 vnode_t vp = NULL, dirp = NULL;
2565 struct nfsvattr nva, dirfor, diraft;
2566 struct nameidata named;
2567 nfsv4stateid_t stateid, delegstateid;
2568 nfsattrbit_t attrbits;
2572 NFSACL_T *aclp = NULL;
2574 #ifdef NFS4_ACL_EXTATTR_NAME
2575 aclp = acl_alloc(M_WAITOK);
2578 NFSZERO_ATTRBIT(&attrbits);
2579 named.ni_startdir = NULL;
2580 named.ni_cnd.cn_nameiop = 0;
2581 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2582 i = fxdr_unsigned(int, *(tl + 5));
2583 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2584 nd->nd_repstat = NFSERR_BADXDR;
2587 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2588 M_NFSDSTATE, M_WAITOK);
2589 stp->ls_ownerlen = i;
2590 stp->ls_op = nd->nd_rp;
2591 stp->ls_flags = NFSLCK_OPEN;
2592 stp->ls_uid = nd->nd_cred->cr_uid;
2593 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2594 i = fxdr_unsigned(int, *tl++);
2596 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2597 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2599 /* For now, ignore these. */
2600 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2601 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2602 case NFSV4OPEN_WANTANYDELEG:
2603 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2605 i &= ~NFSV4OPEN_WANTDELEGMASK;
2607 case NFSV4OPEN_WANTREADDELEG:
2608 stp->ls_flags |= NFSLCK_WANTRDELEG;
2609 i &= ~NFSV4OPEN_WANTDELEGMASK;
2611 case NFSV4OPEN_WANTWRITEDELEG:
2612 stp->ls_flags |= NFSLCK_WANTWDELEG;
2613 i &= ~NFSV4OPEN_WANTDELEGMASK;
2615 case NFSV4OPEN_WANTNODELEG:
2616 stp->ls_flags |= NFSLCK_WANTNODELEG;
2617 i &= ~NFSV4OPEN_WANTDELEGMASK;
2619 case NFSV4OPEN_WANTCANCEL:
2620 printf("NFSv4: ignore Open WantCancel\n");
2621 i &= ~NFSV4OPEN_WANTDELEGMASK;
2624 /* nd_repstat will be set to NFSERR_INVAL below. */
2629 case NFSV4OPEN_ACCESSREAD:
2630 stp->ls_flags |= NFSLCK_READACCESS;
2632 case NFSV4OPEN_ACCESSWRITE:
2633 stp->ls_flags |= NFSLCK_WRITEACCESS;
2635 case NFSV4OPEN_ACCESSBOTH:
2636 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2639 nd->nd_repstat = NFSERR_INVAL;
2641 i = fxdr_unsigned(int, *tl++);
2643 case NFSV4OPEN_DENYNONE:
2645 case NFSV4OPEN_DENYREAD:
2646 stp->ls_flags |= NFSLCK_READDENY;
2648 case NFSV4OPEN_DENYWRITE:
2649 stp->ls_flags |= NFSLCK_WRITEDENY;
2651 case NFSV4OPEN_DENYBOTH:
2652 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2655 nd->nd_repstat = NFSERR_INVAL;
2657 clientid.lval[0] = *tl++;
2658 clientid.lval[1] = *tl;
2659 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2660 if ((nd->nd_flag & ND_NFSV41) != 0)
2661 clientid.qval = nd->nd_clientid.qval;
2662 else if (nd->nd_clientid.qval != clientid.qval)
2663 printf("EEK7 multiple clids\n");
2665 if ((nd->nd_flag & ND_NFSV41) != 0)
2666 printf("EEK! no clientid from session\n");
2667 nd->nd_flag |= ND_IMPLIEDCLID;
2668 nd->nd_clientid.qval = clientid.qval;
2670 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2673 NFSVNO_ATTRINIT(&nva);
2674 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2675 create = fxdr_unsigned(int, *tl);
2676 if (!nd->nd_repstat)
2677 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2678 if (create == NFSV4OPEN_CREATE) {
2681 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2682 how = fxdr_unsigned(int, *tl);
2684 case NFSCREATE_UNCHECKED:
2685 case NFSCREATE_GUARDED:
2686 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2690 * If the na_gid being set is the same as that of
2691 * the directory it is going in, clear it, since
2692 * that is what will be set by default. This allows
2693 * a user that isn't in that group to do the create.
2695 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2696 nva.na_gid == dirfor.na_gid)
2697 NFSVNO_UNSET(&nva, gid);
2698 if (!nd->nd_repstat)
2699 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2701 case NFSCREATE_EXCLUSIVE:
2702 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2706 case NFSCREATE_EXCLUSIVE41:
2707 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2710 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2713 if (NFSISSET_ATTRBIT(&attrbits,
2714 NFSATTRBIT_TIMEACCESSSET))
2715 nd->nd_repstat = NFSERR_INVAL;
2717 * If the na_gid being set is the same as that of
2718 * the directory it is going in, clear it, since
2719 * that is what will be set by default. This allows
2720 * a user that isn't in that group to do the create.
2722 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2723 nva.na_gid == dirfor.na_gid)
2724 NFSVNO_UNSET(&nva, gid);
2725 if (nd->nd_repstat == 0)
2726 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2729 nd->nd_repstat = NFSERR_BADXDR;
2732 } else if (create != NFSV4OPEN_NOCREATE) {
2733 nd->nd_repstat = NFSERR_BADXDR;
2738 * Now, handle the claim, which usually includes looking up a
2739 * name in the directory referenced by dp. The exception is
2740 * NFSV4OPEN_CLAIMPREVIOUS.
2742 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2743 claim = fxdr_unsigned(int, *tl);
2744 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2745 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2746 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2747 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2748 stp->ls_flags |= NFSLCK_DELEGCUR;
2749 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2750 stp->ls_flags |= NFSLCK_DELEGPREV;
2752 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2753 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2754 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2755 claim != NFSV4OPEN_CLAIMNULL)
2756 nd->nd_repstat = NFSERR_INVAL;
2757 if (nd->nd_repstat) {
2758 nd->nd_repstat = nfsrv_opencheck(clientid,
2759 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2762 if (create == NFSV4OPEN_CREATE)
2763 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2764 LOCKPARENT | LOCKLEAF | SAVESTART);
2766 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2767 LOCKLEAF | SAVESTART);
2768 nfsvno_setpathbuf(&named, &bufp, &hashp);
2769 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2772 #ifdef NFS4_ACL_EXTATTR_NAME
2775 FREE((caddr_t)stp, M_NFSDSTATE);
2776 nfsvno_relpathbuf(&named);
2777 NFSEXITCODE2(error, nd);
2780 if (!nd->nd_repstat) {
2781 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2785 nfsvno_relpathbuf(&named);
2787 if (create == NFSV4OPEN_CREATE) {
2789 case NFSCREATE_UNCHECKED:
2792 * Clear the setable attribute bits, except
2793 * for Size, if it is being truncated.
2795 NFSZERO_ATTRBIT(&attrbits);
2796 if (NFSVNO_ISSETSIZE(&nva))
2797 NFSSETBIT_ATTRBIT(&attrbits,
2801 case NFSCREATE_GUARDED:
2802 if (named.ni_vp && !nd->nd_repstat)
2803 nd->nd_repstat = EEXIST;
2805 case NFSCREATE_EXCLUSIVE:
2810 case NFSCREATE_EXCLUSIVE41:
2815 nfsvno_open(nd, &named, clientid, &stateid, stp,
2816 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2817 nd->nd_cred, p, exp, &vp);
2818 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2819 NFSV4OPEN_CLAIMFH) {
2820 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2821 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2822 i = fxdr_unsigned(int, *tl);
2824 case NFSV4OPEN_DELEGATEREAD:
2825 stp->ls_flags |= NFSLCK_DELEGREAD;
2827 case NFSV4OPEN_DELEGATEWRITE:
2828 stp->ls_flags |= NFSLCK_DELEGWRITE;
2829 case NFSV4OPEN_DELEGATENONE:
2832 nd->nd_repstat = NFSERR_BADXDR;
2835 stp->ls_flags |= NFSLCK_RECLAIM;
2838 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
2839 nd->nd_repstat = NFSERR_INVAL;
2842 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2843 if ((vp->v_iflag & VI_DOOMED) == 0)
2844 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2845 stp, vp, nd, p, nd->nd_repstat);
2847 nd->nd_repstat = NFSERR_PERM;
2849 nd->nd_repstat = NFSERR_BADXDR;
2854 * Do basic access checking.
2856 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2858 * The IETF working group decided that this is the correct
2859 * error return for all non-regular files.
2861 nd->nd_repstat = NFSERR_SYMLINK;
2863 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2864 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2865 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2866 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2867 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2868 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2870 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2871 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2872 NFSACCCHK_VPISLOCKED, NULL);
2875 if (!nd->nd_repstat) {
2876 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2877 if (!nd->nd_repstat) {
2878 tverf[0] = nva.na_atime.tv_sec;
2879 tverf[1] = nva.na_atime.tv_nsec;
2882 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2883 cverf[1] != tverf[1]))
2884 nd->nd_repstat = EEXIST;
2886 * Do the open locking/delegation stuff.
2888 if (!nd->nd_repstat)
2889 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2890 &delegstateid, &rflags, exp, p, nva.na_filerev);
2893 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2894 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2895 * (ie: Leave the NFSVOPUNLOCK() about here.)
2898 NFSVOPUNLOCK(vp, 0);
2900 FREE((caddr_t)stp, M_NFSDSTATE);
2901 if (!nd->nd_repstat && dirp)
2902 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2904 if (!nd->nd_repstat) {
2905 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2906 *tl++ = txdr_unsigned(stateid.seqid);
2907 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2908 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2909 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2910 *tl++ = newnfs_true;
2916 *tl++ = newnfs_false; /* Since dirp is not locked */
2917 txdr_hyper(dirfor.na_filerev, tl);
2919 txdr_hyper(diraft.na_filerev, tl);
2922 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2923 (void) nfsrv_putattrbit(nd, &attrbits);
2924 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2925 if (rflags & NFSV4OPEN_READDELEGATE)
2926 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2927 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2928 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2929 else if (retext != 0) {
2930 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
2931 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
2932 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2933 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
2935 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
2936 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2937 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
2940 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2941 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
2944 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2945 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2946 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2947 *tl++ = txdr_unsigned(delegstateid.seqid);
2948 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2950 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2951 if (rflags & NFSV4OPEN_RECALL)
2955 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2956 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2957 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2958 txdr_hyper(nva.na_size, tl);
2960 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2961 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2962 *tl++ = txdr_unsigned(0x0);
2963 acemask = NFSV4ACE_ALLFILESMASK;
2964 if (nva.na_mode & S_IRUSR)
2965 acemask |= NFSV4ACE_READMASK;
2966 if (nva.na_mode & S_IWUSR)
2967 acemask |= NFSV4ACE_WRITEMASK;
2968 if (nva.na_mode & S_IXUSR)
2969 acemask |= NFSV4ACE_EXECUTEMASK;
2970 *tl = txdr_unsigned(acemask);
2971 (void) nfsm_strtom(nd, "OWNER@", 6);
2979 #ifdef NFS4_ACL_EXTATTR_NAME
2982 NFSEXITCODE2(0, nd);
2986 #ifdef NFS4_ACL_EXTATTR_NAME
2990 FREE((caddr_t)stp, M_NFSDSTATE);
2991 NFSEXITCODE2(error, nd);
2996 * nfsv4 close service
2999 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3000 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3003 struct nfsstate st, *stp = &st;
3005 nfsv4stateid_t stateid;
3008 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3009 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3010 stp->ls_ownerlen = 0;
3011 stp->ls_op = nd->nd_rp;
3012 stp->ls_uid = nd->nd_cred->cr_uid;
3013 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3014 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3016 stp->ls_flags = NFSLCK_CLOSE;
3017 clientid.lval[0] = stp->ls_stateid.other[0];
3018 clientid.lval[1] = stp->ls_stateid.other[1];
3019 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3020 if ((nd->nd_flag & ND_NFSV41) != 0)
3021 clientid.qval = nd->nd_clientid.qval;
3022 else if (nd->nd_clientid.qval != clientid.qval)
3023 printf("EEK8 multiple clids\n");
3025 if ((nd->nd_flag & ND_NFSV41) != 0)
3026 printf("EEK! no clientid from session\n");
3027 nd->nd_flag |= ND_IMPLIEDCLID;
3028 nd->nd_clientid.qval = clientid.qval;
3030 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3032 if (!nd->nd_repstat) {
3033 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3034 *tl++ = txdr_unsigned(stateid.seqid);
3035 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3037 NFSEXITCODE2(0, nd);
3041 NFSEXITCODE2(error, nd);
3046 * nfsv4 delegpurge service
3049 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3050 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3056 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3057 nd->nd_repstat = NFSERR_WRONGSEC;
3060 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3061 clientid.lval[0] = *tl++;
3062 clientid.lval[1] = *tl;
3063 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3064 if ((nd->nd_flag & ND_NFSV41) != 0)
3065 clientid.qval = nd->nd_clientid.qval;
3066 else if (nd->nd_clientid.qval != clientid.qval)
3067 printf("EEK9 multiple clids\n");
3069 if ((nd->nd_flag & ND_NFSV41) != 0)
3070 printf("EEK! no clientid from session\n");
3071 nd->nd_flag |= ND_IMPLIEDCLID;
3072 nd->nd_clientid.qval = clientid.qval;
3074 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3075 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
3077 NFSEXITCODE2(error, nd);
3082 * nfsv4 delegreturn service
3085 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3086 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3090 nfsv4stateid_t stateid;
3093 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3094 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3095 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3096 clientid.lval[0] = stateid.other[0];
3097 clientid.lval[1] = stateid.other[1];
3098 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3099 if ((nd->nd_flag & ND_NFSV41) != 0)
3100 clientid.qval = nd->nd_clientid.qval;
3101 else if (nd->nd_clientid.qval != clientid.qval)
3102 printf("EEK10 multiple clids\n");
3104 if ((nd->nd_flag & ND_NFSV41) != 0)
3105 printf("EEK! no clientid from session\n");
3106 nd->nd_flag |= ND_IMPLIEDCLID;
3107 nd->nd_clientid.qval = clientid.qval;
3109 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3110 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
3113 NFSEXITCODE2(error, nd);
3118 * nfsv4 get file handle service
3121 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3122 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3126 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3128 if (!nd->nd_repstat)
3129 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3130 NFSEXITCODE2(0, nd);
3135 * nfsv4 open confirm service
3138 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3139 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3142 struct nfsstate st, *stp = &st;
3144 nfsv4stateid_t stateid;
3147 if ((nd->nd_flag & ND_NFSV41) != 0) {
3148 nd->nd_repstat = NFSERR_NOTSUPP;
3151 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3152 stp->ls_ownerlen = 0;
3153 stp->ls_op = nd->nd_rp;
3154 stp->ls_uid = nd->nd_cred->cr_uid;
3155 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3156 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3158 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3159 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3160 stp->ls_flags = NFSLCK_CONFIRM;
3161 clientid.lval[0] = stp->ls_stateid.other[0];
3162 clientid.lval[1] = stp->ls_stateid.other[1];
3163 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3164 if ((nd->nd_flag & ND_NFSV41) != 0)
3165 clientid.qval = nd->nd_clientid.qval;
3166 else if (nd->nd_clientid.qval != clientid.qval)
3167 printf("EEK11 multiple clids\n");
3169 if ((nd->nd_flag & ND_NFSV41) != 0)
3170 printf("EEK! no clientid from session\n");
3171 nd->nd_flag |= ND_IMPLIEDCLID;
3172 nd->nd_clientid.qval = clientid.qval;
3174 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3175 if (!nd->nd_repstat) {
3176 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3177 *tl++ = txdr_unsigned(stateid.seqid);
3178 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3182 NFSEXITCODE2(error, nd);
3187 * nfsv4 open downgrade service
3190 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3191 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3195 struct nfsstate st, *stp = &st;
3197 nfsv4stateid_t stateid;
3200 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3201 stp->ls_ownerlen = 0;
3202 stp->ls_op = nd->nd_rp;
3203 stp->ls_uid = nd->nd_cred->cr_uid;
3204 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3205 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3207 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3208 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3209 i = fxdr_unsigned(int, *tl++);
3211 case NFSV4OPEN_ACCESSREAD:
3212 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3214 case NFSV4OPEN_ACCESSWRITE:
3215 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3217 case NFSV4OPEN_ACCESSBOTH:
3218 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3222 nd->nd_repstat = NFSERR_BADXDR;
3224 i = fxdr_unsigned(int, *tl);
3226 case NFSV4OPEN_DENYNONE:
3228 case NFSV4OPEN_DENYREAD:
3229 stp->ls_flags |= NFSLCK_READDENY;
3231 case NFSV4OPEN_DENYWRITE:
3232 stp->ls_flags |= NFSLCK_WRITEDENY;
3234 case NFSV4OPEN_DENYBOTH:
3235 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3238 nd->nd_repstat = NFSERR_BADXDR;
3241 clientid.lval[0] = stp->ls_stateid.other[0];
3242 clientid.lval[1] = stp->ls_stateid.other[1];
3243 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3244 if ((nd->nd_flag & ND_NFSV41) != 0)
3245 clientid.qval = nd->nd_clientid.qval;
3246 else if (nd->nd_clientid.qval != clientid.qval)
3247 printf("EEK12 multiple clids\n");
3249 if ((nd->nd_flag & ND_NFSV41) != 0)
3250 printf("EEK! no clientid from session\n");
3251 nd->nd_flag |= ND_IMPLIEDCLID;
3252 nd->nd_clientid.qval = clientid.qval;
3254 if (!nd->nd_repstat)
3255 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3257 if (!nd->nd_repstat) {
3258 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3259 *tl++ = txdr_unsigned(stateid.seqid);
3260 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3264 NFSEXITCODE2(error, nd);
3269 * nfsv4 renew lease service
3272 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3273 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3279 if ((nd->nd_flag & ND_NFSV41) != 0) {
3280 nd->nd_repstat = NFSERR_NOTSUPP;
3283 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3284 nd->nd_repstat = NFSERR_WRONGSEC;
3287 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3288 clientid.lval[0] = *tl++;
3289 clientid.lval[1] = *tl;
3290 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3291 if ((nd->nd_flag & ND_NFSV41) != 0)
3292 clientid.qval = nd->nd_clientid.qval;
3293 else if (nd->nd_clientid.qval != clientid.qval)
3294 printf("EEK13 multiple clids\n");
3296 if ((nd->nd_flag & ND_NFSV41) != 0)
3297 printf("EEK! no clientid from session\n");
3298 nd->nd_flag |= ND_IMPLIEDCLID;
3299 nd->nd_clientid.qval = clientid.qval;
3301 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3302 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3304 NFSEXITCODE2(error, nd);
3309 * nfsv4 security info service
3312 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3313 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3317 struct nameidata named;
3318 vnode_t dirp = NULL, vp;
3320 struct nfsexstuff retnes;
3322 int error = 0, savflag, i;
3327 * All this just to get the export flags for the name.
3329 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3330 LOCKLEAF | SAVESTART);
3331 nfsvno_setpathbuf(&named, &bufp, &hashp);
3332 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3335 nfsvno_relpathbuf(&named);
3338 if (!nd->nd_repstat) {
3339 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3342 nfsvno_relpathbuf(&named);
3348 vrele(named.ni_startdir);
3349 nfsvno_relpathbuf(&named);
3350 fh.nfsrvfh_len = NFSX_MYFH;
3352 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3354 savflag = nd->nd_flag;
3355 if (!nd->nd_repstat) {
3356 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3360 nd->nd_flag = savflag;
3365 * Finally have the export flags for name, so we can create
3366 * the security info.
3369 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3370 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3371 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3372 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3373 *tl = txdr_unsigned(RPCAUTH_UNIX);
3375 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3376 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3377 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3378 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3379 nfsgss_mechlist[KERBV_MECH].len);
3380 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3381 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3382 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3384 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3385 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3386 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3387 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3388 nfsgss_mechlist[KERBV_MECH].len);
3389 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3390 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3391 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3393 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3394 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3395 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3396 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3397 nfsgss_mechlist[KERBV_MECH].len);
3398 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3399 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3400 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3404 *sizp = txdr_unsigned(len);
3407 NFSEXITCODE2(error, nd);
3412 * nfsv4 set client id service
3415 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3416 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3420 int error = 0, idlen;
3421 struct nfsclient *clp = NULL;
3422 struct sockaddr_in *rad;
3423 u_char *verf, *ucp, *ucp2, addrbuf[24];
3424 nfsquad_t clientid, confirm;
3426 if ((nd->nd_flag & ND_NFSV41) != 0) {
3427 nd->nd_repstat = NFSERR_NOTSUPP;
3430 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3431 nd->nd_repstat = NFSERR_WRONGSEC;
3434 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3435 verf = (u_char *)tl;
3436 tl += (NFSX_VERF / NFSX_UNSIGNED);
3437 i = fxdr_unsigned(int, *tl);
3438 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3439 nd->nd_repstat = NFSERR_BADXDR;
3443 if (nd->nd_flag & ND_GSS)
3444 i += nd->nd_princlen;
3445 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3446 M_NFSDCLIENT, M_WAITOK);
3447 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3448 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3449 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3450 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3451 clp->lc_req.nr_cred = NULL;
3452 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3453 clp->lc_idlen = idlen;
3454 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3457 if (nd->nd_flag & ND_GSS) {
3458 clp->lc_flags = LCL_GSS;
3459 if (nd->nd_flag & ND_GSSINTEGRITY)
3460 clp->lc_flags |= LCL_GSSINTEGRITY;
3461 else if (nd->nd_flag & ND_GSSPRIVACY)
3462 clp->lc_flags |= LCL_GSSPRIVACY;
3466 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3467 clp->lc_flags |= LCL_NAME;
3468 clp->lc_namelen = nd->nd_princlen;
3469 clp->lc_name = &clp->lc_id[idlen];
3470 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3472 clp->lc_uid = nd->nd_cred->cr_uid;
3473 clp->lc_gid = nd->nd_cred->cr_gid;
3475 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3476 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3477 error = nfsrv_getclientipaddr(nd, clp);
3480 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3481 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3484 * nfsrv_setclient() does the actual work of adding it to the
3485 * client list. If there is no error, the structure has been
3486 * linked into the client list and clp should no longer be used
3487 * here. When an error is returned, it has not been linked in,
3488 * so it should be free'd.
3490 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3491 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3492 if (clp->lc_flags & LCL_TCPCALLBACK)
3493 (void) nfsm_strtom(nd, "tcp", 3);
3495 (void) nfsm_strtom(nd, "udp", 3);
3496 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3497 ucp = (u_char *)&rad->sin_addr.s_addr;
3498 ucp2 = (u_char *)&rad->sin_port;
3499 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3500 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3501 ucp2[0] & 0xff, ucp2[1] & 0xff);
3502 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3505 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3506 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3507 free((caddr_t)clp, M_NFSDCLIENT);
3509 if (!nd->nd_repstat) {
3510 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3511 *tl++ = clientid.lval[0];
3512 *tl++ = clientid.lval[1];
3513 *tl++ = confirm.lval[0];
3514 *tl = confirm.lval[1];
3518 NFSEXITCODE2(0, nd);
3522 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3523 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3524 free((caddr_t)clp, M_NFSDCLIENT);
3526 NFSEXITCODE2(error, nd);
3531 * nfsv4 set client id confirm service
3534 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3535 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3536 __unused struct nfsexstuff *exp)
3540 nfsquad_t clientid, confirm;
3542 if ((nd->nd_flag & ND_NFSV41) != 0) {
3543 nd->nd_repstat = NFSERR_NOTSUPP;
3546 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3547 nd->nd_repstat = NFSERR_WRONGSEC;
3550 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3551 clientid.lval[0] = *tl++;
3552 clientid.lval[1] = *tl++;
3553 confirm.lval[0] = *tl++;
3554 confirm.lval[1] = *tl;
3557 * nfsrv_getclient() searches the client list for a match and
3558 * returns the appropriate NFSERR status.
3560 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3561 NULL, NULL, confirm, 0, nd, p);
3563 NFSEXITCODE2(error, nd);
3568 * nfsv4 verify service
3571 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3572 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3574 int error = 0, ret, fhsize = NFSX_MYFH;
3575 struct nfsvattr nva;
3577 struct nfsfsinfo fs;
3580 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3581 if (!nd->nd_repstat)
3582 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3583 if (!nd->nd_repstat)
3584 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3585 if (!nd->nd_repstat) {
3586 nfsvno_getfs(&fs, isdgram);
3587 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3588 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3590 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3592 nd->nd_repstat = NFSERR_SAME;
3593 else if (ret != NFSERR_NOTSAME)
3594 nd->nd_repstat = ret;
3596 nd->nd_repstat = ret;
3600 NFSEXITCODE2(error, nd);
3608 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3609 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3610 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3613 int error = 0, createdir;
3615 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3616 createdir = fxdr_unsigned(int, *tl);
3617 nd->nd_repstat = NFSERR_NOTSUPP;
3620 NFSEXITCODE2(error, nd);
3625 * nfsv4 release lock owner service
3628 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3629 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3632 struct nfsstate *stp = NULL;
3636 if ((nd->nd_flag & ND_NFSV41) != 0) {
3637 nd->nd_repstat = NFSERR_NOTSUPP;
3640 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3641 nd->nd_repstat = NFSERR_WRONGSEC;
3644 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3645 len = fxdr_unsigned(int, *(tl + 2));
3646 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3647 nd->nd_repstat = NFSERR_BADXDR;
3650 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3651 M_NFSDSTATE, M_WAITOK);
3652 stp->ls_ownerlen = len;
3654 stp->ls_flags = NFSLCK_RELEASE;
3655 stp->ls_uid = nd->nd_cred->cr_uid;
3656 clientid.lval[0] = *tl++;
3657 clientid.lval[1] = *tl;
3658 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3659 if ((nd->nd_flag & ND_NFSV41) != 0)
3660 clientid.qval = nd->nd_clientid.qval;
3661 else if (nd->nd_clientid.qval != clientid.qval)
3662 printf("EEK14 multiple clids\n");
3664 if ((nd->nd_flag & ND_NFSV41) != 0)
3665 printf("EEK! no clientid from session\n");
3666 nd->nd_flag |= ND_IMPLIEDCLID;
3667 nd->nd_clientid.qval = clientid.qval;
3669 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3672 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3673 FREE((caddr_t)stp, M_NFSDSTATE);
3675 NFSEXITCODE2(0, nd);
3679 free((caddr_t)stp, M_NFSDSTATE);
3680 NFSEXITCODE2(error, nd);
3685 * nfsv4 exchange_id service
3688 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3689 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3692 int error = 0, i, idlen;
3693 struct nfsclient *clp = NULL;
3694 nfsquad_t clientid, confirm;
3696 uint32_t sp4type, v41flags;
3697 uint64_t owner_minor;
3698 struct timespec verstime;
3700 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3701 nd->nd_repstat = NFSERR_WRONGSEC;
3704 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3705 verf = (uint8_t *)tl;
3706 tl += (NFSX_VERF / NFSX_UNSIGNED);
3707 i = fxdr_unsigned(int, *tl);
3708 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3709 nd->nd_repstat = NFSERR_BADXDR;
3713 if (nd->nd_flag & ND_GSS)
3714 i += nd->nd_princlen;
3715 clp = (struct nfsclient *)malloc(sizeof(struct nfsclient) + i,
3716 M_NFSDCLIENT, M_WAITOK | M_ZERO);
3717 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3718 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3719 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3720 clp->lc_req.nr_cred = NULL;
3721 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3722 clp->lc_idlen = idlen;
3723 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3726 if ((nd->nd_flag & ND_GSS) != 0) {
3727 clp->lc_flags = LCL_GSS | LCL_NFSV41;
3728 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
3729 clp->lc_flags |= LCL_GSSINTEGRITY;
3730 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
3731 clp->lc_flags |= LCL_GSSPRIVACY;
3733 clp->lc_flags = LCL_NFSV41;
3734 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
3735 clp->lc_flags |= LCL_NAME;
3736 clp->lc_namelen = nd->nd_princlen;
3737 clp->lc_name = &clp->lc_id[idlen];
3738 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3740 clp->lc_uid = nd->nd_cred->cr_uid;
3741 clp->lc_gid = nd->nd_cred->cr_gid;
3743 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3744 v41flags = fxdr_unsigned(uint32_t, *tl++);
3745 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
3746 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
3747 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
3748 nd->nd_repstat = NFSERR_INVAL;
3751 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
3752 confirm.lval[1] = 1;
3754 confirm.lval[1] = 0;
3755 v41flags = NFSV4EXCH_USENONPNFS;
3756 sp4type = fxdr_unsigned(uint32_t, *tl);
3757 if (sp4type != NFSV4EXCH_SP4NONE) {
3758 nd->nd_repstat = NFSERR_NOTSUPP;
3763 * nfsrv_setclient() does the actual work of adding it to the
3764 * client list. If there is no error, the structure has been
3765 * linked into the client list and clp should no longer be used
3766 * here. When an error is returned, it has not been linked in,
3767 * so it should be free'd.
3769 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3771 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3772 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3773 free(clp, M_NFSDCLIENT);
3775 if (nd->nd_repstat == 0) {
3776 if (confirm.lval[1] != 0)
3777 v41flags |= NFSV4EXCH_CONFIRMEDR;
3778 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
3779 *tl++ = clientid.lval[0]; /* ClientID */
3780 *tl++ = clientid.lval[1];
3781 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
3782 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
3783 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
3784 owner_minor = 0; /* Owner */
3785 txdr_hyper(owner_minor, tl); /* Minor */
3786 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
3787 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
3788 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3789 *tl++ = txdr_unsigned(NFSX_UNSIGNED);
3790 *tl++ = time_uptime; /* Make scope a unique value. */
3791 *tl = txdr_unsigned(1);
3792 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
3793 (void)nfsm_strtom(nd, version, strlen(version));
3794 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
3795 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
3796 verstime.tv_nsec = 0;
3797 txdr_nfsv4time(&verstime, tl);
3799 NFSEXITCODE2(0, nd);
3803 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3804 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3805 free(clp, M_NFSDCLIENT);
3807 NFSEXITCODE2(error, nd);
3812 * nfsv4 create session service
3815 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
3816 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3820 nfsquad_t clientid, confirm;
3821 struct nfsdsession *sep = NULL;
3824 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3825 nd->nd_repstat = NFSERR_WRONGSEC;
3828 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
3829 M_NFSDSESSION, M_WAITOK | M_ZERO);
3830 sep->sess_refcnt = 1;
3831 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
3832 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
3833 clientid.lval[0] = *tl++;
3834 clientid.lval[1] = *tl++;
3835 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
3836 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
3837 /* Persistent sessions and RDMA are not supported. */
3838 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
3840 /* Fore channel attributes. */
3841 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3842 tl++; /* Header pad always 0. */
3843 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
3844 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
3845 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
3846 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
3847 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
3848 if (sep->sess_maxslots > NFSV4_SLOTS)
3849 sep->sess_maxslots = NFSV4_SLOTS;
3850 rdmacnt = fxdr_unsigned(uint32_t, *tl);
3852 nd->nd_repstat = NFSERR_BADXDR;
3854 } else if (rdmacnt == 1)
3855 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3857 /* Back channel attributes. */
3858 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3859 tl++; /* Header pad always 0. */
3860 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
3861 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
3862 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
3863 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
3864 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
3865 rdmacnt = fxdr_unsigned(uint32_t, *tl);
3867 nd->nd_repstat = NFSERR_BADXDR;
3869 } else if (rdmacnt == 1)
3870 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3872 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3873 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
3876 * nfsrv_getclient() searches the client list for a match and
3877 * returns the appropriate NFSERR status.
3879 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
3880 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
3881 if (nd->nd_repstat == 0) {
3882 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3883 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
3884 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
3885 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
3886 *tl++ = txdr_unsigned(sep->sess_crflags);
3888 /* Fore channel attributes. */
3890 *tl++ = txdr_unsigned(sep->sess_maxreq);
3891 *tl++ = txdr_unsigned(sep->sess_maxresp);
3892 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
3893 *tl++ = txdr_unsigned(sep->sess_maxops);
3894 *tl++ = txdr_unsigned(sep->sess_maxslots);
3895 *tl++ = txdr_unsigned(1);
3896 *tl++ = txdr_unsigned(0); /* No RDMA. */
3898 /* Back channel attributes. */
3900 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
3901 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
3902 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
3903 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
3904 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
3905 *tl++ = txdr_unsigned(1);
3906 *tl = txdr_unsigned(0); /* No RDMA. */
3909 if (nd->nd_repstat != 0 && sep != NULL)
3910 free(sep, M_NFSDSESSION);
3911 NFSEXITCODE2(error, nd);
3916 * nfsv4 sequence service
3919 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
3920 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3923 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
3924 int cache_this, error = 0;
3926 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3927 nd->nd_repstat = NFSERR_WRONGSEC;
3930 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
3931 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
3932 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
3933 sequenceid = fxdr_unsigned(uint32_t, *tl++);
3934 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
3935 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
3936 if (*tl == newnfs_true)
3940 nd->nd_flag |= ND_HASSEQUENCE;
3941 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
3942 &target_highest_slotid, cache_this, &sflags, p);
3943 if (nd->nd_repstat == 0) {
3944 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3945 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
3946 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
3947 *tl++ = txdr_unsigned(sequenceid);
3948 *tl++ = txdr_unsigned(nd->nd_slotid);
3949 *tl++ = txdr_unsigned(highest_slotid);
3950 *tl++ = txdr_unsigned(target_highest_slotid);
3951 *tl = txdr_unsigned(sflags);
3954 NFSEXITCODE2(error, nd);
3959 * nfsv4 reclaim complete service
3962 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
3963 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3968 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3969 nd->nd_repstat = NFSERR_WRONGSEC;
3972 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3973 if (*tl == newnfs_true)
3974 nd->nd_repstat = NFSERR_NOTSUPP;
3976 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
3978 NFSEXITCODE2(error, nd);
3983 * nfsv4 destroy clientid service
3986 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
3987 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3993 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3994 nd->nd_repstat = NFSERR_WRONGSEC;
3997 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3998 clientid.lval[0] = *tl++;
3999 clientid.lval[1] = *tl;
4000 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4002 NFSEXITCODE2(error, nd);
4007 * nfsv4 destroy session service
4010 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4011 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4013 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4016 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4017 nd->nd_repstat = NFSERR_WRONGSEC;
4020 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4021 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4022 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4024 NFSEXITCODE2(error, nd);
4029 * nfsv4 free stateid service
4032 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4033 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4036 nfsv4stateid_t stateid;
4039 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4040 nd->nd_repstat = NFSERR_WRONGSEC;
4043 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4044 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4045 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4046 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4048 NFSEXITCODE2(error, nd);
4053 * nfsv4 service not supported
4056 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4057 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4060 nd->nd_repstat = NFSERR_NOTSUPP;
4061 NFSEXITCODE2(0, nd);