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 * 3. 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 extern int nfsrv_statehashsize;
57 #endif /* !APPLEKEXT */
59 static int nfs_async = 0;
60 SYSCTL_DECL(_vfs_nfsd);
61 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
62 "Tell client that writes were synced even though they were not");
65 * This list defines the GSS mechanisms supported.
66 * (Don't ask me how you get these strings from the RFC stuff like
67 * iso(1), org(3)... but someone did it, so I don't need to know.)
69 static struct nfsgss_mechlist nfsgss_mechlist[] = {
70 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
75 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
76 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
77 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
78 int *diraft_retp, nfsattrbit_t *attrbitp,
79 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
81 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
82 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
83 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
84 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
85 NFSPROC_T *p, struct nfsexstuff *exp);
88 * nfs access service (not a part of NFS V2)
91 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
92 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
95 int getret, error = 0;
97 u_int32_t testmode, nfsmode, supported = 0;
100 if (nd->nd_repstat) {
101 nfsrv_postopattr(nd, 1, &nva);
104 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
105 nfsmode = fxdr_unsigned(u_int32_t, *tl);
106 if ((nd->nd_flag & ND_NFSV4) &&
107 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
108 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
109 NFSACCESS_EXECUTE))) {
110 nd->nd_repstat = NFSERR_INVAL;
114 if (nfsmode & NFSACCESS_READ) {
115 supported |= NFSACCESS_READ;
116 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
117 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
118 nfsmode &= ~NFSACCESS_READ;
120 if (nfsmode & NFSACCESS_MODIFY) {
121 supported |= NFSACCESS_MODIFY;
122 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
123 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
124 nfsmode &= ~NFSACCESS_MODIFY;
126 if (nfsmode & NFSACCESS_EXTEND) {
127 supported |= NFSACCESS_EXTEND;
128 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
129 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
130 nfsmode &= ~NFSACCESS_EXTEND;
132 if (nfsmode & NFSACCESS_DELETE) {
133 supported |= NFSACCESS_DELETE;
134 if (vp->v_type == VDIR)
135 deletebit = VDELETE_CHILD;
138 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
139 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
140 nfsmode &= ~NFSACCESS_DELETE;
142 if (vnode_vtype(vp) == VDIR)
143 testmode = NFSACCESS_LOOKUP;
145 testmode = NFSACCESS_EXECUTE;
146 if (nfsmode & testmode) {
147 supported |= (nfsmode & testmode);
148 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
149 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
150 nfsmode &= ~testmode;
152 nfsmode &= supported;
153 if (nd->nd_flag & ND_NFSV3) {
154 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
155 nfsrv_postopattr(nd, getret, &nva);
158 if (nd->nd_flag & ND_NFSV4) {
159 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
160 *tl++ = txdr_unsigned(supported);
162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
163 *tl = txdr_unsigned(nfsmode);
170 NFSEXITCODE2(error, nd);
175 * nfs getattr service
178 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
179 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
183 int at_root = 0, error = 0, supports_nfsv4acls;
184 struct nfsreferral *refp;
185 nfsattrbit_t attrbits, tmpbits;
187 struct vnode *tvp = NULL;
189 uint64_t mounted_on_fileno = 0;
194 if (nd->nd_flag & ND_NFSV4) {
195 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
202 * Check for a referral.
204 refp = nfsv4root_getreferral(vp, NULL, 0);
206 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
211 if (nd->nd_repstat == 0) {
213 NFSSET_ATTRBIT(&tmpbits, &attrbits);
216 * GETATTR with write-only attr time_access_set and time_modify_set
217 * should return NFS4ERR_INVAL.
219 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
220 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
221 error = NFSERR_INVAL;
225 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
226 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
227 accmode |= VREAD_ACL;
229 if (NFSNONZERO_ATTRBIT(&tmpbits))
230 accmode |= VREAD_ATTRIBUTES;
232 nd->nd_repstat = nfsvno_accchk(vp, accmode,
233 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
234 NFSACCCHK_VPISLOCKED, NULL);
238 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
239 if (!nd->nd_repstat) {
240 if (nd->nd_flag & ND_NFSV4) {
241 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
242 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
244 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
245 &nva, &attrbits, nd->nd_cred, p);
246 if (nd->nd_repstat == 0) {
247 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
249 if (nfsrv_enable_crossmntpt != 0 &&
250 vp->v_type == VDIR &&
251 (vp->v_vflag & VV_ROOT) != 0 &&
253 tvp = mp->mnt_vnodecovered;
261 if ((nd->nd_repstat =
262 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
263 nd->nd_repstat = VOP_GETATTR(
264 tvp, &va, nd->nd_cred);
268 if (nd->nd_repstat == 0)
269 mounted_on_fileno = (uint64_t)
274 if (nd->nd_repstat == 0)
275 nd->nd_repstat = vfs_busy(mp, 0);
277 if (nd->nd_repstat == 0) {
278 (void)nfsvno_fillattr(nd, mp, vp, &nva,
279 &fh, 0, &attrbits, nd->nd_cred, p,
280 isdgram, 1, supports_nfsv4acls,
281 at_root, mounted_on_fileno);
288 nfsrv_fillattr(nd, &nva);
296 NFSEXITCODE2(error, nd);
301 * nfs setattr service
304 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
305 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
307 struct nfsvattr nva, nva2;
309 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
310 struct timespec guard = { 0, 0 };
311 nfsattrbit_t attrbits, retbits;
312 nfsv4stateid_t stateid;
313 NFSACL_T *aclp = NULL;
315 if (nd->nd_repstat) {
316 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
319 #ifdef NFS4_ACL_EXTATTR_NAME
320 aclp = acl_alloc(M_WAITOK);
323 NFSVNO_ATTRINIT(&nva);
324 NFSZERO_ATTRBIT(&retbits);
325 if (nd->nd_flag & ND_NFSV4) {
326 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
327 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
328 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
330 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
333 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
335 nd->nd_repstat = preat_ret;
336 if (nd->nd_flag & ND_NFSV3) {
337 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
338 gcheck = fxdr_unsigned(int, *tl);
340 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
341 fxdr_nfsv3time(tl, &guard);
343 if (!nd->nd_repstat && gcheck &&
344 (nva2.na_ctime.tv_sec != guard.tv_sec ||
345 nva2.na_ctime.tv_nsec != guard.tv_nsec))
346 nd->nd_repstat = NFSERR_NOT_SYNC;
347 if (nd->nd_repstat) {
349 #ifdef NFS4_ACL_EXTATTR_NAME
352 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
355 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
356 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
359 * Now that we have all the fields, lets do it.
360 * If the size is being changed write access is required, otherwise
361 * just check for a read only file system.
363 if (!nd->nd_repstat) {
364 if (NFSVNO_NOTSETSIZE(&nva)) {
365 if (NFSVNO_EXRDONLY(exp) ||
366 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
367 nd->nd_repstat = EROFS;
369 if (vnode_vtype(vp) != VREG)
370 nd->nd_repstat = EINVAL;
371 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
372 NFSVNO_EXSTRICTACCESS(exp))
373 nd->nd_repstat = nfsvno_accchk(vp,
374 VWRITE, nd->nd_cred, exp, p,
375 NFSACCCHK_NOOVERRIDE,
376 NFSACCCHK_VPISLOCKED, NULL);
379 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
380 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
381 &nva, &attrbits, exp, p);
383 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
385 * For V4, try setting the attrbutes in sets, so that the
386 * reply bitmap will be correct for an error case.
388 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
389 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
390 NFSVNO_ATTRINIT(&nva2);
391 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
392 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
393 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
395 if (!nd->nd_repstat) {
396 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
397 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
398 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
399 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
402 if (!nd->nd_repstat &&
403 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
404 NFSVNO_ATTRINIT(&nva2);
405 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
406 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
409 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
411 if (!nd->nd_repstat &&
412 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
413 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
414 NFSVNO_ATTRINIT(&nva2);
415 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
416 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
417 if (nva.na_vaflags & VA_UTIMES_NULL) {
418 nva2.na_vaflags |= VA_UTIMES_NULL;
419 NFSVNO_SETACTIVE(&nva2, vaflags);
421 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
423 if (!nd->nd_repstat) {
424 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
425 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
426 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
427 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
430 if (!nd->nd_repstat &&
431 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
432 NFSVNO_ATTRINIT(&nva2);
433 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
434 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
437 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
440 #ifdef NFS4_ACL_EXTATTR_NAME
441 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
442 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
443 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
445 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
448 } else if (!nd->nd_repstat) {
449 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
452 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
453 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
455 nd->nd_repstat = postat_ret;
458 #ifdef NFS4_ACL_EXTATTR_NAME
461 if (nd->nd_flag & ND_NFSV3)
462 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
463 else if (nd->nd_flag & ND_NFSV4)
464 (void) nfsrv_putattrbit(nd, &retbits);
465 else if (!nd->nd_repstat)
466 nfsrv_fillattr(nd, &nva);
473 #ifdef NFS4_ACL_EXTATTR_NAME
476 if (nd->nd_flag & ND_NFSV4) {
478 * For all nd_repstat, the V4 reply includes a bitmap,
479 * even NFSERR_BADXDR, which is what this will end up
482 (void) nfsrv_putattrbit(nd, &retbits);
484 NFSEXITCODE2(error, nd);
490 * (Also performs lookup parent for v4)
493 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
494 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
495 struct nfsexstuff *exp)
497 struct nameidata named;
498 vnode_t vp, dirp = NULL;
499 int error = 0, dattr_ret = 1;
500 struct nfsvattr nva, dattr;
504 if (nd->nd_repstat) {
505 nfsrv_postopattr(nd, dattr_ret, &dattr);
510 * For some reason, if dp is a symlink, the error
511 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
513 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
514 nd->nd_repstat = NFSERR_SYMLINK;
519 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
520 LOCKLEAF | SAVESTART);
521 nfsvno_setpathbuf(&named, &bufp, &hashp);
522 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
525 nfsvno_relpathbuf(&named);
528 if (!nd->nd_repstat) {
529 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
532 nfsvno_relpathbuf(&named);
534 if (nd->nd_repstat) {
536 if (nd->nd_flag & ND_NFSV3)
537 dattr_ret = nfsvno_getattr(dirp, &dattr,
541 if (nd->nd_flag & ND_NFSV3)
542 nfsrv_postopattr(nd, dattr_ret, &dattr);
545 if (named.ni_startdir)
546 vrele(named.ni_startdir);
547 nfsvno_relpathbuf(&named);
549 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
550 vp->v_type != VDIR && vp->v_type != VLNK)
552 * Only allow lookup of VDIR and VLNK for traversal of
553 * non-exported volumes during NFSv4 mounting.
555 nd->nd_repstat = ENOENT;
556 if (nd->nd_repstat == 0)
557 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
558 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
559 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
560 if (vpp != NULL && nd->nd_repstat == 0)
565 if (nd->nd_flag & ND_NFSV3)
566 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
570 if (nd->nd_repstat) {
571 if (nd->nd_flag & ND_NFSV3)
572 nfsrv_postopattr(nd, dattr_ret, &dattr);
575 if (nd->nd_flag & ND_NFSV2) {
576 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
577 nfsrv_fillattr(nd, &nva);
578 } else if (nd->nd_flag & ND_NFSV3) {
579 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
580 nfsrv_postopattr(nd, 0, &nva);
581 nfsrv_postopattr(nd, dattr_ret, &dattr);
585 NFSEXITCODE2(error, nd);
590 * nfs readlink service
593 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
594 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
597 mbuf_t mp = NULL, mpend = NULL;
601 if (nd->nd_repstat) {
602 nfsrv_postopattr(nd, getret, &nva);
605 if (vnode_vtype(vp) != VLNK) {
606 if (nd->nd_flag & ND_NFSV2)
607 nd->nd_repstat = ENXIO;
609 nd->nd_repstat = EINVAL;
612 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
614 if (nd->nd_flag & ND_NFSV3)
615 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
617 if (nd->nd_flag & ND_NFSV3)
618 nfsrv_postopattr(nd, getret, &nva);
621 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
622 *tl = txdr_unsigned(len);
623 mbuf_setnext(nd->nd_mb, mp);
625 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
636 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
637 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
640 int error = 0, cnt, getret = 1, reqlen, eof = 0;
644 struct nfsstate st, *stp = &st;
645 struct nfslock lo, *lop = &lo;
646 nfsv4stateid_t stateid;
649 if (nd->nd_repstat) {
650 nfsrv_postopattr(nd, getret, &nva);
653 if (nd->nd_flag & ND_NFSV2) {
654 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
655 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
656 reqlen = fxdr_unsigned(int, *tl);
657 } else if (nd->nd_flag & ND_NFSV3) {
658 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
659 off = fxdr_hyper(tl);
661 reqlen = fxdr_unsigned(int, *tl);
663 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
664 reqlen = fxdr_unsigned(int, *(tl + 6));
666 if (reqlen > NFS_SRVMAXDATA(nd)) {
667 reqlen = NFS_SRVMAXDATA(nd);
668 } else if (reqlen < 0) {
672 if (nd->nd_flag & ND_NFSV4) {
673 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
674 lop->lo_flags = NFSLCK_READ;
675 stp->ls_ownerlen = 0;
677 stp->ls_uid = nd->nd_cred->cr_uid;
678 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
679 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
680 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
681 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
682 if ((nd->nd_flag & ND_NFSV41) != 0)
683 clientid.qval = nd->nd_clientid.qval;
684 else if (nd->nd_clientid.qval != clientid.qval)
685 printf("EEK1 multiple clids\n");
687 if ((nd->nd_flag & ND_NFSV41) != 0)
688 printf("EEK! no clientid from session\n");
689 nd->nd_flag |= ND_IMPLIEDCLID;
690 nd->nd_clientid.qval = clientid.qval;
692 stp->ls_stateid.other[2] = *tl++;
693 off = fxdr_hyper(tl);
696 lop->lo_end = off + reqlen;
698 * Paranoia, just in case it wraps around.
700 if (lop->lo_end < off)
701 lop->lo_end = NFS64BITSSET;
703 if (vnode_vtype(vp) != VREG) {
704 if (nd->nd_flag & ND_NFSV3)
705 nd->nd_repstat = EINVAL;
707 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
710 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
712 nd->nd_repstat = getret;
713 if (!nd->nd_repstat &&
714 (nva.na_uid != nd->nd_cred->cr_uid ||
715 NFSVNO_EXSTRICTACCESS(exp))) {
716 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
718 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
720 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
721 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
722 NFSACCCHK_VPISLOCKED, NULL);
724 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
725 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
726 &stateid, exp, nd, p);
727 if (nd->nd_repstat) {
729 if (nd->nd_flag & ND_NFSV3)
730 nfsrv_postopattr(nd, getret, &nva);
733 if (off >= nva.na_size) {
736 } else if (reqlen == 0)
738 else if ((off + reqlen) >= nva.na_size) {
739 cnt = nva.na_size - off;
745 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
747 if (!(nd->nd_flag & ND_NFSV4)) {
748 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
750 nd->nd_repstat = getret;
752 if (nd->nd_repstat) {
756 if (nd->nd_flag & ND_NFSV3)
757 nfsrv_postopattr(nd, getret, &nva);
762 if (nd->nd_flag & ND_NFSV2) {
763 nfsrv_fillattr(nd, &nva);
764 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
766 if (nd->nd_flag & ND_NFSV3) {
767 nfsrv_postopattr(nd, getret, &nva);
768 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
769 *tl++ = txdr_unsigned(cnt);
771 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
775 *tl++ = newnfs_false;
777 *tl = txdr_unsigned(cnt);
779 mbuf_setnext(nd->nd_mb, m3);
781 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
789 NFSEXITCODE2(error, nd);
797 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
798 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
803 struct nfsvattr nva, forat;
804 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
805 int stable = NFSWRITE_FILESYNC;
807 struct nfsstate st, *stp = &st;
808 struct nfslock lo, *lop = &lo;
809 nfsv4stateid_t stateid;
812 if (nd->nd_repstat) {
813 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
816 if (nd->nd_flag & ND_NFSV2) {
817 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
818 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
820 retlen = len = fxdr_unsigned(int32_t, *tl);
821 } else if (nd->nd_flag & ND_NFSV3) {
822 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
823 off = fxdr_hyper(tl);
825 stable = fxdr_unsigned(int, *tl++);
826 retlen = len = fxdr_unsigned(int32_t, *tl);
828 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
829 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
830 lop->lo_flags = NFSLCK_WRITE;
831 stp->ls_ownerlen = 0;
833 stp->ls_uid = nd->nd_cred->cr_uid;
834 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
835 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
836 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
837 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
838 if ((nd->nd_flag & ND_NFSV41) != 0)
839 clientid.qval = nd->nd_clientid.qval;
840 else if (nd->nd_clientid.qval != clientid.qval)
841 printf("EEK2 multiple clids\n");
843 if ((nd->nd_flag & ND_NFSV41) != 0)
844 printf("EEK! no clientid from session\n");
845 nd->nd_flag |= ND_IMPLIEDCLID;
846 nd->nd_clientid.qval = clientid.qval;
848 stp->ls_stateid.other[2] = *tl++;
849 off = fxdr_hyper(tl);
852 stable = fxdr_unsigned(int, *tl++);
853 retlen = len = fxdr_unsigned(int32_t, *tl);
854 lop->lo_end = off + len;
856 * Paranoia, just in case it wraps around, which shouldn't
857 * ever happen anyhow.
859 if (lop->lo_end < lop->lo_first)
860 lop->lo_end = NFS64BITSSET;
864 * Loop through the mbuf chain, counting how many mbufs are a
865 * part of this write operation, so the iovec size is known.
869 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
885 if (retlen > NFS_SRVMAXIO || retlen < 0)
886 nd->nd_repstat = EIO;
887 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
888 if (nd->nd_flag & ND_NFSV3)
889 nd->nd_repstat = EINVAL;
891 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
894 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
896 nd->nd_repstat = forat_ret;
897 if (!nd->nd_repstat &&
898 (forat.na_uid != nd->nd_cred->cr_uid ||
899 NFSVNO_EXSTRICTACCESS(exp)))
900 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
902 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
903 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
904 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
905 &stateid, exp, nd, p);
907 if (nd->nd_repstat) {
909 if (nd->nd_flag & ND_NFSV3)
910 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
915 * For NFS Version 2, it is not obvious what a write of zero length
916 * should do, but I might as well be consistent with Version 3,
917 * which is to return ok so long as there are no permission problems.
920 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
921 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
922 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
924 panic("nfsrv_write mbuf");
926 if (nd->nd_flag & ND_NFSV4)
929 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
932 nd->nd_repstat = aftat_ret;
933 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
934 if (nd->nd_flag & ND_NFSV3)
935 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
938 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
939 *tl++ = txdr_unsigned(retlen);
941 * If nfs_async is set, then pretend the write was FILESYNC.
942 * Warning: Doing this violates RFC1813 and runs a risk
943 * of data written by a client being lost when the server
946 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
947 *tl++ = txdr_unsigned(stable);
949 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
951 * Actually, there is no need to txdr these fields,
952 * but it may make the values more human readable,
953 * for debugging purposes.
955 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
956 *tl = txdr_unsigned(nfsboottime.tv_usec);
957 } else if (!nd->nd_repstat)
958 nfsrv_fillattr(nd, &nva);
965 NFSEXITCODE2(error, nd);
970 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
971 * now does a truncate to 0 length via. setattr if it already exists
972 * The core creation routine has been extracted out into nfsrv_creatsub(),
973 * so it can also be used by nfsrv_open() for V4.
976 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
977 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
979 struct nfsvattr nva, dirfor, diraft;
980 struct nfsv2_sattr *sp;
981 struct nameidata named;
983 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
984 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
986 vnode_t vp = NULL, dirp = NULL;
991 int32_t cverf[2], tverf[2] = { 0, 0 };
993 if (nd->nd_repstat) {
994 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
997 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
998 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
999 nfsvno_setpathbuf(&named, &bufp, &hashp);
1000 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1003 if (!nd->nd_repstat) {
1004 NFSVNO_ATTRINIT(&nva);
1005 if (nd->nd_flag & ND_NFSV2) {
1006 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1007 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1010 NFSVNO_SETATTRVAL(&nva, type, vtyp);
1011 NFSVNO_SETATTRVAL(&nva, mode,
1012 nfstov_mode(sp->sa_mode));
1013 switch (nva.na_type) {
1015 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1017 NFSVNO_SETATTRVAL(&nva, size,
1023 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1029 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1030 how = fxdr_unsigned(int, *tl);
1032 case NFSCREATE_GUARDED:
1033 case NFSCREATE_UNCHECKED:
1034 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1038 case NFSCREATE_EXCLUSIVE:
1039 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1045 NFSVNO_SETATTRVAL(&nva, type, VREG);
1048 if (nd->nd_repstat) {
1049 nfsvno_relpathbuf(&named);
1050 if (nd->nd_flag & ND_NFSV3) {
1051 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1053 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1060 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1062 if (nd->nd_flag & ND_NFSV2) {
1066 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1070 if (nd->nd_repstat) {
1071 if (nd->nd_flag & ND_NFSV3)
1072 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1079 if (!(nd->nd_flag & ND_NFSV2)) {
1081 case NFSCREATE_GUARDED:
1083 nd->nd_repstat = EEXIST;
1085 case NFSCREATE_UNCHECKED:
1087 case NFSCREATE_EXCLUSIVE:
1088 if (named.ni_vp == NULL)
1089 NFSVNO_SETATTRVAL(&nva, mode, 0);
1095 * Iff doesn't exist, create it
1096 * otherwise just truncate to 0 length
1097 * should I set the mode too ?
1099 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1100 &exclusive_flag, cverf, rdev, p, exp);
1102 if (!nd->nd_repstat) {
1103 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1104 if (!nd->nd_repstat)
1105 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1108 if (!nd->nd_repstat) {
1109 tverf[0] = nva.na_atime.tv_sec;
1110 tverf[1] = nva.na_atime.tv_nsec;
1113 if (nd->nd_flag & ND_NFSV2) {
1114 if (!nd->nd_repstat) {
1115 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1116 nfsrv_fillattr(nd, &nva);
1119 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1120 || cverf[1] != tverf[1]))
1121 nd->nd_repstat = EEXIST;
1122 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1124 if (!nd->nd_repstat) {
1125 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1126 nfsrv_postopattr(nd, 0, &nva);
1128 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1132 NFSEXITCODE2(0, nd);
1136 nfsvno_relpathbuf(&named);
1137 NFSEXITCODE2(error, nd);
1142 * nfs v3 mknod service (and v4 create)
1145 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1146 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1147 struct nfsexstuff *exp)
1149 struct nfsvattr nva, dirfor, diraft;
1151 struct nameidata named;
1152 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1153 u_int32_t major, minor;
1154 enum vtype vtyp = VNON;
1155 nfstype nfs4type = NFNON;
1156 vnode_t vp, dirp = NULL;
1157 nfsattrbit_t attrbits;
1158 char *bufp = NULL, *pathcp = NULL;
1159 u_long *hashp, cnflags;
1160 NFSACL_T *aclp = NULL;
1162 NFSVNO_ATTRINIT(&nva);
1163 cnflags = (LOCKPARENT | SAVESTART);
1164 if (nd->nd_repstat) {
1165 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1168 #ifdef NFS4_ACL_EXTATTR_NAME
1169 aclp = acl_alloc(M_WAITOK);
1174 * For V4, the creation stuff is here, Yuck!
1176 if (nd->nd_flag & ND_NFSV4) {
1177 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1178 vtyp = nfsv34tov_type(*tl);
1179 nfs4type = fxdr_unsigned(nfstype, *tl);
1182 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1189 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1190 major = fxdr_unsigned(u_int32_t, *tl++);
1191 minor = fxdr_unsigned(u_int32_t, *tl);
1192 nva.na_rdev = NFSMAKEDEV(major, minor);
1198 cnflags = (LOCKPARENT | SAVENAME);
1201 nd->nd_repstat = NFSERR_BADTYPE;
1203 #ifdef NFS4_ACL_EXTATTR_NAME
1209 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1210 nfsvno_setpathbuf(&named, &bufp, &hashp);
1211 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1214 if (!nd->nd_repstat) {
1215 if (nd->nd_flag & ND_NFSV3) {
1216 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1217 vtyp = nfsv34tov_type(*tl);
1219 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1223 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1224 (vtyp == VCHR || vtyp == VBLK)) {
1225 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1226 major = fxdr_unsigned(u_int32_t, *tl++);
1227 minor = fxdr_unsigned(u_int32_t, *tl);
1228 nva.na_rdev = NFSMAKEDEV(major, minor);
1232 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1233 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1234 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1235 dirfor.na_gid == nva.na_gid)
1236 NFSVNO_UNSET(&nva, gid);
1237 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1239 if (nd->nd_repstat) {
1241 #ifdef NFS4_ACL_EXTATTR_NAME
1244 nfsvno_relpathbuf(&named);
1246 FREE(pathcp, M_TEMP);
1247 if (nd->nd_flag & ND_NFSV3)
1248 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1254 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1255 * in va_mode, so we'll have to set a default here.
1257 if (NFSVNO_NOTSETMODE(&nva)) {
1265 named.ni_cnd.cn_flags |= WILLBEDIR;
1266 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1267 if (nd->nd_repstat) {
1269 if (nd->nd_flag & ND_NFSV3)
1270 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1274 #ifdef NFS4_ACL_EXTATTR_NAME
1277 if (nd->nd_flag & ND_NFSV3)
1278 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1283 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1285 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1287 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1288 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1290 #ifdef NFS4_ACL_EXTATTR_NAME
1294 } else if (vtyp == VLNK) {
1295 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1296 &dirfor, &diraft, &diraft_ret, &attrbits,
1297 aclp, p, exp, pathcp, pathlen);
1298 #ifdef NFS4_ACL_EXTATTR_NAME
1301 FREE(pathcp, M_TEMP);
1306 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1307 if (!nd->nd_repstat) {
1309 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1310 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1311 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1312 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1314 if (vpp != NULL && nd->nd_repstat == 0) {
1315 NFSVOPUNLOCK(vp, 0);
1321 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1323 if (!nd->nd_repstat) {
1324 if (nd->nd_flag & ND_NFSV3) {
1325 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1326 nfsrv_postopattr(nd, 0, &nva);
1328 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1329 *tl++ = newnfs_false;
1330 txdr_hyper(dirfor.na_filerev, tl);
1332 txdr_hyper(diraft.na_filerev, tl);
1333 (void) nfsrv_putattrbit(nd, &attrbits);
1336 if (nd->nd_flag & ND_NFSV3)
1337 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1338 #ifdef NFS4_ACL_EXTATTR_NAME
1343 NFSEXITCODE2(0, nd);
1347 #ifdef NFS4_ACL_EXTATTR_NAME
1351 nfsvno_relpathbuf(&named);
1353 FREE(pathcp, M_TEMP);
1355 NFSEXITCODE2(error, nd);
1360 * nfs remove service
1363 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1364 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1366 struct nameidata named;
1368 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1369 vnode_t dirp = NULL;
1370 struct nfsvattr dirfor, diraft;
1374 if (nd->nd_repstat) {
1375 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1378 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1379 LOCKPARENT | LOCKLEAF);
1380 nfsvno_setpathbuf(&named, &bufp, &hashp);
1381 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1384 nfsvno_relpathbuf(&named);
1387 if (!nd->nd_repstat) {
1388 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1391 nfsvno_relpathbuf(&named);
1394 if (!(nd->nd_flag & ND_NFSV2)) {
1395 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1402 if (!nd->nd_repstat) {
1403 if (nd->nd_flag & ND_NFSV4) {
1404 if (vnode_vtype(named.ni_vp) == VDIR)
1405 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1406 nd->nd_cred, p, exp);
1408 nd->nd_repstat = nfsvno_removesub(&named, 1,
1409 nd->nd_cred, p, exp);
1410 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1411 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1412 nd->nd_cred, p, exp);
1414 nd->nd_repstat = nfsvno_removesub(&named, 0,
1415 nd->nd_cred, p, exp);
1418 if (!(nd->nd_flag & ND_NFSV2)) {
1420 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1424 if (nd->nd_flag & ND_NFSV3) {
1425 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1427 } else if (!nd->nd_repstat) {
1428 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1429 *tl++ = newnfs_false;
1430 txdr_hyper(dirfor.na_filerev, tl);
1432 txdr_hyper(diraft.na_filerev, tl);
1437 NFSEXITCODE2(error, nd);
1442 * nfs rename service
1445 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1446 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1447 struct nfsexstuff *toexp)
1450 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1451 int tdirfor_ret = 1, tdiraft_ret = 1;
1452 struct nameidata fromnd, tond;
1453 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1454 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1455 struct nfsexstuff tnes;
1457 char *bufp, *tbufp = NULL;
1461 if (nd->nd_repstat) {
1462 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1463 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1466 if (!(nd->nd_flag & ND_NFSV2))
1467 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1468 tond.ni_cnd.cn_nameiop = 0;
1469 tond.ni_startdir = NULL;
1470 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1471 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1472 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1477 nfsvno_relpathbuf(&fromnd);
1481 * Unlock dp in this code section, so it is unlocked before
1482 * tdp gets locked. This avoids a potential LOR if tdp is the
1483 * parent directory of dp.
1485 if (nd->nd_flag & ND_NFSV4) {
1489 NFSVOPUNLOCK(dp, 0);
1490 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1491 p, 0); /* Might lock tdp. */
1493 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1495 NFSVOPUNLOCK(dp, 0);
1498 tfh.nfsrvfh_len = 0;
1499 error = nfsrv_mtofh(nd, &tfh);
1501 error = nfsvno_getfh(dp, &fh, p);
1504 /* todp is always NULL except NFSv4 */
1505 nfsvno_relpathbuf(&fromnd);
1509 /* If this is the same file handle, just VREF() the vnode. */
1510 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1511 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1515 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1517 NFSVOPUNLOCK(dp, 0);
1519 NFSVOPUNLOCK(dp, 0);
1520 nd->nd_cred->cr_uid = nd->nd_saveduid;
1521 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1522 0, p); /* Locks tdp. */
1524 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1526 NFSVOPUNLOCK(tdp, 0);
1530 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1531 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1532 if (!nd->nd_repstat) {
1533 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1538 nfsvno_relpathbuf(&fromnd);
1539 nfsvno_relpathbuf(&tond);
1543 if (nd->nd_repstat) {
1544 if (nd->nd_flag & ND_NFSV3) {
1545 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1547 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1553 nfsvno_relpathbuf(&fromnd);
1554 nfsvno_relpathbuf(&tond);
1559 * Done parsing, now down to business.
1561 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1562 if (nd->nd_repstat) {
1563 if (nd->nd_flag & ND_NFSV3) {
1564 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1566 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1573 nfsvno_relpathbuf(&tond);
1576 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1577 tond.ni_cnd.cn_flags |= WILLBEDIR;
1578 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1579 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1580 nd->nd_flag, nd->nd_cred, p);
1582 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1585 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1591 if (nd->nd_flag & ND_NFSV3) {
1592 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1593 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1594 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1595 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1596 *tl++ = newnfs_false;
1597 txdr_hyper(fdirfor.na_filerev, tl);
1599 txdr_hyper(fdiraft.na_filerev, tl);
1601 *tl++ = newnfs_false;
1602 txdr_hyper(tdirfor.na_filerev, tl);
1604 txdr_hyper(tdiraft.na_filerev, tl);
1608 NFSEXITCODE2(error, nd);
1616 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1617 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1618 struct nfsexstuff *toexp)
1620 struct nameidata named;
1622 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1623 vnode_t dirp = NULL, dp = NULL;
1624 struct nfsvattr dirfor, diraft, at;
1625 struct nfsexstuff tnes;
1630 if (nd->nd_repstat) {
1631 nfsrv_postopattr(nd, getret, &at);
1632 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1635 NFSVOPUNLOCK(vp, 0);
1636 if (vnode_vtype(vp) == VDIR) {
1637 if (nd->nd_flag & ND_NFSV4)
1638 nd->nd_repstat = NFSERR_ISDIR;
1640 nd->nd_repstat = NFSERR_INVAL;
1644 if (!nd->nd_repstat) {
1645 if (nd->nd_flag & ND_NFSV4) {
1649 error = nfsrv_mtofh(nd, &dfh);
1652 /* tovp is always NULL unless NFSv4 */
1655 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1658 NFSVOPUNLOCK(dp, 0);
1661 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1662 LOCKPARENT | SAVENAME | NOCACHE);
1663 if (!nd->nd_repstat) {
1664 nfsvno_setpathbuf(&named, &bufp, &hashp);
1665 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1670 nfsvno_relpathbuf(&named);
1673 if (!nd->nd_repstat) {
1674 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1679 nfsvno_relpathbuf(&named);
1683 if (nd->nd_flag & ND_NFSV2) {
1687 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1691 if (!nd->nd_repstat)
1692 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1693 if (nd->nd_flag & ND_NFSV3)
1694 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1696 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1700 if (nd->nd_flag & ND_NFSV3) {
1701 nfsrv_postopattr(nd, getret, &at);
1702 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1703 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1704 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1705 *tl++ = newnfs_false;
1706 txdr_hyper(dirfor.na_filerev, tl);
1708 txdr_hyper(diraft.na_filerev, tl);
1712 NFSEXITCODE2(error, nd);
1717 * nfs symbolic link service
1720 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1721 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1722 struct nfsexstuff *exp)
1724 struct nfsvattr nva, dirfor, diraft;
1725 struct nameidata named;
1726 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1727 vnode_t dirp = NULL;
1728 char *bufp, *pathcp = NULL;
1731 if (nd->nd_repstat) {
1732 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1737 NFSVNO_ATTRINIT(&nva);
1738 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1739 LOCKPARENT | SAVESTART | NOCACHE);
1740 nfsvno_setpathbuf(&named, &bufp, &hashp);
1741 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1742 if (!error && !nd->nd_repstat)
1743 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1746 nfsvno_relpathbuf(&named);
1749 if (!nd->nd_repstat) {
1750 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1753 nfsvno_relpathbuf(&named);
1755 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1761 * And call nfsrvd_symlinksub() to do the common code. It will
1762 * return EBADRPC upon a parsing error, 0 otherwise.
1764 if (!nd->nd_repstat) {
1766 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1768 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1769 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1771 } else if (dirp != NULL) {
1772 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1776 FREE(pathcp, M_TEMP);
1778 if (nd->nd_flag & ND_NFSV3) {
1779 if (!nd->nd_repstat) {
1780 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1781 nfsrv_postopattr(nd, 0, &nva);
1783 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1787 NFSEXITCODE2(error, nd);
1792 * Common code for creating a symbolic link.
1795 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1796 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1797 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1798 int *diraft_retp, nfsattrbit_t *attrbitp,
1799 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1804 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1805 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1806 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1807 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1808 if (nd->nd_flag & ND_NFSV3) {
1809 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1810 if (!nd->nd_repstat)
1811 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1812 nvap, nd->nd_cred, p, 1);
1814 if (vpp != NULL && nd->nd_repstat == 0) {
1815 NFSVOPUNLOCK(ndp->ni_vp, 0);
1821 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1824 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1825 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1826 *tl++ = newnfs_false;
1827 txdr_hyper(dirforp->na_filerev, tl);
1829 txdr_hyper(diraftp->na_filerev, tl);
1830 (void) nfsrv_putattrbit(nd, attrbitp);
1833 NFSEXITCODE2(0, nd);
1840 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1841 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1842 struct nfsexstuff *exp)
1844 struct nfsvattr nva, dirfor, diraft;
1845 struct nameidata named;
1847 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1848 vnode_t dirp = NULL;
1852 if (nd->nd_repstat) {
1853 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1856 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1857 LOCKPARENT | SAVENAME | NOCACHE);
1858 nfsvno_setpathbuf(&named, &bufp, &hashp);
1859 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1862 if (!nd->nd_repstat) {
1863 NFSVNO_ATTRINIT(&nva);
1864 if (nd->nd_flag & ND_NFSV3) {
1865 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1869 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1870 nva.na_mode = nfstov_mode(*tl++);
1873 if (!nd->nd_repstat) {
1874 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1877 nfsvno_relpathbuf(&named);
1879 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1883 if (nd->nd_repstat) {
1885 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1889 if (nd->nd_flag & ND_NFSV3)
1890 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1895 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1898 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1900 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1901 &diraft_ret, NULL, NULL, p, exp);
1903 if (nd->nd_flag & ND_NFSV3) {
1904 if (!nd->nd_repstat) {
1905 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1906 nfsrv_postopattr(nd, 0, &nva);
1908 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1909 } else if (!nd->nd_repstat) {
1910 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1911 nfsrv_fillattr(nd, &nva);
1915 NFSEXITCODE2(0, nd);
1919 nfsvno_relpathbuf(&named);
1920 NFSEXITCODE2(error, nd);
1925 * Code common to mkdir for V2,3 and 4.
1928 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1929 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1930 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1931 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1932 NFSPROC_T *p, struct nfsexstuff *exp)
1937 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1938 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1939 nd->nd_cred, p, exp);
1940 if (!nd->nd_repstat) {
1942 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1943 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1944 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1945 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1947 if (vpp && !nd->nd_repstat) {
1948 NFSVOPUNLOCK(vp, 0);
1955 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1958 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1959 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1960 *tl++ = newnfs_false;
1961 txdr_hyper(dirforp->na_filerev, tl);
1963 txdr_hyper(diraftp->na_filerev, tl);
1964 (void) nfsrv_putattrbit(nd, attrbitp);
1967 NFSEXITCODE2(0, nd);
1971 * nfs commit service
1974 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1975 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1977 struct nfsvattr bfor, aft;
1979 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1982 if (nd->nd_repstat) {
1983 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1987 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
1988 if (vp->v_type != VREG) {
1989 if (nd->nd_flag & ND_NFSV3)
1990 error = NFSERR_NOTSUPP;
1992 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
1995 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1998 * XXX At this time VOP_FSYNC() does not accept offset and byte
1999 * count parameters, so these arguments are useless (someday maybe).
2001 off = fxdr_hyper(tl);
2003 cnt = fxdr_unsigned(int, *tl);
2004 if (nd->nd_flag & ND_NFSV3)
2005 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
2006 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2007 if (nd->nd_flag & ND_NFSV3) {
2008 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
2009 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2012 if (!nd->nd_repstat) {
2013 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2014 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2015 *tl = txdr_unsigned(nfsboottime.tv_usec);
2019 NFSEXITCODE2(0, nd);
2023 NFSEXITCODE2(error, nd);
2028 * nfs statfs service
2031 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2032 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2041 if (nd->nd_repstat) {
2042 nfsrv_postopattr(nd, getret, &at);
2045 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2046 nd->nd_repstat = nfsvno_statfs(vp, sf);
2047 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2049 if (nd->nd_flag & ND_NFSV3)
2050 nfsrv_postopattr(nd, getret, &at);
2053 if (nd->nd_flag & ND_NFSV2) {
2054 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2055 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2056 *tl++ = txdr_unsigned(sf->f_bsize);
2057 *tl++ = txdr_unsigned(sf->f_blocks);
2058 *tl++ = txdr_unsigned(sf->f_bfree);
2059 *tl = txdr_unsigned(sf->f_bavail);
2061 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2062 tval = (u_quad_t)sf->f_blocks;
2063 tval *= (u_quad_t)sf->f_bsize;
2064 txdr_hyper(tval, tl); tl += 2;
2065 tval = (u_quad_t)sf->f_bfree;
2066 tval *= (u_quad_t)sf->f_bsize;
2067 txdr_hyper(tval, tl); tl += 2;
2068 tval = (u_quad_t)sf->f_bavail;
2069 tval *= (u_quad_t)sf->f_bsize;
2070 txdr_hyper(tval, tl); tl += 2;
2071 tval = (u_quad_t)sf->f_files;
2072 txdr_hyper(tval, tl); tl += 2;
2073 tval = (u_quad_t)sf->f_ffree;
2074 txdr_hyper(tval, tl); tl += 2;
2075 tval = (u_quad_t)sf->f_ffree;
2076 txdr_hyper(tval, tl); tl += 2;
2082 NFSEXITCODE2(0, nd);
2087 * nfs fsinfo service
2090 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2091 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2094 struct nfsfsinfo fs;
2098 if (nd->nd_repstat) {
2099 nfsrv_postopattr(nd, getret, &at);
2102 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2103 nfsvno_getfs(&fs, isdgram);
2105 nfsrv_postopattr(nd, getret, &at);
2106 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2107 *tl++ = txdr_unsigned(fs.fs_rtmax);
2108 *tl++ = txdr_unsigned(fs.fs_rtpref);
2109 *tl++ = txdr_unsigned(fs.fs_rtmult);
2110 *tl++ = txdr_unsigned(fs.fs_wtmax);
2111 *tl++ = txdr_unsigned(fs.fs_wtpref);
2112 *tl++ = txdr_unsigned(fs.fs_wtmult);
2113 *tl++ = txdr_unsigned(fs.fs_dtpref);
2114 txdr_hyper(fs.fs_maxfilesize, tl);
2116 txdr_nfsv3time(&fs.fs_timedelta, tl);
2118 *tl = txdr_unsigned(fs.fs_properties);
2121 NFSEXITCODE2(0, nd);
2126 * nfs pathconf service
2129 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2130 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2132 struct nfsv3_pathconf *pc;
2134 register_t linkmax, namemax, chownres, notrunc;
2137 if (nd->nd_repstat) {
2138 nfsrv_postopattr(nd, getret, &at);
2141 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2143 if (!nd->nd_repstat)
2144 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2146 if (!nd->nd_repstat)
2147 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2148 &chownres, nd->nd_cred, p);
2149 if (!nd->nd_repstat)
2150 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2152 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2154 nfsrv_postopattr(nd, getret, &at);
2155 if (!nd->nd_repstat) {
2156 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2157 pc->pc_linkmax = txdr_unsigned(linkmax);
2158 pc->pc_namemax = txdr_unsigned(namemax);
2159 pc->pc_notrunc = txdr_unsigned(notrunc);
2160 pc->pc_chownrestricted = txdr_unsigned(chownres);
2163 * These should probably be supported by VOP_PATHCONF(), but
2164 * until msdosfs is exportable (why would you want to?), the
2165 * Unix defaults should be ok.
2167 pc->pc_caseinsensitive = newnfs_false;
2168 pc->pc_casepreserving = newnfs_true;
2172 NFSEXITCODE2(0, nd);
2177 * nfsv4 lock service
2180 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2181 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2185 struct nfsstate *stp = NULL;
2186 struct nfslock *lop;
2187 struct nfslockconflict cf;
2189 u_short flags = NFSLCK_LOCK, lflags;
2190 u_int64_t offset, len;
2191 nfsv4stateid_t stateid;
2194 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2195 i = fxdr_unsigned(int, *tl++);
2197 case NFSV4LOCKT_READW:
2198 flags |= NFSLCK_BLOCKING;
2199 case NFSV4LOCKT_READ:
2200 lflags = NFSLCK_READ;
2202 case NFSV4LOCKT_WRITEW:
2203 flags |= NFSLCK_BLOCKING;
2204 case NFSV4LOCKT_WRITE:
2205 lflags = NFSLCK_WRITE;
2208 nd->nd_repstat = NFSERR_BADXDR;
2211 if (*tl++ == newnfs_true)
2212 flags |= NFSLCK_RECLAIM;
2213 offset = fxdr_hyper(tl);
2215 len = fxdr_hyper(tl);
2217 if (*tl == newnfs_true)
2218 flags |= NFSLCK_OPENTOLOCK;
2219 if (flags & NFSLCK_OPENTOLOCK) {
2220 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2221 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2222 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2223 nd->nd_repstat = NFSERR_BADXDR;
2226 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2227 M_NFSDSTATE, M_WAITOK);
2228 stp->ls_ownerlen = i;
2229 stp->ls_op = nd->nd_rp;
2230 stp->ls_seq = fxdr_unsigned(int, *tl++);
2231 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2232 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2234 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2235 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2236 clientid.lval[0] = *tl++;
2237 clientid.lval[1] = *tl++;
2238 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2239 if ((nd->nd_flag & ND_NFSV41) != 0)
2240 clientid.qval = nd->nd_clientid.qval;
2241 else if (nd->nd_clientid.qval != clientid.qval)
2242 printf("EEK3 multiple clids\n");
2244 if ((nd->nd_flag & ND_NFSV41) != 0)
2245 printf("EEK! no clientid from session\n");
2246 nd->nd_flag |= ND_IMPLIEDCLID;
2247 nd->nd_clientid.qval = clientid.qval;
2249 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2253 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2254 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2255 M_NFSDSTATE, M_WAITOK);
2256 stp->ls_ownerlen = 0;
2257 stp->ls_op = nd->nd_rp;
2258 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2259 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2261 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2262 stp->ls_seq = fxdr_unsigned(int, *tl);
2263 clientid.lval[0] = stp->ls_stateid.other[0];
2264 clientid.lval[1] = stp->ls_stateid.other[1];
2265 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2266 if ((nd->nd_flag & ND_NFSV41) != 0)
2267 clientid.qval = nd->nd_clientid.qval;
2268 else if (nd->nd_clientid.qval != clientid.qval)
2269 printf("EEK4 multiple clids\n");
2271 if ((nd->nd_flag & ND_NFSV41) != 0)
2272 printf("EEK! no clientid from session\n");
2273 nd->nd_flag |= ND_IMPLIEDCLID;
2274 nd->nd_clientid.qval = clientid.qval;
2277 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2278 M_NFSDLOCK, M_WAITOK);
2279 lop->lo_first = offset;
2280 if (len == NFS64BITSSET) {
2281 lop->lo_end = NFS64BITSSET;
2283 lop->lo_end = offset + len;
2284 if (lop->lo_end <= lop->lo_first)
2285 nd->nd_repstat = NFSERR_INVAL;
2287 lop->lo_flags = lflags;
2288 stp->ls_flags = flags;
2289 stp->ls_uid = nd->nd_cred->cr_uid;
2292 * Do basic access checking.
2294 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2295 if (vnode_vtype(vp) == VDIR)
2296 nd->nd_repstat = NFSERR_ISDIR;
2298 nd->nd_repstat = NFSERR_INVAL;
2300 if (!nd->nd_repstat) {
2301 if (lflags & NFSLCK_WRITE) {
2302 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2303 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2304 NFSACCCHK_VPISLOCKED, NULL);
2306 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2307 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2308 NFSACCCHK_VPISLOCKED, NULL);
2310 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2311 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2312 NFSACCCHK_VPISLOCKED, NULL);
2317 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2318 * seqid# gets updated. nfsrv_lockctrl() will return the value
2319 * of nd_repstat, if it gets that far.
2321 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2322 &stateid, exp, nd, p);
2324 FREE((caddr_t)lop, M_NFSDLOCK);
2326 FREE((caddr_t)stp, M_NFSDSTATE);
2327 if (!nd->nd_repstat) {
2328 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2329 *tl++ = txdr_unsigned(stateid.seqid);
2330 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2331 } else if (nd->nd_repstat == NFSERR_DENIED) {
2332 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2333 txdr_hyper(cf.cl_first, tl);
2335 if (cf.cl_end == NFS64BITSSET)
2338 len = cf.cl_end - cf.cl_first;
2339 txdr_hyper(len, tl);
2341 if (cf.cl_flags == NFSLCK_WRITE)
2342 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2344 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2345 *tl++ = stateid.other[0];
2346 *tl = stateid.other[1];
2347 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2350 NFSEXITCODE2(0, nd);
2355 free((caddr_t)stp, M_NFSDSTATE);
2356 NFSEXITCODE2(error, nd);
2361 * nfsv4 lock test service
2364 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2365 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2369 struct nfsstate *stp = NULL;
2370 struct nfslock lo, *lop = &lo;
2371 struct nfslockconflict cf;
2373 nfsv4stateid_t stateid;
2377 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2378 i = fxdr_unsigned(int, *(tl + 7));
2379 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2380 nd->nd_repstat = NFSERR_BADXDR;
2383 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2384 M_NFSDSTATE, M_WAITOK);
2385 stp->ls_ownerlen = i;
2387 stp->ls_flags = NFSLCK_TEST;
2388 stp->ls_uid = nd->nd_cred->cr_uid;
2389 i = fxdr_unsigned(int, *tl++);
2391 case NFSV4LOCKT_READW:
2392 stp->ls_flags |= NFSLCK_BLOCKING;
2393 case NFSV4LOCKT_READ:
2394 lo.lo_flags = NFSLCK_READ;
2396 case NFSV4LOCKT_WRITEW:
2397 stp->ls_flags |= NFSLCK_BLOCKING;
2398 case NFSV4LOCKT_WRITE:
2399 lo.lo_flags = NFSLCK_WRITE;
2402 nd->nd_repstat = NFSERR_BADXDR;
2405 lo.lo_first = fxdr_hyper(tl);
2407 len = fxdr_hyper(tl);
2408 if (len == NFS64BITSSET) {
2409 lo.lo_end = NFS64BITSSET;
2411 lo.lo_end = lo.lo_first + len;
2412 if (lo.lo_end <= lo.lo_first)
2413 nd->nd_repstat = NFSERR_INVAL;
2416 clientid.lval[0] = *tl++;
2417 clientid.lval[1] = *tl;
2418 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2419 if ((nd->nd_flag & ND_NFSV41) != 0)
2420 clientid.qval = nd->nd_clientid.qval;
2421 else if (nd->nd_clientid.qval != clientid.qval)
2422 printf("EEK5 multiple clids\n");
2424 if ((nd->nd_flag & ND_NFSV41) != 0)
2425 printf("EEK! no clientid from session\n");
2426 nd->nd_flag |= ND_IMPLIEDCLID;
2427 nd->nd_clientid.qval = clientid.qval;
2429 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2432 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2433 if (vnode_vtype(vp) == VDIR)
2434 nd->nd_repstat = NFSERR_ISDIR;
2436 nd->nd_repstat = NFSERR_INVAL;
2438 if (!nd->nd_repstat)
2439 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2440 &stateid, exp, nd, p);
2441 if (nd->nd_repstat) {
2442 if (nd->nd_repstat == NFSERR_DENIED) {
2443 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2444 txdr_hyper(cf.cl_first, tl);
2446 if (cf.cl_end == NFS64BITSSET)
2449 len = cf.cl_end - cf.cl_first;
2450 txdr_hyper(len, tl);
2452 if (cf.cl_flags == NFSLCK_WRITE)
2453 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2455 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2456 *tl++ = stp->ls_stateid.other[0];
2457 *tl = stp->ls_stateid.other[1];
2458 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2463 FREE((caddr_t)stp, M_NFSDSTATE);
2464 NFSEXITCODE2(0, nd);
2469 free((caddr_t)stp, M_NFSDSTATE);
2470 NFSEXITCODE2(error, nd);
2475 * nfsv4 unlock service
2478 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2479 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2483 struct nfsstate *stp;
2484 struct nfslock *lop;
2486 nfsv4stateid_t stateid;
2490 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2491 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2492 M_NFSDSTATE, M_WAITOK);
2493 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2494 M_NFSDLOCK, M_WAITOK);
2495 stp->ls_flags = NFSLCK_UNLOCK;
2496 lop->lo_flags = NFSLCK_UNLOCK;
2497 stp->ls_op = nd->nd_rp;
2498 i = fxdr_unsigned(int, *tl++);
2500 case NFSV4LOCKT_READW:
2501 stp->ls_flags |= NFSLCK_BLOCKING;
2502 case NFSV4LOCKT_READ:
2504 case NFSV4LOCKT_WRITEW:
2505 stp->ls_flags |= NFSLCK_BLOCKING;
2506 case NFSV4LOCKT_WRITE:
2509 nd->nd_repstat = NFSERR_BADXDR;
2510 free(stp, M_NFSDSTATE);
2511 free(lop, M_NFSDLOCK);
2514 stp->ls_ownerlen = 0;
2515 stp->ls_uid = nd->nd_cred->cr_uid;
2516 stp->ls_seq = fxdr_unsigned(int, *tl++);
2517 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2518 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2520 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2521 lop->lo_first = fxdr_hyper(tl);
2523 len = fxdr_hyper(tl);
2524 if (len == NFS64BITSSET) {
2525 lop->lo_end = NFS64BITSSET;
2527 lop->lo_end = lop->lo_first + len;
2528 if (lop->lo_end <= lop->lo_first)
2529 nd->nd_repstat = NFSERR_INVAL;
2531 clientid.lval[0] = stp->ls_stateid.other[0];
2532 clientid.lval[1] = stp->ls_stateid.other[1];
2533 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2534 if ((nd->nd_flag & ND_NFSV41) != 0)
2535 clientid.qval = nd->nd_clientid.qval;
2536 else if (nd->nd_clientid.qval != clientid.qval)
2537 printf("EEK6 multiple clids\n");
2539 if ((nd->nd_flag & ND_NFSV41) != 0)
2540 printf("EEK! no clientid from session\n");
2541 nd->nd_flag |= ND_IMPLIEDCLID;
2542 nd->nd_clientid.qval = clientid.qval;
2544 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2545 if (vnode_vtype(vp) == VDIR)
2546 nd->nd_repstat = NFSERR_ISDIR;
2548 nd->nd_repstat = NFSERR_INVAL;
2551 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2552 * seqid# gets incremented. nfsrv_lockctrl() will return the
2553 * value of nd_repstat, if it gets that far.
2555 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2556 &stateid, exp, nd, p);
2558 FREE((caddr_t)stp, M_NFSDSTATE);
2560 free((caddr_t)lop, M_NFSDLOCK);
2561 if (!nd->nd_repstat) {
2562 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2563 *tl++ = txdr_unsigned(stateid.seqid);
2564 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2568 NFSEXITCODE2(error, nd);
2573 * nfsv4 open service
2576 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2577 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2578 struct nfsexstuff *exp)
2582 struct nfsstate *stp = NULL;
2583 int error = 0, create, claim, exclusive_flag = 0;
2584 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2585 int how = NFSCREATE_UNCHECKED;
2586 int32_t cverf[2], tverf[2] = { 0, 0 };
2587 vnode_t vp = NULL, dirp = NULL;
2588 struct nfsvattr nva, dirfor, diraft;
2589 struct nameidata named;
2590 nfsv4stateid_t stateid, delegstateid;
2591 nfsattrbit_t attrbits;
2595 NFSACL_T *aclp = NULL;
2597 #ifdef NFS4_ACL_EXTATTR_NAME
2598 aclp = acl_alloc(M_WAITOK);
2601 NFSZERO_ATTRBIT(&attrbits);
2602 named.ni_startdir = NULL;
2603 named.ni_cnd.cn_nameiop = 0;
2604 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2605 i = fxdr_unsigned(int, *(tl + 5));
2606 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2607 nd->nd_repstat = NFSERR_BADXDR;
2610 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2611 M_NFSDSTATE, M_WAITOK);
2612 stp->ls_ownerlen = i;
2613 stp->ls_op = nd->nd_rp;
2614 stp->ls_flags = NFSLCK_OPEN;
2615 stp->ls_uid = nd->nd_cred->cr_uid;
2616 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2617 i = fxdr_unsigned(int, *tl++);
2619 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2620 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2622 /* For now, ignore these. */
2623 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2624 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2625 case NFSV4OPEN_WANTANYDELEG:
2626 stp->ls_flags |= (NFSLCK_WANTRDELEG |
2628 i &= ~NFSV4OPEN_WANTDELEGMASK;
2630 case NFSV4OPEN_WANTREADDELEG:
2631 stp->ls_flags |= NFSLCK_WANTRDELEG;
2632 i &= ~NFSV4OPEN_WANTDELEGMASK;
2634 case NFSV4OPEN_WANTWRITEDELEG:
2635 stp->ls_flags |= NFSLCK_WANTWDELEG;
2636 i &= ~NFSV4OPEN_WANTDELEGMASK;
2638 case NFSV4OPEN_WANTNODELEG:
2639 stp->ls_flags |= NFSLCK_WANTNODELEG;
2640 i &= ~NFSV4OPEN_WANTDELEGMASK;
2642 case NFSV4OPEN_WANTCANCEL:
2643 printf("NFSv4: ignore Open WantCancel\n");
2644 i &= ~NFSV4OPEN_WANTDELEGMASK;
2647 /* nd_repstat will be set to NFSERR_INVAL below. */
2652 case NFSV4OPEN_ACCESSREAD:
2653 stp->ls_flags |= NFSLCK_READACCESS;
2655 case NFSV4OPEN_ACCESSWRITE:
2656 stp->ls_flags |= NFSLCK_WRITEACCESS;
2658 case NFSV4OPEN_ACCESSBOTH:
2659 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2662 nd->nd_repstat = NFSERR_INVAL;
2664 i = fxdr_unsigned(int, *tl++);
2666 case NFSV4OPEN_DENYNONE:
2668 case NFSV4OPEN_DENYREAD:
2669 stp->ls_flags |= NFSLCK_READDENY;
2671 case NFSV4OPEN_DENYWRITE:
2672 stp->ls_flags |= NFSLCK_WRITEDENY;
2674 case NFSV4OPEN_DENYBOTH:
2675 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2678 nd->nd_repstat = NFSERR_INVAL;
2680 clientid.lval[0] = *tl++;
2681 clientid.lval[1] = *tl;
2682 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2683 if ((nd->nd_flag & ND_NFSV41) != 0)
2684 clientid.qval = nd->nd_clientid.qval;
2685 else if (nd->nd_clientid.qval != clientid.qval)
2686 printf("EEK7 multiple clids\n");
2688 if ((nd->nd_flag & ND_NFSV41) != 0)
2689 printf("EEK! no clientid from session\n");
2690 nd->nd_flag |= ND_IMPLIEDCLID;
2691 nd->nd_clientid.qval = clientid.qval;
2693 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2696 NFSVNO_ATTRINIT(&nva);
2697 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2698 create = fxdr_unsigned(int, *tl);
2699 if (!nd->nd_repstat)
2700 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2701 if (create == NFSV4OPEN_CREATE) {
2704 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2705 how = fxdr_unsigned(int, *tl);
2707 case NFSCREATE_UNCHECKED:
2708 case NFSCREATE_GUARDED:
2709 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2713 * If the na_gid being set is the same as that of
2714 * the directory it is going in, clear it, since
2715 * that is what will be set by default. This allows
2716 * a user that isn't in that group to do the create.
2718 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2719 nva.na_gid == dirfor.na_gid)
2720 NFSVNO_UNSET(&nva, gid);
2721 if (!nd->nd_repstat)
2722 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2724 case NFSCREATE_EXCLUSIVE:
2725 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2729 case NFSCREATE_EXCLUSIVE41:
2730 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2733 error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
2736 if (NFSISSET_ATTRBIT(&attrbits,
2737 NFSATTRBIT_TIMEACCESSSET))
2738 nd->nd_repstat = NFSERR_INVAL;
2740 * If the na_gid being set is the same as that of
2741 * the directory it is going in, clear it, since
2742 * that is what will be set by default. This allows
2743 * a user that isn't in that group to do the create.
2745 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2746 nva.na_gid == dirfor.na_gid)
2747 NFSVNO_UNSET(&nva, gid);
2748 if (nd->nd_repstat == 0)
2749 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2752 nd->nd_repstat = NFSERR_BADXDR;
2755 } else if (create != NFSV4OPEN_NOCREATE) {
2756 nd->nd_repstat = NFSERR_BADXDR;
2761 * Now, handle the claim, which usually includes looking up a
2762 * name in the directory referenced by dp. The exception is
2763 * NFSV4OPEN_CLAIMPREVIOUS.
2765 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2766 claim = fxdr_unsigned(int, *tl);
2767 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2768 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2769 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2770 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2771 stp->ls_flags |= NFSLCK_DELEGCUR;
2772 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2773 stp->ls_flags |= NFSLCK_DELEGPREV;
2775 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2776 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2777 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2778 claim != NFSV4OPEN_CLAIMNULL)
2779 nd->nd_repstat = NFSERR_INVAL;
2780 if (nd->nd_repstat) {
2781 nd->nd_repstat = nfsrv_opencheck(clientid,
2782 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2785 if (create == NFSV4OPEN_CREATE)
2786 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2787 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2789 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2790 LOCKLEAF | SAVESTART);
2791 nfsvno_setpathbuf(&named, &bufp, &hashp);
2792 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2795 #ifdef NFS4_ACL_EXTATTR_NAME
2798 FREE((caddr_t)stp, M_NFSDSTATE);
2799 nfsvno_relpathbuf(&named);
2800 NFSEXITCODE2(error, nd);
2803 if (!nd->nd_repstat) {
2804 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2808 nfsvno_relpathbuf(&named);
2810 if (create == NFSV4OPEN_CREATE) {
2812 case NFSCREATE_UNCHECKED:
2815 * Clear the setable attribute bits, except
2816 * for Size, if it is being truncated.
2818 NFSZERO_ATTRBIT(&attrbits);
2819 if (NFSVNO_ISSETSIZE(&nva))
2820 NFSSETBIT_ATTRBIT(&attrbits,
2824 case NFSCREATE_GUARDED:
2825 if (named.ni_vp && !nd->nd_repstat)
2826 nd->nd_repstat = EEXIST;
2828 case NFSCREATE_EXCLUSIVE:
2833 case NFSCREATE_EXCLUSIVE41:
2838 nfsvno_open(nd, &named, clientid, &stateid, stp,
2839 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2840 nd->nd_cred, p, exp, &vp);
2841 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2842 NFSV4OPEN_CLAIMFH) {
2843 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2844 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2845 i = fxdr_unsigned(int, *tl);
2847 case NFSV4OPEN_DELEGATEREAD:
2848 stp->ls_flags |= NFSLCK_DELEGREAD;
2850 case NFSV4OPEN_DELEGATEWRITE:
2851 stp->ls_flags |= NFSLCK_DELEGWRITE;
2852 case NFSV4OPEN_DELEGATENONE:
2855 nd->nd_repstat = NFSERR_BADXDR;
2858 stp->ls_flags |= NFSLCK_RECLAIM;
2861 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
2862 nd->nd_repstat = NFSERR_INVAL;
2865 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2866 if ((vp->v_iflag & VI_DOOMED) == 0)
2867 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2868 stp, vp, nd, p, nd->nd_repstat);
2870 nd->nd_repstat = NFSERR_PERM;
2872 nd->nd_repstat = NFSERR_BADXDR;
2877 * Do basic access checking.
2879 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2881 * The IETF working group decided that this is the correct
2882 * error return for all non-regular files.
2884 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
2886 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2887 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2888 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2889 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2890 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2891 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2893 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2894 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2895 NFSACCCHK_VPISLOCKED, NULL);
2898 if (!nd->nd_repstat) {
2899 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2900 if (!nd->nd_repstat) {
2901 tverf[0] = nva.na_atime.tv_sec;
2902 tverf[1] = nva.na_atime.tv_nsec;
2905 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2906 cverf[1] != tverf[1]))
2907 nd->nd_repstat = EEXIST;
2909 * Do the open locking/delegation stuff.
2911 if (!nd->nd_repstat)
2912 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2913 &delegstateid, &rflags, exp, p, nva.na_filerev);
2916 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2917 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2918 * (ie: Leave the NFSVOPUNLOCK() about here.)
2921 NFSVOPUNLOCK(vp, 0);
2923 FREE((caddr_t)stp, M_NFSDSTATE);
2924 if (!nd->nd_repstat && dirp)
2925 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2927 if (!nd->nd_repstat) {
2928 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2929 *tl++ = txdr_unsigned(stateid.seqid);
2930 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2931 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2932 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2933 *tl++ = newnfs_true;
2939 *tl++ = newnfs_false; /* Since dirp is not locked */
2940 txdr_hyper(dirfor.na_filerev, tl);
2942 txdr_hyper(diraft.na_filerev, tl);
2945 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2946 (void) nfsrv_putattrbit(nd, &attrbits);
2947 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2948 if (rflags & NFSV4OPEN_READDELEGATE)
2949 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2950 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2951 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2952 else if (retext != 0) {
2953 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
2954 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
2955 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2956 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
2958 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
2959 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2960 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
2963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2964 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
2967 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2968 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2969 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2970 *tl++ = txdr_unsigned(delegstateid.seqid);
2971 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2973 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2974 if (rflags & NFSV4OPEN_RECALL)
2978 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2979 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2980 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2981 txdr_hyper(nva.na_size, tl);
2983 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2984 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2985 *tl++ = txdr_unsigned(0x0);
2986 acemask = NFSV4ACE_ALLFILESMASK;
2987 if (nva.na_mode & S_IRUSR)
2988 acemask |= NFSV4ACE_READMASK;
2989 if (nva.na_mode & S_IWUSR)
2990 acemask |= NFSV4ACE_WRITEMASK;
2991 if (nva.na_mode & S_IXUSR)
2992 acemask |= NFSV4ACE_EXECUTEMASK;
2993 *tl = txdr_unsigned(acemask);
2994 (void) nfsm_strtom(nd, "OWNER@", 6);
3002 #ifdef NFS4_ACL_EXTATTR_NAME
3005 NFSEXITCODE2(0, nd);
3009 #ifdef NFS4_ACL_EXTATTR_NAME
3013 FREE((caddr_t)stp, M_NFSDSTATE);
3014 NFSEXITCODE2(error, nd);
3019 * nfsv4 close service
3022 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3023 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3026 struct nfsstate st, *stp = &st;
3028 nfsv4stateid_t stateid;
3031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3032 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3033 stp->ls_ownerlen = 0;
3034 stp->ls_op = nd->nd_rp;
3035 stp->ls_uid = nd->nd_cred->cr_uid;
3036 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3037 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3039 stp->ls_flags = NFSLCK_CLOSE;
3040 clientid.lval[0] = stp->ls_stateid.other[0];
3041 clientid.lval[1] = stp->ls_stateid.other[1];
3042 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3043 if ((nd->nd_flag & ND_NFSV41) != 0)
3044 clientid.qval = nd->nd_clientid.qval;
3045 else if (nd->nd_clientid.qval != clientid.qval)
3046 printf("EEK8 multiple clids\n");
3048 if ((nd->nd_flag & ND_NFSV41) != 0)
3049 printf("EEK! no clientid from session\n");
3050 nd->nd_flag |= ND_IMPLIEDCLID;
3051 nd->nd_clientid.qval = clientid.qval;
3053 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3055 if (!nd->nd_repstat) {
3056 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3057 *tl++ = txdr_unsigned(stateid.seqid);
3058 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3060 NFSEXITCODE2(0, nd);
3064 NFSEXITCODE2(error, nd);
3069 * nfsv4 delegpurge service
3072 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3073 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3079 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3080 nd->nd_repstat = NFSERR_WRONGSEC;
3083 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3084 clientid.lval[0] = *tl++;
3085 clientid.lval[1] = *tl;
3086 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3087 if ((nd->nd_flag & ND_NFSV41) != 0)
3088 clientid.qval = nd->nd_clientid.qval;
3089 else if (nd->nd_clientid.qval != clientid.qval)
3090 printf("EEK9 multiple clids\n");
3092 if ((nd->nd_flag & ND_NFSV41) != 0)
3093 printf("EEK! no clientid from session\n");
3094 nd->nd_flag |= ND_IMPLIEDCLID;
3095 nd->nd_clientid.qval = clientid.qval;
3097 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3098 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
3100 NFSEXITCODE2(error, nd);
3105 * nfsv4 delegreturn service
3108 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3109 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3113 nfsv4stateid_t stateid;
3116 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3117 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3118 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3119 clientid.lval[0] = stateid.other[0];
3120 clientid.lval[1] = stateid.other[1];
3121 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3122 if ((nd->nd_flag & ND_NFSV41) != 0)
3123 clientid.qval = nd->nd_clientid.qval;
3124 else if (nd->nd_clientid.qval != clientid.qval)
3125 printf("EEK10 multiple clids\n");
3127 if ((nd->nd_flag & ND_NFSV41) != 0)
3128 printf("EEK! no clientid from session\n");
3129 nd->nd_flag |= ND_IMPLIEDCLID;
3130 nd->nd_clientid.qval = clientid.qval;
3132 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3133 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
3136 NFSEXITCODE2(error, nd);
3141 * nfsv4 get file handle service
3144 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3145 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3149 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3151 if (!nd->nd_repstat)
3152 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3153 NFSEXITCODE2(0, nd);
3158 * nfsv4 open confirm service
3161 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3162 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3165 struct nfsstate st, *stp = &st;
3167 nfsv4stateid_t stateid;
3170 if ((nd->nd_flag & ND_NFSV41) != 0) {
3171 nd->nd_repstat = NFSERR_NOTSUPP;
3174 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3175 stp->ls_ownerlen = 0;
3176 stp->ls_op = nd->nd_rp;
3177 stp->ls_uid = nd->nd_cred->cr_uid;
3178 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3179 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3181 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3182 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3183 stp->ls_flags = NFSLCK_CONFIRM;
3184 clientid.lval[0] = stp->ls_stateid.other[0];
3185 clientid.lval[1] = stp->ls_stateid.other[1];
3186 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3187 if ((nd->nd_flag & ND_NFSV41) != 0)
3188 clientid.qval = nd->nd_clientid.qval;
3189 else if (nd->nd_clientid.qval != clientid.qval)
3190 printf("EEK11 multiple clids\n");
3192 if ((nd->nd_flag & ND_NFSV41) != 0)
3193 printf("EEK! no clientid from session\n");
3194 nd->nd_flag |= ND_IMPLIEDCLID;
3195 nd->nd_clientid.qval = clientid.qval;
3197 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3198 if (!nd->nd_repstat) {
3199 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3200 *tl++ = txdr_unsigned(stateid.seqid);
3201 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3205 NFSEXITCODE2(error, nd);
3210 * nfsv4 open downgrade service
3213 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3214 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3218 struct nfsstate st, *stp = &st;
3220 nfsv4stateid_t stateid;
3223 /* opendowngrade can only work on a file object.*/
3224 if (vp->v_type != VREG) {
3225 error = NFSERR_INVAL;
3228 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3229 stp->ls_ownerlen = 0;
3230 stp->ls_op = nd->nd_rp;
3231 stp->ls_uid = nd->nd_cred->cr_uid;
3232 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3233 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3235 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3236 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3237 i = fxdr_unsigned(int, *tl++);
3239 case NFSV4OPEN_ACCESSREAD:
3240 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3242 case NFSV4OPEN_ACCESSWRITE:
3243 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3245 case NFSV4OPEN_ACCESSBOTH:
3246 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3250 nd->nd_repstat = NFSERR_BADXDR;
3252 i = fxdr_unsigned(int, *tl);
3254 case NFSV4OPEN_DENYNONE:
3256 case NFSV4OPEN_DENYREAD:
3257 stp->ls_flags |= NFSLCK_READDENY;
3259 case NFSV4OPEN_DENYWRITE:
3260 stp->ls_flags |= NFSLCK_WRITEDENY;
3262 case NFSV4OPEN_DENYBOTH:
3263 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3266 nd->nd_repstat = NFSERR_BADXDR;
3269 clientid.lval[0] = stp->ls_stateid.other[0];
3270 clientid.lval[1] = stp->ls_stateid.other[1];
3271 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3272 if ((nd->nd_flag & ND_NFSV41) != 0)
3273 clientid.qval = nd->nd_clientid.qval;
3274 else if (nd->nd_clientid.qval != clientid.qval)
3275 printf("EEK12 multiple clids\n");
3277 if ((nd->nd_flag & ND_NFSV41) != 0)
3278 printf("EEK! no clientid from session\n");
3279 nd->nd_flag |= ND_IMPLIEDCLID;
3280 nd->nd_clientid.qval = clientid.qval;
3282 if (!nd->nd_repstat)
3283 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3285 if (!nd->nd_repstat) {
3286 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3287 *tl++ = txdr_unsigned(stateid.seqid);
3288 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3292 NFSEXITCODE2(error, nd);
3297 * nfsv4 renew lease service
3300 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3301 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3307 if ((nd->nd_flag & ND_NFSV41) != 0) {
3308 nd->nd_repstat = NFSERR_NOTSUPP;
3311 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3312 nd->nd_repstat = NFSERR_WRONGSEC;
3315 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3316 clientid.lval[0] = *tl++;
3317 clientid.lval[1] = *tl;
3318 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3319 if ((nd->nd_flag & ND_NFSV41) != 0)
3320 clientid.qval = nd->nd_clientid.qval;
3321 else if (nd->nd_clientid.qval != clientid.qval)
3322 printf("EEK13 multiple clids\n");
3324 if ((nd->nd_flag & ND_NFSV41) != 0)
3325 printf("EEK! no clientid from session\n");
3326 nd->nd_flag |= ND_IMPLIEDCLID;
3327 nd->nd_clientid.qval = clientid.qval;
3329 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3330 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3332 NFSEXITCODE2(error, nd);
3337 * nfsv4 security info service
3340 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3341 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3345 struct nameidata named;
3346 vnode_t dirp = NULL, vp;
3348 struct nfsexstuff retnes;
3350 int error = 0, savflag, i;
3355 * All this just to get the export flags for the name.
3357 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3358 LOCKLEAF | SAVESTART);
3359 nfsvno_setpathbuf(&named, &bufp, &hashp);
3360 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3363 nfsvno_relpathbuf(&named);
3366 if (!nd->nd_repstat) {
3367 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3370 nfsvno_relpathbuf(&named);
3376 vrele(named.ni_startdir);
3377 nfsvno_relpathbuf(&named);
3378 fh.nfsrvfh_len = NFSX_MYFH;
3380 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3382 savflag = nd->nd_flag;
3383 if (!nd->nd_repstat) {
3384 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3388 nd->nd_flag = savflag;
3393 * Finally have the export flags for name, so we can create
3394 * the security info.
3397 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3398 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3399 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3400 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3401 *tl = txdr_unsigned(RPCAUTH_UNIX);
3403 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3404 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3405 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3406 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3407 nfsgss_mechlist[KERBV_MECH].len);
3408 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3409 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3410 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3412 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3413 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3414 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3415 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3416 nfsgss_mechlist[KERBV_MECH].len);
3417 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3418 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3419 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3421 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3422 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3423 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3424 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3425 nfsgss_mechlist[KERBV_MECH].len);
3426 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3427 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3428 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3432 *sizp = txdr_unsigned(len);
3435 NFSEXITCODE2(error, nd);
3440 * nfsv4 set client id service
3443 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3444 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3448 int error = 0, idlen;
3449 struct nfsclient *clp = NULL;
3450 struct sockaddr_in *rad;
3451 u_char *verf, *ucp, *ucp2, addrbuf[24];
3452 nfsquad_t clientid, confirm;
3454 if ((nd->nd_flag & ND_NFSV41) != 0) {
3455 nd->nd_repstat = NFSERR_NOTSUPP;
3458 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3459 nd->nd_repstat = NFSERR_WRONGSEC;
3462 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3463 verf = (u_char *)tl;
3464 tl += (NFSX_VERF / NFSX_UNSIGNED);
3465 i = fxdr_unsigned(int, *tl);
3466 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3467 nd->nd_repstat = NFSERR_BADXDR;
3471 if (nd->nd_flag & ND_GSS)
3472 i += nd->nd_princlen;
3473 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3475 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3476 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3477 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3478 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3479 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3480 clp->lc_req.nr_cred = NULL;
3481 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3482 clp->lc_idlen = idlen;
3483 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3486 if (nd->nd_flag & ND_GSS) {
3487 clp->lc_flags = LCL_GSS;
3488 if (nd->nd_flag & ND_GSSINTEGRITY)
3489 clp->lc_flags |= LCL_GSSINTEGRITY;
3490 else if (nd->nd_flag & ND_GSSPRIVACY)
3491 clp->lc_flags |= LCL_GSSPRIVACY;
3495 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3496 clp->lc_flags |= LCL_NAME;
3497 clp->lc_namelen = nd->nd_princlen;
3498 clp->lc_name = &clp->lc_id[idlen];
3499 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3501 clp->lc_uid = nd->nd_cred->cr_uid;
3502 clp->lc_gid = nd->nd_cred->cr_gid;
3504 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3505 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3506 error = nfsrv_getclientipaddr(nd, clp);
3509 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3510 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3513 * nfsrv_setclient() does the actual work of adding it to the
3514 * client list. If there is no error, the structure has been
3515 * linked into the client list and clp should no longer be used
3516 * here. When an error is returned, it has not been linked in,
3517 * so it should be free'd.
3519 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3520 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3521 if (clp->lc_flags & LCL_TCPCALLBACK)
3522 (void) nfsm_strtom(nd, "tcp", 3);
3524 (void) nfsm_strtom(nd, "udp", 3);
3525 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3526 ucp = (u_char *)&rad->sin_addr.s_addr;
3527 ucp2 = (u_char *)&rad->sin_port;
3528 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3529 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3530 ucp2[0] & 0xff, ucp2[1] & 0xff);
3531 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3534 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3535 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3536 free(clp->lc_stateid, M_NFSDCLIENT);
3537 free(clp, M_NFSDCLIENT);
3539 if (!nd->nd_repstat) {
3540 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3541 *tl++ = clientid.lval[0];
3542 *tl++ = clientid.lval[1];
3543 *tl++ = confirm.lval[0];
3544 *tl = confirm.lval[1];
3548 NFSEXITCODE2(0, nd);
3552 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3553 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3554 free(clp->lc_stateid, M_NFSDCLIENT);
3555 free(clp, M_NFSDCLIENT);
3557 NFSEXITCODE2(error, nd);
3562 * nfsv4 set client id confirm service
3565 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3566 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3567 __unused struct nfsexstuff *exp)
3571 nfsquad_t clientid, confirm;
3573 if ((nd->nd_flag & ND_NFSV41) != 0) {
3574 nd->nd_repstat = NFSERR_NOTSUPP;
3577 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3578 nd->nd_repstat = NFSERR_WRONGSEC;
3581 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3582 clientid.lval[0] = *tl++;
3583 clientid.lval[1] = *tl++;
3584 confirm.lval[0] = *tl++;
3585 confirm.lval[1] = *tl;
3588 * nfsrv_getclient() searches the client list for a match and
3589 * returns the appropriate NFSERR status.
3591 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3592 NULL, NULL, confirm, 0, nd, p);
3594 NFSEXITCODE2(error, nd);
3599 * nfsv4 verify service
3602 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3603 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3605 int error = 0, ret, fhsize = NFSX_MYFH;
3606 struct nfsvattr nva;
3608 struct nfsfsinfo fs;
3611 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3612 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3613 if (!nd->nd_repstat)
3614 nd->nd_repstat = nfsvno_statfs(vp, sf);
3615 if (!nd->nd_repstat)
3616 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3617 if (!nd->nd_repstat) {
3618 nfsvno_getfs(&fs, isdgram);
3619 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3620 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3622 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3624 nd->nd_repstat = NFSERR_SAME;
3625 else if (ret != NFSERR_NOTSAME)
3626 nd->nd_repstat = ret;
3628 nd->nd_repstat = ret;
3633 NFSEXITCODE2(error, nd);
3641 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3642 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3643 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3646 int error = 0, createdir;
3648 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3649 createdir = fxdr_unsigned(int, *tl);
3650 nd->nd_repstat = NFSERR_NOTSUPP;
3653 NFSEXITCODE2(error, nd);
3658 * nfsv4 release lock owner service
3661 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3662 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3665 struct nfsstate *stp = NULL;
3669 if ((nd->nd_flag & ND_NFSV41) != 0) {
3670 nd->nd_repstat = NFSERR_NOTSUPP;
3673 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3674 nd->nd_repstat = NFSERR_WRONGSEC;
3677 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3678 len = fxdr_unsigned(int, *(tl + 2));
3679 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3680 nd->nd_repstat = NFSERR_BADXDR;
3683 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3684 M_NFSDSTATE, M_WAITOK);
3685 stp->ls_ownerlen = len;
3687 stp->ls_flags = NFSLCK_RELEASE;
3688 stp->ls_uid = nd->nd_cred->cr_uid;
3689 clientid.lval[0] = *tl++;
3690 clientid.lval[1] = *tl;
3691 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3692 if ((nd->nd_flag & ND_NFSV41) != 0)
3693 clientid.qval = nd->nd_clientid.qval;
3694 else if (nd->nd_clientid.qval != clientid.qval)
3695 printf("EEK14 multiple clids\n");
3697 if ((nd->nd_flag & ND_NFSV41) != 0)
3698 printf("EEK! no clientid from session\n");
3699 nd->nd_flag |= ND_IMPLIEDCLID;
3700 nd->nd_clientid.qval = clientid.qval;
3702 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3705 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3706 FREE((caddr_t)stp, M_NFSDSTATE);
3708 NFSEXITCODE2(0, nd);
3712 free((caddr_t)stp, M_NFSDSTATE);
3713 NFSEXITCODE2(error, nd);
3718 * nfsv4 exchange_id service
3721 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3722 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3725 int error = 0, i, idlen;
3726 struct nfsclient *clp = NULL;
3727 nfsquad_t clientid, confirm;
3729 uint32_t sp4type, v41flags;
3730 uint64_t owner_minor;
3731 struct timespec verstime;
3733 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3734 nd->nd_repstat = NFSERR_WRONGSEC;
3737 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3738 verf = (uint8_t *)tl;
3739 tl += (NFSX_VERF / NFSX_UNSIGNED);
3740 i = fxdr_unsigned(int, *tl);
3741 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3742 nd->nd_repstat = NFSERR_BADXDR;
3746 if (nd->nd_flag & ND_GSS)
3747 i += nd->nd_princlen;
3748 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3750 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3751 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3752 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3753 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3754 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3755 clp->lc_req.nr_cred = NULL;
3756 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3757 clp->lc_idlen = idlen;
3758 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3761 if ((nd->nd_flag & ND_GSS) != 0) {
3762 clp->lc_flags = LCL_GSS | LCL_NFSV41;
3763 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
3764 clp->lc_flags |= LCL_GSSINTEGRITY;
3765 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
3766 clp->lc_flags |= LCL_GSSPRIVACY;
3768 clp->lc_flags = LCL_NFSV41;
3769 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
3770 clp->lc_flags |= LCL_NAME;
3771 clp->lc_namelen = nd->nd_princlen;
3772 clp->lc_name = &clp->lc_id[idlen];
3773 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3775 clp->lc_uid = nd->nd_cred->cr_uid;
3776 clp->lc_gid = nd->nd_cred->cr_gid;
3778 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3779 v41flags = fxdr_unsigned(uint32_t, *tl++);
3780 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
3781 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
3782 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
3783 nd->nd_repstat = NFSERR_INVAL;
3786 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
3787 confirm.lval[1] = 1;
3789 confirm.lval[1] = 0;
3790 v41flags = NFSV4EXCH_USENONPNFS;
3791 sp4type = fxdr_unsigned(uint32_t, *tl);
3792 if (sp4type != NFSV4EXCH_SP4NONE) {
3793 nd->nd_repstat = NFSERR_NOTSUPP;
3798 * nfsrv_setclient() does the actual work of adding it to the
3799 * client list. If there is no error, the structure has been
3800 * linked into the client list and clp should no longer be used
3801 * here. When an error is returned, it has not been linked in,
3802 * so it should be free'd.
3804 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3806 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3807 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3808 free(clp->lc_stateid, M_NFSDCLIENT);
3809 free(clp, M_NFSDCLIENT);
3811 if (nd->nd_repstat == 0) {
3812 if (confirm.lval[1] != 0)
3813 v41flags |= NFSV4EXCH_CONFIRMEDR;
3814 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
3815 *tl++ = clientid.lval[0]; /* ClientID */
3816 *tl++ = clientid.lval[1];
3817 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
3818 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
3819 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
3820 owner_minor = 0; /* Owner */
3821 txdr_hyper(owner_minor, tl); /* Minor */
3822 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
3823 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
3824 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3825 *tl++ = txdr_unsigned(NFSX_UNSIGNED);
3826 *tl++ = time_uptime; /* Make scope a unique value. */
3827 *tl = txdr_unsigned(1);
3828 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
3829 (void)nfsm_strtom(nd, version, strlen(version));
3830 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
3831 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
3832 verstime.tv_nsec = 0;
3833 txdr_nfsv4time(&verstime, tl);
3835 NFSEXITCODE2(0, nd);
3839 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3840 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3841 free(clp->lc_stateid, M_NFSDCLIENT);
3842 free(clp, M_NFSDCLIENT);
3844 NFSEXITCODE2(error, nd);
3849 * nfsv4 create session service
3852 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
3853 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3857 nfsquad_t clientid, confirm;
3858 struct nfsdsession *sep = NULL;
3861 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3862 nd->nd_repstat = NFSERR_WRONGSEC;
3865 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
3866 M_NFSDSESSION, M_WAITOK | M_ZERO);
3867 sep->sess_refcnt = 1;
3868 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
3869 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
3870 clientid.lval[0] = *tl++;
3871 clientid.lval[1] = *tl++;
3872 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
3873 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
3874 /* Persistent sessions and RDMA are not supported. */
3875 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
3877 /* Fore channel attributes. */
3878 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3879 tl++; /* Header pad always 0. */
3880 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
3881 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
3882 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
3883 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
3884 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
3885 if (sep->sess_maxslots > NFSV4_SLOTS)
3886 sep->sess_maxslots = NFSV4_SLOTS;
3887 rdmacnt = fxdr_unsigned(uint32_t, *tl);
3889 nd->nd_repstat = NFSERR_BADXDR;
3891 } else if (rdmacnt == 1)
3892 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3894 /* Back channel attributes. */
3895 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3896 tl++; /* Header pad always 0. */
3897 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
3898 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
3899 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
3900 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
3901 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
3902 rdmacnt = fxdr_unsigned(uint32_t, *tl);
3904 nd->nd_repstat = NFSERR_BADXDR;
3906 } else if (rdmacnt == 1)
3907 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3909 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3910 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
3913 * nfsrv_getclient() searches the client list for a match and
3914 * returns the appropriate NFSERR status.
3916 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
3917 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
3918 if (nd->nd_repstat == 0) {
3919 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3920 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
3921 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
3922 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
3923 *tl++ = txdr_unsigned(sep->sess_crflags);
3925 /* Fore channel attributes. */
3927 *tl++ = txdr_unsigned(sep->sess_maxreq);
3928 *tl++ = txdr_unsigned(sep->sess_maxresp);
3929 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
3930 *tl++ = txdr_unsigned(sep->sess_maxops);
3931 *tl++ = txdr_unsigned(sep->sess_maxslots);
3932 *tl++ = txdr_unsigned(1);
3933 *tl++ = txdr_unsigned(0); /* No RDMA. */
3935 /* Back channel attributes. */
3937 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
3938 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
3939 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
3940 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
3941 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
3942 *tl++ = txdr_unsigned(1);
3943 *tl = txdr_unsigned(0); /* No RDMA. */
3946 if (nd->nd_repstat != 0 && sep != NULL)
3947 free(sep, M_NFSDSESSION);
3948 NFSEXITCODE2(error, nd);
3953 * nfsv4 sequence service
3956 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
3957 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3960 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
3961 int cache_this, error = 0;
3963 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3964 nd->nd_repstat = NFSERR_WRONGSEC;
3967 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
3968 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
3969 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
3970 sequenceid = fxdr_unsigned(uint32_t, *tl++);
3971 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
3972 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
3973 if (*tl == newnfs_true)
3977 nd->nd_flag |= ND_HASSEQUENCE;
3978 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
3979 &target_highest_slotid, cache_this, &sflags, p);
3980 if (nd->nd_repstat == 0) {
3981 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3982 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
3983 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
3984 *tl++ = txdr_unsigned(sequenceid);
3985 *tl++ = txdr_unsigned(nd->nd_slotid);
3986 *tl++ = txdr_unsigned(highest_slotid);
3987 *tl++ = txdr_unsigned(target_highest_slotid);
3988 *tl = txdr_unsigned(sflags);
3991 NFSEXITCODE2(error, nd);
3996 * nfsv4 reclaim complete service
3999 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4000 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4005 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4006 nd->nd_repstat = NFSERR_WRONGSEC;
4009 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4010 if (*tl == newnfs_true)
4011 nd->nd_repstat = NFSERR_NOTSUPP;
4013 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
4015 NFSEXITCODE2(error, nd);
4020 * nfsv4 destroy clientid service
4023 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4024 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4030 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4031 nd->nd_repstat = NFSERR_WRONGSEC;
4034 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4035 clientid.lval[0] = *tl++;
4036 clientid.lval[1] = *tl;
4037 nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4039 NFSEXITCODE2(error, nd);
4044 * nfsv4 destroy session service
4047 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4048 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4050 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4053 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4054 nd->nd_repstat = NFSERR_WRONGSEC;
4057 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4058 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4059 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4061 NFSEXITCODE2(error, nd);
4066 * nfsv4 free stateid service
4069 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4070 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4073 nfsv4stateid_t stateid;
4076 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4077 nd->nd_repstat = NFSERR_WRONGSEC;
4080 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4081 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4082 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4083 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4085 NFSEXITCODE2(error, nd);
4090 * nfsv4 service not supported
4093 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4094 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4097 nd->nd_repstat = NFSERR_NOTSUPP;
4098 NFSEXITCODE2(0, nd);