2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * nfs version 2, 3 and 4 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42 * function in nfsd_port.c
43 * 3 - build the rpc reply in an mbuf list
44 * For nfsv4, these functions are called for each Op within the Compound RPC.
48 #include <fs/nfs/nfsport.h>
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset;
55 extern int nfsrv_enable_crossmntpt;
56 #endif /* !APPLEKEXT */
59 * This list defines the GSS mechanisms supported.
60 * (Don't ask me how you get these strings from the RFC stuff like
61 * iso(1), org(3)... but someone did it, so I don't need to know.)
63 static struct nfsgss_mechlist nfsgss_mechlist[] = {
64 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
69 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
70 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
71 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
72 int *diraft_retp, nfsattrbit_t *attrbitp,
73 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
75 static void nfsrvd_mkdirsub(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, NFSACL_T *aclp,
79 NFSPROC_T *p, struct nfsexstuff *exp);
82 * nfs access service (not a part of NFS V2)
85 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
86 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
89 int getret, error = 0;
91 u_int32_t testmode, nfsmode, supported = 0;
95 nfsrv_postopattr(nd, 1, &nva);
98 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
99 nfsmode = fxdr_unsigned(u_int32_t, *tl);
100 if ((nd->nd_flag & ND_NFSV4) &&
101 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
102 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
103 NFSACCESS_EXECUTE))) {
104 nd->nd_repstat = NFSERR_INVAL;
108 if (nfsmode & NFSACCESS_READ) {
109 supported |= NFSACCESS_READ;
110 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
111 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
112 nfsmode &= ~NFSACCESS_READ;
114 if (nfsmode & NFSACCESS_MODIFY) {
115 supported |= NFSACCESS_MODIFY;
116 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
117 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
118 nfsmode &= ~NFSACCESS_MODIFY;
120 if (nfsmode & NFSACCESS_EXTEND) {
121 supported |= NFSACCESS_EXTEND;
122 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
123 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
124 nfsmode &= ~NFSACCESS_EXTEND;
126 if (nfsmode & NFSACCESS_DELETE) {
127 supported |= NFSACCESS_DELETE;
128 if (vp->v_type == VDIR)
129 deletebit = VDELETE_CHILD;
132 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
133 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
134 nfsmode &= ~NFSACCESS_DELETE;
136 if (vnode_vtype(vp) == VDIR)
137 testmode = NFSACCESS_LOOKUP;
139 testmode = NFSACCESS_EXECUTE;
140 if (nfsmode & testmode) {
141 supported |= (nfsmode & testmode);
142 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
143 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
144 nfsmode &= ~testmode;
146 nfsmode &= supported;
147 if (nd->nd_flag & ND_NFSV3) {
148 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
149 nfsrv_postopattr(nd, getret, &nva);
152 if (nd->nd_flag & ND_NFSV4) {
153 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
154 *tl++ = txdr_unsigned(supported);
156 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
157 *tl = txdr_unsigned(nfsmode);
164 NFSEXITCODE2(error, nd);
169 * nfs getattr service
172 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
173 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
177 int at_root = 0, error = 0, supports_nfsv4acls;
178 struct nfsreferral *refp;
179 nfsattrbit_t attrbits, tmpbits;
181 struct vnode *tvp = NULL;
183 uint64_t mounted_on_fileno = 0;
188 if (nd->nd_flag & ND_NFSV4) {
189 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
196 * Check for a referral.
198 refp = nfsv4root_getreferral(vp, NULL, 0);
200 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
205 if (nd->nd_repstat == 0) {
207 NFSSET_ATTRBIT(&tmpbits, &attrbits);
208 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
209 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
210 accmode |= VREAD_ACL;
212 if (NFSNONZERO_ATTRBIT(&tmpbits))
213 accmode |= VREAD_ATTRIBUTES;
215 nd->nd_repstat = nfsvno_accchk(vp, accmode,
216 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
217 NFSACCCHK_VPISLOCKED, NULL);
221 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
222 if (!nd->nd_repstat) {
223 if (nd->nd_flag & ND_NFSV4) {
224 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
225 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
227 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
228 &nva, &attrbits, nd->nd_cred, p);
229 if (nd->nd_repstat == 0) {
230 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
232 if (nfsrv_enable_crossmntpt != 0 &&
233 vp->v_type == VDIR &&
234 (vp->v_vflag & VV_ROOT) != 0 &&
236 tvp = mp->mnt_vnodecovered;
244 if ((nd->nd_repstat =
245 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
246 nd->nd_repstat = VOP_GETATTR(
247 tvp, &va, nd->nd_cred);
251 if (nd->nd_repstat == 0)
252 mounted_on_fileno = (uint64_t)
257 if (nd->nd_repstat == 0)
258 nd->nd_repstat = vfs_busy(mp, 0);
260 if (nd->nd_repstat == 0) {
261 (void)nfsvno_fillattr(nd, mp, vp, &nva,
262 &fh, 0, &attrbits, nd->nd_cred, p,
263 isdgram, 1, supports_nfsv4acls,
264 at_root, mounted_on_fileno);
271 nfsrv_fillattr(nd, &nva);
279 NFSEXITCODE2(error, nd);
284 * nfs setattr service
287 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
288 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
290 struct nfsvattr nva, nva2;
292 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
293 struct timespec guard = { 0, 0 };
294 nfsattrbit_t attrbits, retbits;
295 nfsv4stateid_t stateid;
296 NFSACL_T *aclp = NULL;
298 if (nd->nd_repstat) {
299 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
302 #ifdef NFS4_ACL_EXTATTR_NAME
303 aclp = acl_alloc(M_WAITOK);
306 NFSVNO_ATTRINIT(&nva);
307 NFSZERO_ATTRBIT(&retbits);
308 if (nd->nd_flag & ND_NFSV4) {
309 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
310 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
311 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
313 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
316 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
318 nd->nd_repstat = preat_ret;
319 if (nd->nd_flag & ND_NFSV3) {
320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
321 gcheck = fxdr_unsigned(int, *tl);
323 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
324 fxdr_nfsv3time(tl, &guard);
326 if (!nd->nd_repstat && gcheck &&
327 (nva2.na_ctime.tv_sec != guard.tv_sec ||
328 nva2.na_ctime.tv_nsec != guard.tv_nsec))
329 nd->nd_repstat = NFSERR_NOT_SYNC;
330 if (nd->nd_repstat) {
332 #ifdef NFS4_ACL_EXTATTR_NAME
335 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
338 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
339 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
342 * Now that we have all the fields, lets do it.
343 * If the size is being changed write access is required, otherwise
344 * just check for a read only file system.
346 if (!nd->nd_repstat) {
347 if (NFSVNO_NOTSETSIZE(&nva)) {
348 if (NFSVNO_EXRDONLY(exp) ||
349 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
350 nd->nd_repstat = EROFS;
352 if (vnode_vtype(vp) != VREG)
353 nd->nd_repstat = EINVAL;
354 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
355 NFSVNO_EXSTRICTACCESS(exp))
356 nd->nd_repstat = nfsvno_accchk(vp,
357 VWRITE, nd->nd_cred, exp, p,
358 NFSACCCHK_NOOVERRIDE,
359 NFSACCCHK_VPISLOCKED, NULL);
362 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
363 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
364 &nva, &attrbits, exp, p);
366 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
368 * For V4, try setting the attrbutes in sets, so that the
369 * reply bitmap will be correct for an error case.
371 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
372 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
373 NFSVNO_ATTRINIT(&nva2);
374 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
375 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
376 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
378 if (!nd->nd_repstat) {
379 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
380 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
381 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
382 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
385 if (!nd->nd_repstat &&
386 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
387 NFSVNO_ATTRINIT(&nva2);
388 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
389 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
392 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
394 if (!nd->nd_repstat &&
395 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
396 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
397 NFSVNO_ATTRINIT(&nva2);
398 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
399 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
400 if (nva.na_vaflags & VA_UTIMES_NULL) {
401 nva2.na_vaflags |= VA_UTIMES_NULL;
402 NFSVNO_SETACTIVE(&nva2, vaflags);
404 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
406 if (!nd->nd_repstat) {
407 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
408 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
409 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
410 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
413 if (!nd->nd_repstat &&
414 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
415 NFSVNO_ATTRINIT(&nva2);
416 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
417 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
420 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
423 #ifdef NFS4_ACL_EXTATTR_NAME
424 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
425 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
426 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
428 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
431 } else if (!nd->nd_repstat) {
432 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
435 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
436 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
438 nd->nd_repstat = postat_ret;
441 #ifdef NFS4_ACL_EXTATTR_NAME
444 if (nd->nd_flag & ND_NFSV3)
445 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
446 else if (nd->nd_flag & ND_NFSV4)
447 (void) nfsrv_putattrbit(nd, &retbits);
448 else if (!nd->nd_repstat)
449 nfsrv_fillattr(nd, &nva);
456 #ifdef NFS4_ACL_EXTATTR_NAME
459 if (nd->nd_flag & ND_NFSV4) {
461 * For all nd_repstat, the V4 reply includes a bitmap,
462 * even NFSERR_BADXDR, which is what this will end up
465 (void) nfsrv_putattrbit(nd, &retbits);
467 NFSEXITCODE2(error, nd);
473 * (Also performs lookup parent for v4)
476 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
477 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
478 struct nfsexstuff *exp)
480 struct nameidata named;
481 vnode_t vp, dirp = NULL;
482 int error = 0, dattr_ret = 1;
483 struct nfsvattr nva, dattr;
487 if (nd->nd_repstat) {
488 nfsrv_postopattr(nd, dattr_ret, &dattr);
493 * For some reason, if dp is a symlink, the error
494 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
496 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
497 nd->nd_repstat = NFSERR_SYMLINK;
502 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
503 LOCKLEAF | SAVESTART);
504 nfsvno_setpathbuf(&named, &bufp, &hashp);
505 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
508 nfsvno_relpathbuf(&named);
511 if (!nd->nd_repstat) {
512 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
515 nfsvno_relpathbuf(&named);
517 if (nd->nd_repstat) {
519 if (nd->nd_flag & ND_NFSV3)
520 dattr_ret = nfsvno_getattr(dirp, &dattr,
524 if (nd->nd_flag & ND_NFSV3)
525 nfsrv_postopattr(nd, dattr_ret, &dattr);
528 if (named.ni_startdir)
529 vrele(named.ni_startdir);
530 nfsvno_relpathbuf(&named);
532 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
533 vp->v_type != VDIR && vp->v_type != VLNK)
535 * Only allow lookup of VDIR and VLNK for traversal of
536 * non-exported volumes during NFSv4 mounting.
538 nd->nd_repstat = ENOENT;
539 if (nd->nd_repstat == 0)
540 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
541 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
542 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
543 if (vpp != NULL && nd->nd_repstat == 0)
548 if (nd->nd_flag & ND_NFSV3)
549 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
553 if (nd->nd_repstat) {
554 if (nd->nd_flag & ND_NFSV3)
555 nfsrv_postopattr(nd, dattr_ret, &dattr);
558 if (nd->nd_flag & ND_NFSV2) {
559 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
560 nfsrv_fillattr(nd, &nva);
561 } else if (nd->nd_flag & ND_NFSV3) {
562 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
563 nfsrv_postopattr(nd, 0, &nva);
564 nfsrv_postopattr(nd, dattr_ret, &dattr);
568 NFSEXITCODE2(error, nd);
573 * nfs readlink service
576 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
577 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
580 mbuf_t mp = NULL, mpend = NULL;
584 if (nd->nd_repstat) {
585 nfsrv_postopattr(nd, getret, &nva);
588 if (vnode_vtype(vp) != VLNK) {
589 if (nd->nd_flag & ND_NFSV2)
590 nd->nd_repstat = ENXIO;
592 nd->nd_repstat = EINVAL;
595 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
597 if (nd->nd_flag & ND_NFSV3)
598 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
600 if (nd->nd_flag & ND_NFSV3)
601 nfsrv_postopattr(nd, getret, &nva);
604 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
605 *tl = txdr_unsigned(len);
606 mbuf_setnext(nd->nd_mb, mp);
608 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
619 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
620 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
623 int error = 0, cnt, getret = 1, reqlen, eof = 0;
627 struct nfsstate st, *stp = &st;
628 struct nfslock lo, *lop = &lo;
629 nfsv4stateid_t stateid;
632 if (nd->nd_repstat) {
633 nfsrv_postopattr(nd, getret, &nva);
636 if (nd->nd_flag & ND_NFSV2) {
637 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
638 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
639 reqlen = fxdr_unsigned(int, *tl);
640 } else if (nd->nd_flag & ND_NFSV3) {
641 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
642 off = fxdr_hyper(tl);
644 reqlen = fxdr_unsigned(int, *tl);
646 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
647 reqlen = fxdr_unsigned(int, *(tl + 6));
649 if (reqlen > NFS_SRVMAXDATA(nd)) {
650 reqlen = NFS_SRVMAXDATA(nd);
651 } else if (reqlen < 0) {
655 if (nd->nd_flag & ND_NFSV4) {
656 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
657 lop->lo_flags = NFSLCK_READ;
658 stp->ls_ownerlen = 0;
660 stp->ls_uid = nd->nd_cred->cr_uid;
661 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
662 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
663 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
664 if (nd->nd_flag & ND_IMPLIEDCLID) {
665 if (nd->nd_clientid.qval != clientid.qval)
666 printf("EEK! multiple clids\n");
668 nd->nd_flag |= ND_IMPLIEDCLID;
669 nd->nd_clientid.qval = clientid.qval;
671 stp->ls_stateid.other[2] = *tl++;
672 off = fxdr_hyper(tl);
675 lop->lo_end = off + reqlen;
677 * Paranoia, just in case it wraps around.
679 if (lop->lo_end < off)
680 lop->lo_end = NFS64BITSSET;
682 if (vnode_vtype(vp) != VREG) {
683 if (nd->nd_flag & ND_NFSV3)
684 nd->nd_repstat = EINVAL;
686 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
689 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
691 nd->nd_repstat = getret;
692 if (!nd->nd_repstat &&
693 (nva.na_uid != nd->nd_cred->cr_uid ||
694 NFSVNO_EXSTRICTACCESS(exp))) {
695 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
697 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
699 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
700 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
701 NFSACCCHK_VPISLOCKED, NULL);
703 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
704 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
705 &stateid, exp, nd, p);
706 if (nd->nd_repstat) {
708 if (nd->nd_flag & ND_NFSV3)
709 nfsrv_postopattr(nd, getret, &nva);
712 if (off >= nva.na_size) {
715 } else if (reqlen == 0)
717 else if ((off + reqlen) >= nva.na_size) {
718 cnt = nva.na_size - off;
724 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
726 if (!(nd->nd_flag & ND_NFSV4)) {
727 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
729 nd->nd_repstat = getret;
731 if (nd->nd_repstat) {
735 if (nd->nd_flag & ND_NFSV3)
736 nfsrv_postopattr(nd, getret, &nva);
741 if (nd->nd_flag & ND_NFSV2) {
742 nfsrv_fillattr(nd, &nva);
743 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
745 if (nd->nd_flag & ND_NFSV3) {
746 nfsrv_postopattr(nd, getret, &nva);
747 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
748 *tl++ = txdr_unsigned(cnt);
750 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
754 *tl++ = newnfs_false;
756 *tl = txdr_unsigned(cnt);
758 mbuf_setnext(nd->nd_mb, m3);
760 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
768 NFSEXITCODE2(error, nd);
776 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
777 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
782 struct nfsvattr nva, forat;
783 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
784 int stable = NFSWRITE_FILESYNC;
786 struct nfsstate st, *stp = &st;
787 struct nfslock lo, *lop = &lo;
788 nfsv4stateid_t stateid;
791 if (nd->nd_repstat) {
792 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
795 if (nd->nd_flag & ND_NFSV2) {
796 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
797 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
799 retlen = len = fxdr_unsigned(int32_t, *tl);
800 } else if (nd->nd_flag & ND_NFSV3) {
801 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
802 off = fxdr_hyper(tl);
804 stable = fxdr_unsigned(int, *tl++);
805 retlen = len = fxdr_unsigned(int32_t, *tl);
807 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
808 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
809 lop->lo_flags = NFSLCK_WRITE;
810 stp->ls_ownerlen = 0;
812 stp->ls_uid = nd->nd_cred->cr_uid;
813 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
814 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
815 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
816 if (nd->nd_flag & ND_IMPLIEDCLID) {
817 if (nd->nd_clientid.qval != clientid.qval)
818 printf("EEK! multiple clids\n");
820 nd->nd_flag |= ND_IMPLIEDCLID;
821 nd->nd_clientid.qval = clientid.qval;
823 stp->ls_stateid.other[2] = *tl++;
824 off = fxdr_hyper(tl);
827 stable = fxdr_unsigned(int, *tl++);
828 retlen = len = fxdr_unsigned(int32_t, *tl);
829 lop->lo_end = off + len;
831 * Paranoia, just in case it wraps around, which shouldn't
832 * ever happen anyhow.
834 if (lop->lo_end < lop->lo_first)
835 lop->lo_end = NFS64BITSSET;
839 * Loop through the mbuf chain, counting how many mbufs are a
840 * part of this write operation, so the iovec size is known.
844 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
860 if (retlen > NFS_MAXDATA || retlen < 0)
861 nd->nd_repstat = EIO;
862 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
863 if (nd->nd_flag & ND_NFSV3)
864 nd->nd_repstat = EINVAL;
866 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
869 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
871 nd->nd_repstat = forat_ret;
872 if (!nd->nd_repstat &&
873 (forat.na_uid != nd->nd_cred->cr_uid ||
874 NFSVNO_EXSTRICTACCESS(exp)))
875 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
877 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
878 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
879 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
880 &stateid, exp, nd, p);
882 if (nd->nd_repstat) {
884 if (nd->nd_flag & ND_NFSV3)
885 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
890 * For NFS Version 2, it is not obvious what a write of zero length
891 * should do, but I might as well be consistent with Version 3,
892 * which is to return ok so long as there are no permission problems.
895 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
896 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
897 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
899 panic("nfsrv_write mbuf");
901 if (nd->nd_flag & ND_NFSV4)
904 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
907 nd->nd_repstat = aftat_ret;
908 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
909 if (nd->nd_flag & ND_NFSV3)
910 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
913 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
914 *tl++ = txdr_unsigned(retlen);
915 if (stable == NFSWRITE_UNSTABLE)
916 *tl++ = txdr_unsigned(stable);
918 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
920 * Actually, there is no need to txdr these fields,
921 * but it may make the values more human readable,
922 * for debugging purposes.
924 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
925 *tl = txdr_unsigned(nfsboottime.tv_usec);
926 } else if (!nd->nd_repstat)
927 nfsrv_fillattr(nd, &nva);
934 NFSEXITCODE2(error, nd);
939 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
940 * now does a truncate to 0 length via. setattr if it already exists
941 * The core creation routine has been extracted out into nfsrv_creatsub(),
942 * so it can also be used by nfsrv_open() for V4.
945 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
946 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
948 struct nfsvattr nva, dirfor, diraft;
949 struct nfsv2_sattr *sp;
950 struct nameidata named;
952 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
953 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
955 vnode_t vp = NULL, dirp = NULL;
960 int32_t cverf[2], tverf[2] = { 0, 0 };
962 if (nd->nd_repstat) {
963 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
966 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
967 LOCKPARENT | LOCKLEAF | SAVESTART);
968 nfsvno_setpathbuf(&named, &bufp, &hashp);
969 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
972 if (!nd->nd_repstat) {
973 NFSVNO_ATTRINIT(&nva);
974 if (nd->nd_flag & ND_NFSV2) {
975 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
976 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
979 NFSVNO_SETATTRVAL(&nva, type, vtyp);
980 NFSVNO_SETATTRVAL(&nva, mode,
981 nfstov_mode(sp->sa_mode));
982 switch (nva.na_type) {
984 tsize = fxdr_unsigned(int32_t, sp->sa_size);
986 NFSVNO_SETATTRVAL(&nva, size,
992 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
998 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
999 how = fxdr_unsigned(int, *tl);
1001 case NFSCREATE_GUARDED:
1002 case NFSCREATE_UNCHECKED:
1003 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1007 case NFSCREATE_EXCLUSIVE:
1008 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1014 NFSVNO_SETATTRVAL(&nva, type, VREG);
1017 if (nd->nd_repstat) {
1018 nfsvno_relpathbuf(&named);
1019 if (nd->nd_flag & ND_NFSV3) {
1020 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1022 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1029 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1031 if (nd->nd_flag & ND_NFSV2) {
1035 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1039 if (nd->nd_repstat) {
1040 if (nd->nd_flag & ND_NFSV3)
1041 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1048 if (!(nd->nd_flag & ND_NFSV2)) {
1050 case NFSCREATE_GUARDED:
1052 nd->nd_repstat = EEXIST;
1054 case NFSCREATE_UNCHECKED:
1056 case NFSCREATE_EXCLUSIVE:
1057 if (named.ni_vp == NULL)
1058 NFSVNO_SETATTRVAL(&nva, mode, 0);
1064 * Iff doesn't exist, create it
1065 * otherwise just truncate to 0 length
1066 * should I set the mode too ?
1068 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1069 &exclusive_flag, cverf, rdev, p, exp);
1071 if (!nd->nd_repstat) {
1072 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1073 if (!nd->nd_repstat)
1074 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1077 if (!nd->nd_repstat) {
1078 tverf[0] = nva.na_atime.tv_sec;
1079 tverf[1] = nva.na_atime.tv_nsec;
1082 if (nd->nd_flag & ND_NFSV2) {
1083 if (!nd->nd_repstat) {
1084 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1085 nfsrv_fillattr(nd, &nva);
1088 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1089 || cverf[1] != tverf[1]))
1090 nd->nd_repstat = EEXIST;
1091 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1093 if (!nd->nd_repstat) {
1094 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1095 nfsrv_postopattr(nd, 0, &nva);
1097 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1101 NFSEXITCODE2(0, nd);
1105 nfsvno_relpathbuf(&named);
1106 NFSEXITCODE2(error, nd);
1111 * nfs v3 mknod service (and v4 create)
1114 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1115 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1116 struct nfsexstuff *exp)
1118 struct nfsvattr nva, dirfor, diraft;
1120 struct nameidata named;
1121 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1122 u_int32_t major, minor;
1123 enum vtype vtyp = VNON;
1124 nfstype nfs4type = NFNON;
1125 vnode_t vp, dirp = NULL;
1126 nfsattrbit_t attrbits;
1127 char *bufp = NULL, *pathcp = NULL;
1128 u_long *hashp, cnflags;
1129 NFSACL_T *aclp = NULL;
1131 NFSVNO_ATTRINIT(&nva);
1132 cnflags = (LOCKPARENT | SAVESTART);
1133 if (nd->nd_repstat) {
1134 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1137 #ifdef NFS4_ACL_EXTATTR_NAME
1138 aclp = acl_alloc(M_WAITOK);
1143 * For V4, the creation stuff is here, Yuck!
1145 if (nd->nd_flag & ND_NFSV4) {
1146 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1147 vtyp = nfsv34tov_type(*tl);
1148 nfs4type = fxdr_unsigned(nfstype, *tl);
1151 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1158 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1159 major = fxdr_unsigned(u_int32_t, *tl++);
1160 minor = fxdr_unsigned(u_int32_t, *tl);
1161 nva.na_rdev = NFSMAKEDEV(major, minor);
1167 cnflags = (LOCKPARENT | SAVENAME);
1170 nd->nd_repstat = NFSERR_BADTYPE;
1172 #ifdef NFS4_ACL_EXTATTR_NAME
1178 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1179 nfsvno_setpathbuf(&named, &bufp, &hashp);
1180 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1183 if (!nd->nd_repstat) {
1184 if (nd->nd_flag & ND_NFSV3) {
1185 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1186 vtyp = nfsv34tov_type(*tl);
1188 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1192 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1193 (vtyp == VCHR || vtyp == VBLK)) {
1194 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1195 major = fxdr_unsigned(u_int32_t, *tl++);
1196 minor = fxdr_unsigned(u_int32_t, *tl);
1197 nva.na_rdev = NFSMAKEDEV(major, minor);
1201 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1202 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1203 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1204 dirfor.na_gid == nva.na_gid)
1205 NFSVNO_UNSET(&nva, gid);
1206 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1208 if (nd->nd_repstat) {
1210 #ifdef NFS4_ACL_EXTATTR_NAME
1213 nfsvno_relpathbuf(&named);
1215 FREE(pathcp, M_TEMP);
1216 if (nd->nd_flag & ND_NFSV3)
1217 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1223 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1224 * in va_mode, so we'll have to set a default here.
1226 if (NFSVNO_NOTSETMODE(&nva)) {
1234 named.ni_cnd.cn_flags |= WILLBEDIR;
1235 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1236 if (nd->nd_repstat) {
1238 if (nd->nd_flag & ND_NFSV3)
1239 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1243 #ifdef NFS4_ACL_EXTATTR_NAME
1246 if (nd->nd_flag & ND_NFSV3)
1247 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1252 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1254 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1256 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1257 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1259 #ifdef NFS4_ACL_EXTATTR_NAME
1263 } else if (vtyp == VLNK) {
1264 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1265 &dirfor, &diraft, &diraft_ret, &attrbits,
1266 aclp, p, exp, pathcp, pathlen);
1267 #ifdef NFS4_ACL_EXTATTR_NAME
1270 FREE(pathcp, M_TEMP);
1275 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1276 if (!nd->nd_repstat) {
1278 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1279 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1280 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1281 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1283 if (vpp != NULL && nd->nd_repstat == 0) {
1284 NFSVOPUNLOCK(vp, 0);
1290 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1292 if (!nd->nd_repstat) {
1293 if (nd->nd_flag & ND_NFSV3) {
1294 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1295 nfsrv_postopattr(nd, 0, &nva);
1297 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1298 *tl++ = newnfs_false;
1299 txdr_hyper(dirfor.na_filerev, tl);
1301 txdr_hyper(diraft.na_filerev, tl);
1302 (void) nfsrv_putattrbit(nd, &attrbits);
1305 if (nd->nd_flag & ND_NFSV3)
1306 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1307 #ifdef NFS4_ACL_EXTATTR_NAME
1312 NFSEXITCODE2(0, nd);
1316 #ifdef NFS4_ACL_EXTATTR_NAME
1320 nfsvno_relpathbuf(&named);
1322 FREE(pathcp, M_TEMP);
1324 NFSEXITCODE2(error, nd);
1329 * nfs remove service
1332 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1333 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1335 struct nameidata named;
1337 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1338 vnode_t dirp = NULL;
1339 struct nfsvattr dirfor, diraft;
1343 if (nd->nd_repstat) {
1344 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1347 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1348 LOCKPARENT | LOCKLEAF);
1349 nfsvno_setpathbuf(&named, &bufp, &hashp);
1350 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1353 nfsvno_relpathbuf(&named);
1356 if (!nd->nd_repstat) {
1357 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1360 nfsvno_relpathbuf(&named);
1363 if (!(nd->nd_flag & ND_NFSV2)) {
1364 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1371 if (!nd->nd_repstat) {
1372 if (nd->nd_flag & ND_NFSV4) {
1373 if (vnode_vtype(named.ni_vp) == VDIR)
1374 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1375 nd->nd_cred, p, exp);
1377 nd->nd_repstat = nfsvno_removesub(&named, 1,
1378 nd->nd_cred, p, exp);
1379 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1380 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1381 nd->nd_cred, p, exp);
1383 nd->nd_repstat = nfsvno_removesub(&named, 0,
1384 nd->nd_cred, p, exp);
1387 if (!(nd->nd_flag & ND_NFSV2)) {
1389 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1393 if (nd->nd_flag & ND_NFSV3) {
1394 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1396 } else if (!nd->nd_repstat) {
1397 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1398 *tl++ = newnfs_false;
1399 txdr_hyper(dirfor.na_filerev, tl);
1401 txdr_hyper(diraft.na_filerev, tl);
1406 NFSEXITCODE2(error, nd);
1411 * nfs rename service
1414 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1415 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1416 struct nfsexstuff *toexp)
1419 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1420 int tdirfor_ret = 1, tdiraft_ret = 1;
1421 struct nameidata fromnd, tond;
1422 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1423 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1424 struct nfsexstuff tnes;
1426 char *bufp, *tbufp = NULL;
1430 if (nd->nd_repstat) {
1431 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1432 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1435 if (!(nd->nd_flag & ND_NFSV2))
1436 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1437 tond.ni_cnd.cn_nameiop = 0;
1438 tond.ni_startdir = NULL;
1439 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1440 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1441 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1446 nfsvno_relpathbuf(&fromnd);
1450 * Unlock dp in this code section, so it is unlocked before
1451 * tdp gets locked. This avoids a potential LOR if tdp is the
1452 * parent directory of dp.
1454 if (nd->nd_flag & ND_NFSV4) {
1458 NFSVOPUNLOCK(dp, 0);
1459 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1460 p, 0); /* Might lock tdp. */
1462 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1464 NFSVOPUNLOCK(dp, 0);
1467 tfh.nfsrvfh_len = 0;
1468 error = nfsrv_mtofh(nd, &tfh);
1470 error = nfsvno_getfh(dp, &fh, p);
1473 /* todp is always NULL except NFSv4 */
1474 nfsvno_relpathbuf(&fromnd);
1478 /* If this is the same file handle, just VREF() the vnode. */
1479 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1480 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1484 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1486 NFSVOPUNLOCK(dp, 0);
1488 NFSVOPUNLOCK(dp, 0);
1489 nd->nd_cred->cr_uid = nd->nd_saveduid;
1490 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1491 0, p); /* Locks tdp. */
1493 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1495 NFSVOPUNLOCK(tdp, 0);
1499 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1500 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1501 if (!nd->nd_repstat) {
1502 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1507 nfsvno_relpathbuf(&fromnd);
1508 nfsvno_relpathbuf(&tond);
1512 if (nd->nd_repstat) {
1513 if (nd->nd_flag & ND_NFSV3) {
1514 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1516 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1522 nfsvno_relpathbuf(&fromnd);
1523 nfsvno_relpathbuf(&tond);
1528 * Done parsing, now down to business.
1530 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1531 if (nd->nd_repstat) {
1532 if (nd->nd_flag & ND_NFSV3) {
1533 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1535 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1542 nfsvno_relpathbuf(&tond);
1545 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1546 tond.ni_cnd.cn_flags |= WILLBEDIR;
1547 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1548 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1549 nd->nd_flag, nd->nd_cred, p);
1551 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1554 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1560 if (nd->nd_flag & ND_NFSV3) {
1561 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1562 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1563 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1564 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1565 *tl++ = newnfs_false;
1566 txdr_hyper(fdirfor.na_filerev, tl);
1568 txdr_hyper(fdiraft.na_filerev, tl);
1570 *tl++ = newnfs_false;
1571 txdr_hyper(tdirfor.na_filerev, tl);
1573 txdr_hyper(tdiraft.na_filerev, tl);
1577 NFSEXITCODE2(error, nd);
1585 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1586 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1587 struct nfsexstuff *toexp)
1589 struct nameidata named;
1591 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1592 vnode_t dirp = NULL, dp = NULL;
1593 struct nfsvattr dirfor, diraft, at;
1594 struct nfsexstuff tnes;
1599 if (nd->nd_repstat) {
1600 nfsrv_postopattr(nd, getret, &at);
1601 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1604 NFSVOPUNLOCK(vp, 0);
1605 if (vnode_vtype(vp) == VDIR) {
1606 if (nd->nd_flag & ND_NFSV4)
1607 nd->nd_repstat = NFSERR_ISDIR;
1609 nd->nd_repstat = NFSERR_INVAL;
1612 } else if (vnode_vtype(vp) == VLNK) {
1613 if (nd->nd_flag & ND_NFSV2)
1614 nd->nd_repstat = NFSERR_INVAL;
1616 nd->nd_repstat = NFSERR_NOTSUPP;
1620 if (!nd->nd_repstat) {
1621 if (nd->nd_flag & ND_NFSV4) {
1625 error = nfsrv_mtofh(nd, &dfh);
1628 /* tovp is always NULL unless NFSv4 */
1631 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1634 NFSVOPUNLOCK(dp, 0);
1637 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1638 LOCKPARENT | SAVENAME);
1639 if (!nd->nd_repstat) {
1640 nfsvno_setpathbuf(&named, &bufp, &hashp);
1641 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1646 nfsvno_relpathbuf(&named);
1649 if (!nd->nd_repstat) {
1650 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1655 nfsvno_relpathbuf(&named);
1659 if (nd->nd_flag & ND_NFSV2) {
1663 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1667 if (!nd->nd_repstat)
1668 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1669 if (nd->nd_flag & ND_NFSV3)
1670 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1672 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1676 if (nd->nd_flag & ND_NFSV3) {
1677 nfsrv_postopattr(nd, getret, &at);
1678 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1679 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1680 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1681 *tl++ = newnfs_false;
1682 txdr_hyper(dirfor.na_filerev, tl);
1684 txdr_hyper(diraft.na_filerev, tl);
1688 NFSEXITCODE2(error, nd);
1693 * nfs symbolic link service
1696 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1697 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1698 struct nfsexstuff *exp)
1700 struct nfsvattr nva, dirfor, diraft;
1701 struct nameidata named;
1702 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1703 vnode_t dirp = NULL;
1704 char *bufp, *pathcp = NULL;
1707 if (nd->nd_repstat) {
1708 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1713 NFSVNO_ATTRINIT(&nva);
1714 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1715 LOCKPARENT | SAVESTART);
1716 nfsvno_setpathbuf(&named, &bufp, &hashp);
1717 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1718 if (!error && !nd->nd_repstat)
1719 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1722 nfsvno_relpathbuf(&named);
1725 if (!nd->nd_repstat) {
1726 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1729 nfsvno_relpathbuf(&named);
1731 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1737 * And call nfsrvd_symlinksub() to do the common code. It will
1738 * return EBADRPC upon a parsing error, 0 otherwise.
1740 if (!nd->nd_repstat) {
1742 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1744 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1745 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1747 } else if (dirp != NULL) {
1748 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1752 FREE(pathcp, M_TEMP);
1754 if (nd->nd_flag & ND_NFSV3) {
1755 if (!nd->nd_repstat) {
1756 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1757 nfsrv_postopattr(nd, 0, &nva);
1759 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1763 NFSEXITCODE2(error, nd);
1768 * Common code for creating a symbolic link.
1771 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1772 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1773 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1774 int *diraft_retp, nfsattrbit_t *attrbitp,
1775 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1780 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1781 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1782 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1783 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1784 if (nd->nd_flag & ND_NFSV3) {
1785 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1786 if (!nd->nd_repstat)
1787 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1788 nvap, nd->nd_cred, p, 1);
1790 if (vpp != NULL && nd->nd_repstat == 0) {
1791 NFSVOPUNLOCK(ndp->ni_vp, 0);
1797 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1800 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1801 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1802 *tl++ = newnfs_false;
1803 txdr_hyper(dirforp->na_filerev, tl);
1805 txdr_hyper(diraftp->na_filerev, tl);
1806 (void) nfsrv_putattrbit(nd, attrbitp);
1809 NFSEXITCODE2(0, nd);
1816 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1817 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1818 struct nfsexstuff *exp)
1820 struct nfsvattr nva, dirfor, diraft;
1821 struct nameidata named;
1823 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1824 vnode_t dirp = NULL;
1828 if (nd->nd_repstat) {
1829 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1832 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1833 LOCKPARENT | SAVENAME);
1834 nfsvno_setpathbuf(&named, &bufp, &hashp);
1835 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1838 if (!nd->nd_repstat) {
1839 NFSVNO_ATTRINIT(&nva);
1840 if (nd->nd_flag & ND_NFSV3) {
1841 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1845 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1846 nva.na_mode = nfstov_mode(*tl++);
1849 if (!nd->nd_repstat) {
1850 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1853 nfsvno_relpathbuf(&named);
1855 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1859 if (nd->nd_repstat) {
1861 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1865 if (nd->nd_flag & ND_NFSV3)
1866 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1871 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1874 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1876 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1877 &diraft_ret, NULL, NULL, p, exp);
1879 if (nd->nd_flag & ND_NFSV3) {
1880 if (!nd->nd_repstat) {
1881 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1882 nfsrv_postopattr(nd, 0, &nva);
1884 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1885 } else if (!nd->nd_repstat) {
1886 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1887 nfsrv_fillattr(nd, &nva);
1891 NFSEXITCODE2(0, nd);
1895 nfsvno_relpathbuf(&named);
1896 NFSEXITCODE2(error, nd);
1901 * Code common to mkdir for V2,3 and 4.
1904 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1905 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1906 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1907 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1908 NFSPROC_T *p, struct nfsexstuff *exp)
1913 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1914 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1915 nd->nd_cred, p, exp);
1916 if (!nd->nd_repstat) {
1918 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1919 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1920 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1921 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1923 if (vpp && !nd->nd_repstat) {
1924 NFSVOPUNLOCK(vp, 0);
1931 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1934 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1935 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1936 *tl++ = newnfs_false;
1937 txdr_hyper(dirforp->na_filerev, tl);
1939 txdr_hyper(diraftp->na_filerev, tl);
1940 (void) nfsrv_putattrbit(nd, attrbitp);
1943 NFSEXITCODE2(0, nd);
1947 * nfs commit service
1950 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1951 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1953 struct nfsvattr bfor, aft;
1955 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1958 if (nd->nd_repstat) {
1959 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1962 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1964 * XXX At this time VOP_FSYNC() does not accept offset and byte
1965 * count parameters, so these arguments are useless (someday maybe).
1967 off = fxdr_hyper(tl);
1969 cnt = fxdr_unsigned(int, *tl);
1970 if (nd->nd_flag & ND_NFSV3)
1971 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1972 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1973 if (nd->nd_flag & ND_NFSV3) {
1974 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1975 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1978 if (!nd->nd_repstat) {
1979 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1980 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1981 *tl = txdr_unsigned(nfsboottime.tv_usec);
1985 NFSEXITCODE2(0, nd);
1989 NFSEXITCODE2(error, nd);
1994 * nfs statfs service
1997 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1998 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2007 if (nd->nd_repstat) {
2008 nfsrv_postopattr(nd, getret, &at);
2012 nd->nd_repstat = nfsvno_statfs(vp, sf);
2013 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2015 if (nd->nd_flag & ND_NFSV3)
2016 nfsrv_postopattr(nd, getret, &at);
2019 if (nd->nd_flag & ND_NFSV2) {
2020 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2021 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2022 *tl++ = txdr_unsigned(sf->f_bsize);
2023 *tl++ = txdr_unsigned(sf->f_blocks);
2024 *tl++ = txdr_unsigned(sf->f_bfree);
2025 *tl = txdr_unsigned(sf->f_bavail);
2027 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2028 tval = (u_quad_t)sf->f_blocks;
2029 tval *= (u_quad_t)sf->f_bsize;
2030 txdr_hyper(tval, tl); tl += 2;
2031 tval = (u_quad_t)sf->f_bfree;
2032 tval *= (u_quad_t)sf->f_bsize;
2033 txdr_hyper(tval, tl); tl += 2;
2034 tval = (u_quad_t)sf->f_bavail;
2035 tval *= (u_quad_t)sf->f_bsize;
2036 txdr_hyper(tval, tl); tl += 2;
2037 tval = (u_quad_t)sf->f_files;
2038 txdr_hyper(tval, tl); tl += 2;
2039 tval = (u_quad_t)sf->f_ffree;
2040 txdr_hyper(tval, tl); tl += 2;
2041 tval = (u_quad_t)sf->f_ffree;
2042 txdr_hyper(tval, tl); tl += 2;
2047 NFSEXITCODE2(0, nd);
2052 * nfs fsinfo service
2055 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2056 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2059 struct nfsfsinfo fs;
2063 if (nd->nd_repstat) {
2064 nfsrv_postopattr(nd, getret, &at);
2067 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2068 nfsvno_getfs(&fs, isdgram);
2070 nfsrv_postopattr(nd, getret, &at);
2071 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2072 *tl++ = txdr_unsigned(fs.fs_rtmax);
2073 *tl++ = txdr_unsigned(fs.fs_rtpref);
2074 *tl++ = txdr_unsigned(fs.fs_rtmult);
2075 *tl++ = txdr_unsigned(fs.fs_wtmax);
2076 *tl++ = txdr_unsigned(fs.fs_wtpref);
2077 *tl++ = txdr_unsigned(fs.fs_wtmult);
2078 *tl++ = txdr_unsigned(fs.fs_dtpref);
2079 txdr_hyper(fs.fs_maxfilesize, tl);
2081 txdr_nfsv3time(&fs.fs_timedelta, tl);
2083 *tl = txdr_unsigned(fs.fs_properties);
2086 NFSEXITCODE2(0, nd);
2091 * nfs pathconf service
2094 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2095 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2097 struct nfsv3_pathconf *pc;
2099 register_t linkmax, namemax, chownres, notrunc;
2102 if (nd->nd_repstat) {
2103 nfsrv_postopattr(nd, getret, &at);
2106 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2108 if (!nd->nd_repstat)
2109 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2111 if (!nd->nd_repstat)
2112 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2113 &chownres, nd->nd_cred, p);
2114 if (!nd->nd_repstat)
2115 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2117 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2119 nfsrv_postopattr(nd, getret, &at);
2120 if (!nd->nd_repstat) {
2121 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2122 pc->pc_linkmax = txdr_unsigned(linkmax);
2123 pc->pc_namemax = txdr_unsigned(namemax);
2124 pc->pc_notrunc = txdr_unsigned(notrunc);
2125 pc->pc_chownrestricted = txdr_unsigned(chownres);
2128 * These should probably be supported by VOP_PATHCONF(), but
2129 * until msdosfs is exportable (why would you want to?), the
2130 * Unix defaults should be ok.
2132 pc->pc_caseinsensitive = newnfs_false;
2133 pc->pc_casepreserving = newnfs_true;
2137 NFSEXITCODE2(0, nd);
2142 * nfsv4 lock service
2145 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2146 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2150 struct nfsstate *stp = NULL;
2151 struct nfslock *lop;
2152 struct nfslockconflict cf;
2154 u_short flags = NFSLCK_LOCK, lflags;
2155 u_int64_t offset, len;
2156 nfsv4stateid_t stateid;
2159 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2160 i = fxdr_unsigned(int, *tl++);
2162 case NFSV4LOCKT_READW:
2163 flags |= NFSLCK_BLOCKING;
2164 case NFSV4LOCKT_READ:
2165 lflags = NFSLCK_READ;
2167 case NFSV4LOCKT_WRITEW:
2168 flags |= NFSLCK_BLOCKING;
2169 case NFSV4LOCKT_WRITE:
2170 lflags = NFSLCK_WRITE;
2173 nd->nd_repstat = NFSERR_BADXDR;
2176 if (*tl++ == newnfs_true)
2177 flags |= NFSLCK_RECLAIM;
2178 offset = fxdr_hyper(tl);
2180 len = fxdr_hyper(tl);
2182 if (*tl == newnfs_true)
2183 flags |= NFSLCK_OPENTOLOCK;
2184 if (flags & NFSLCK_OPENTOLOCK) {
2185 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2186 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2187 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2188 nd->nd_repstat = NFSERR_BADXDR;
2191 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2192 M_NFSDSTATE, M_WAITOK);
2193 stp->ls_ownerlen = i;
2194 stp->ls_op = nd->nd_rp;
2195 stp->ls_seq = fxdr_unsigned(int, *tl++);
2196 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2197 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2199 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2200 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2201 clientid.lval[0] = *tl++;
2202 clientid.lval[1] = *tl++;
2203 if (nd->nd_flag & ND_IMPLIEDCLID) {
2204 if (nd->nd_clientid.qval != clientid.qval)
2205 printf("EEK! multiple clids\n");
2207 nd->nd_flag |= ND_IMPLIEDCLID;
2208 nd->nd_clientid.qval = clientid.qval;
2210 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2214 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2215 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2216 M_NFSDSTATE, M_WAITOK);
2217 stp->ls_ownerlen = 0;
2218 stp->ls_op = nd->nd_rp;
2219 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2220 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2222 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2223 stp->ls_seq = fxdr_unsigned(int, *tl);
2224 clientid.lval[0] = stp->ls_stateid.other[0];
2225 clientid.lval[1] = stp->ls_stateid.other[1];
2226 if (nd->nd_flag & ND_IMPLIEDCLID) {
2227 if (nd->nd_clientid.qval != clientid.qval)
2228 printf("EEK! multiple clids\n");
2230 nd->nd_flag |= ND_IMPLIEDCLID;
2231 nd->nd_clientid.qval = clientid.qval;
2234 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2235 M_NFSDLOCK, M_WAITOK);
2236 lop->lo_first = offset;
2237 if (len == NFS64BITSSET) {
2238 lop->lo_end = NFS64BITSSET;
2240 lop->lo_end = offset + len;
2241 if (lop->lo_end <= lop->lo_first)
2242 nd->nd_repstat = NFSERR_INVAL;
2244 lop->lo_flags = lflags;
2245 stp->ls_flags = flags;
2246 stp->ls_uid = nd->nd_cred->cr_uid;
2249 * Do basic access checking.
2251 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2252 if (vnode_vtype(vp) == VDIR)
2253 nd->nd_repstat = NFSERR_ISDIR;
2255 nd->nd_repstat = NFSERR_INVAL;
2257 if (!nd->nd_repstat) {
2258 if (lflags & NFSLCK_WRITE) {
2259 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2260 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2261 NFSACCCHK_VPISLOCKED, NULL);
2263 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2264 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2265 NFSACCCHK_VPISLOCKED, NULL);
2267 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2268 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2269 NFSACCCHK_VPISLOCKED, NULL);
2274 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2275 * seqid# gets updated. nfsrv_lockctrl() will return the value
2276 * of nd_repstat, if it gets that far.
2278 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2279 &stateid, exp, nd, p);
2281 FREE((caddr_t)lop, M_NFSDLOCK);
2283 FREE((caddr_t)stp, M_NFSDSTATE);
2284 if (!nd->nd_repstat) {
2285 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2286 *tl++ = txdr_unsigned(stateid.seqid);
2287 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2288 } else if (nd->nd_repstat == NFSERR_DENIED) {
2289 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2290 txdr_hyper(cf.cl_first, tl);
2292 if (cf.cl_end == NFS64BITSSET)
2295 len = cf.cl_end - cf.cl_first;
2296 txdr_hyper(len, tl);
2298 if (cf.cl_flags == NFSLCK_WRITE)
2299 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2301 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2302 *tl++ = stateid.other[0];
2303 *tl = stateid.other[1];
2304 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2307 NFSEXITCODE2(0, nd);
2312 free((caddr_t)stp, M_NFSDSTATE);
2313 NFSEXITCODE2(error, nd);
2318 * nfsv4 lock test service
2321 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2322 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2326 struct nfsstate *stp = NULL;
2327 struct nfslock lo, *lop = &lo;
2328 struct nfslockconflict cf;
2330 nfsv4stateid_t stateid;
2334 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2335 i = fxdr_unsigned(int, *(tl + 7));
2336 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2337 nd->nd_repstat = NFSERR_BADXDR;
2340 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2341 M_NFSDSTATE, M_WAITOK);
2342 stp->ls_ownerlen = i;
2344 stp->ls_flags = NFSLCK_TEST;
2345 stp->ls_uid = nd->nd_cred->cr_uid;
2346 i = fxdr_unsigned(int, *tl++);
2348 case NFSV4LOCKT_READW:
2349 stp->ls_flags |= NFSLCK_BLOCKING;
2350 case NFSV4LOCKT_READ:
2351 lo.lo_flags = NFSLCK_READ;
2353 case NFSV4LOCKT_WRITEW:
2354 stp->ls_flags |= NFSLCK_BLOCKING;
2355 case NFSV4LOCKT_WRITE:
2356 lo.lo_flags = NFSLCK_WRITE;
2359 nd->nd_repstat = NFSERR_BADXDR;
2362 lo.lo_first = fxdr_hyper(tl);
2364 len = fxdr_hyper(tl);
2365 if (len == NFS64BITSSET) {
2366 lo.lo_end = NFS64BITSSET;
2368 lo.lo_end = lo.lo_first + len;
2369 if (lo.lo_end <= lo.lo_first)
2370 nd->nd_repstat = NFSERR_INVAL;
2373 clientid.lval[0] = *tl++;
2374 clientid.lval[1] = *tl;
2375 if (nd->nd_flag & ND_IMPLIEDCLID) {
2376 if (nd->nd_clientid.qval != clientid.qval)
2377 printf("EEK! multiple clids\n");
2379 nd->nd_flag |= ND_IMPLIEDCLID;
2380 nd->nd_clientid.qval = clientid.qval;
2382 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2385 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2386 if (vnode_vtype(vp) == VDIR)
2387 nd->nd_repstat = NFSERR_ISDIR;
2389 nd->nd_repstat = NFSERR_INVAL;
2391 if (!nd->nd_repstat)
2392 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2393 &stateid, exp, nd, p);
2395 FREE((caddr_t)stp, M_NFSDSTATE);
2396 if (nd->nd_repstat) {
2397 if (nd->nd_repstat == NFSERR_DENIED) {
2398 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2399 txdr_hyper(cf.cl_first, tl);
2401 if (cf.cl_end == NFS64BITSSET)
2404 len = cf.cl_end - cf.cl_first;
2405 txdr_hyper(len, tl);
2407 if (cf.cl_flags == NFSLCK_WRITE)
2408 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2410 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2411 *tl++ = stp->ls_stateid.other[0];
2412 *tl = stp->ls_stateid.other[1];
2413 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2417 NFSEXITCODE2(0, nd);
2422 free((caddr_t)stp, M_NFSDSTATE);
2423 NFSEXITCODE2(error, nd);
2428 * nfsv4 unlock service
2431 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2432 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2436 struct nfsstate *stp;
2437 struct nfslock *lop;
2439 nfsv4stateid_t stateid;
2443 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2444 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2445 M_NFSDSTATE, M_WAITOK);
2446 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2447 M_NFSDLOCK, M_WAITOK);
2448 stp->ls_flags = NFSLCK_UNLOCK;
2449 lop->lo_flags = NFSLCK_UNLOCK;
2450 stp->ls_op = nd->nd_rp;
2451 i = fxdr_unsigned(int, *tl++);
2453 case NFSV4LOCKT_READW:
2454 stp->ls_flags |= NFSLCK_BLOCKING;
2455 case NFSV4LOCKT_READ:
2457 case NFSV4LOCKT_WRITEW:
2458 stp->ls_flags |= NFSLCK_BLOCKING;
2459 case NFSV4LOCKT_WRITE:
2462 nd->nd_repstat = NFSERR_BADXDR;
2463 free(stp, M_NFSDSTATE);
2464 free(lop, M_NFSDLOCK);
2467 stp->ls_ownerlen = 0;
2468 stp->ls_uid = nd->nd_cred->cr_uid;
2469 stp->ls_seq = fxdr_unsigned(int, *tl++);
2470 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2471 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2473 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2474 lop->lo_first = fxdr_hyper(tl);
2476 len = fxdr_hyper(tl);
2477 if (len == NFS64BITSSET) {
2478 lop->lo_end = NFS64BITSSET;
2480 lop->lo_end = lop->lo_first + len;
2481 if (lop->lo_end <= lop->lo_first)
2482 nd->nd_repstat = NFSERR_INVAL;
2484 clientid.lval[0] = stp->ls_stateid.other[0];
2485 clientid.lval[1] = stp->ls_stateid.other[1];
2486 if (nd->nd_flag & ND_IMPLIEDCLID) {
2487 if (nd->nd_clientid.qval != clientid.qval)
2488 printf("EEK! multiple clids\n");
2490 nd->nd_flag |= ND_IMPLIEDCLID;
2491 nd->nd_clientid.qval = clientid.qval;
2493 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2494 if (vnode_vtype(vp) == VDIR)
2495 nd->nd_repstat = NFSERR_ISDIR;
2497 nd->nd_repstat = NFSERR_INVAL;
2500 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2501 * seqid# gets incremented. nfsrv_lockctrl() will return the
2502 * value of nd_repstat, if it gets that far.
2504 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2505 &stateid, exp, nd, p);
2507 FREE((caddr_t)stp, M_NFSDSTATE);
2509 free((caddr_t)lop, M_NFSDLOCK);
2510 if (!nd->nd_repstat) {
2511 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2512 *tl++ = txdr_unsigned(stateid.seqid);
2513 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2517 NFSEXITCODE2(error, nd);
2522 * nfsv4 open service
2525 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2526 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2527 struct nfsexstuff *exp)
2531 struct nfsstate *stp = NULL;
2532 int error = 0, create, claim, exclusive_flag = 0;
2533 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2534 int how = NFSCREATE_UNCHECKED;
2535 int32_t cverf[2], tverf[2] = { 0, 0 };
2536 vnode_t vp = NULL, dirp = NULL;
2537 struct nfsvattr nva, dirfor, diraft;
2538 struct nameidata named;
2539 nfsv4stateid_t stateid, delegstateid;
2540 nfsattrbit_t attrbits;
2544 NFSACL_T *aclp = NULL;
2546 #ifdef NFS4_ACL_EXTATTR_NAME
2547 aclp = acl_alloc(M_WAITOK);
2550 NFSZERO_ATTRBIT(&attrbits);
2551 named.ni_startdir = NULL;
2552 named.ni_cnd.cn_nameiop = 0;
2553 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2554 i = fxdr_unsigned(int, *(tl + 5));
2555 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2556 nd->nd_repstat = NFSERR_BADXDR;
2559 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2560 M_NFSDSTATE, M_WAITOK);
2561 stp->ls_ownerlen = i;
2562 stp->ls_op = nd->nd_rp;
2563 stp->ls_flags = NFSLCK_OPEN;
2564 stp->ls_uid = nd->nd_cred->cr_uid;
2565 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2566 i = fxdr_unsigned(int, *tl++);
2568 case NFSV4OPEN_ACCESSREAD:
2569 stp->ls_flags |= NFSLCK_READACCESS;
2571 case NFSV4OPEN_ACCESSWRITE:
2572 stp->ls_flags |= NFSLCK_WRITEACCESS;
2574 case NFSV4OPEN_ACCESSBOTH:
2575 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2578 nd->nd_repstat = NFSERR_INVAL;
2580 i = fxdr_unsigned(int, *tl++);
2582 case NFSV4OPEN_DENYNONE:
2584 case NFSV4OPEN_DENYREAD:
2585 stp->ls_flags |= NFSLCK_READDENY;
2587 case NFSV4OPEN_DENYWRITE:
2588 stp->ls_flags |= NFSLCK_WRITEDENY;
2590 case NFSV4OPEN_DENYBOTH:
2591 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2594 nd->nd_repstat = NFSERR_INVAL;
2596 clientid.lval[0] = *tl++;
2597 clientid.lval[1] = *tl;
2598 if (nd->nd_flag & ND_IMPLIEDCLID) {
2599 if (nd->nd_clientid.qval != clientid.qval)
2600 printf("EEK! multiple clids\n");
2602 nd->nd_flag |= ND_IMPLIEDCLID;
2603 nd->nd_clientid.qval = clientid.qval;
2605 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2608 NFSVNO_ATTRINIT(&nva);
2609 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2610 create = fxdr_unsigned(int, *tl);
2611 if (!nd->nd_repstat)
2612 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2613 if (create == NFSV4OPEN_CREATE) {
2616 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2617 how = fxdr_unsigned(int, *tl);
2619 case NFSCREATE_UNCHECKED:
2620 case NFSCREATE_GUARDED:
2621 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2625 * If the na_gid being set is the same as that of
2626 * the directory it is going in, clear it, since
2627 * that is what will be set by default. This allows
2628 * a user that isn't in that group to do the create.
2630 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2631 nva.na_gid == dirfor.na_gid)
2632 NFSVNO_UNSET(&nva, gid);
2633 if (!nd->nd_repstat)
2634 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2636 case NFSCREATE_EXCLUSIVE:
2637 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2642 nd->nd_repstat = NFSERR_BADXDR;
2645 } else if (create != NFSV4OPEN_NOCREATE) {
2646 nd->nd_repstat = NFSERR_BADXDR;
2651 * Now, handle the claim, which usually includes looking up a
2652 * name in the directory referenced by dp. The exception is
2653 * NFSV4OPEN_CLAIMPREVIOUS.
2655 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2656 claim = fxdr_unsigned(int, *tl);
2657 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2658 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2659 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2660 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2661 stp->ls_flags |= NFSLCK_DELEGCUR;
2662 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2663 stp->ls_flags |= NFSLCK_DELEGPREV;
2665 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2666 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2667 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2668 claim != NFSV4OPEN_CLAIMNULL)
2669 nd->nd_repstat = NFSERR_INVAL;
2670 if (nd->nd_repstat) {
2671 nd->nd_repstat = nfsrv_opencheck(clientid,
2672 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2675 if (create == NFSV4OPEN_CREATE)
2676 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2677 LOCKPARENT | LOCKLEAF | SAVESTART);
2679 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2680 LOCKLEAF | SAVESTART);
2681 nfsvno_setpathbuf(&named, &bufp, &hashp);
2682 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2685 #ifdef NFS4_ACL_EXTATTR_NAME
2688 FREE((caddr_t)stp, M_NFSDSTATE);
2689 nfsvno_relpathbuf(&named);
2690 NFSEXITCODE2(error, nd);
2693 if (!nd->nd_repstat) {
2694 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2698 nfsvno_relpathbuf(&named);
2700 if (create == NFSV4OPEN_CREATE) {
2702 case NFSCREATE_UNCHECKED:
2705 * Clear the setable attribute bits, except
2706 * for Size, if it is being truncated.
2708 NFSZERO_ATTRBIT(&attrbits);
2709 if (NFSVNO_ISSETSIZE(&nva))
2710 NFSSETBIT_ATTRBIT(&attrbits,
2714 case NFSCREATE_GUARDED:
2715 if (named.ni_vp && !nd->nd_repstat)
2716 nd->nd_repstat = EEXIST;
2718 case NFSCREATE_EXCLUSIVE:
2724 nfsvno_open(nd, &named, clientid, &stateid, stp,
2725 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2726 nd->nd_cred, p, exp, &vp);
2727 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2729 i = fxdr_unsigned(int, *tl);
2731 case NFSV4OPEN_DELEGATEREAD:
2732 stp->ls_flags |= NFSLCK_DELEGREAD;
2734 case NFSV4OPEN_DELEGATEWRITE:
2735 stp->ls_flags |= NFSLCK_DELEGWRITE;
2736 case NFSV4OPEN_DELEGATENONE:
2739 nd->nd_repstat = NFSERR_BADXDR;
2742 stp->ls_flags |= NFSLCK_RECLAIM;
2744 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2745 if ((vp->v_iflag & VI_DOOMED) == 0)
2746 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2747 stp, vp, nd, p, nd->nd_repstat);
2749 nd->nd_repstat = NFSERR_PERM;
2751 nd->nd_repstat = NFSERR_BADXDR;
2756 * Do basic access checking.
2758 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2760 * The IETF working group decided that this is the correct
2761 * error return for all non-regular files.
2763 nd->nd_repstat = NFSERR_SYMLINK;
2765 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2766 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2767 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2768 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2769 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2770 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2772 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2773 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2774 NFSACCCHK_VPISLOCKED, NULL);
2777 if (!nd->nd_repstat) {
2778 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2779 if (!nd->nd_repstat) {
2780 tverf[0] = nva.na_atime.tv_sec;
2781 tverf[1] = nva.na_atime.tv_nsec;
2784 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2785 cverf[1] != tverf[1]))
2786 nd->nd_repstat = EEXIST;
2788 * Do the open locking/delegation stuff.
2790 if (!nd->nd_repstat)
2791 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2792 &delegstateid, &rflags, exp, p, nva.na_filerev);
2795 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2796 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2797 * (ie: Leave the NFSVOPUNLOCK() about here.)
2800 NFSVOPUNLOCK(vp, 0);
2802 FREE((caddr_t)stp, M_NFSDSTATE);
2803 if (!nd->nd_repstat && dirp)
2804 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2806 if (!nd->nd_repstat) {
2807 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2808 *tl++ = txdr_unsigned(stateid.seqid);
2809 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2810 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2811 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2812 *tl++ = newnfs_true;
2818 *tl++ = newnfs_false; /* Since dirp is not locked */
2819 txdr_hyper(dirfor.na_filerev, tl);
2821 txdr_hyper(diraft.na_filerev, tl);
2824 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2825 (void) nfsrv_putattrbit(nd, &attrbits);
2826 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2827 if (rflags & NFSV4OPEN_READDELEGATE)
2828 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2829 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2830 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2832 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2833 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2834 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2835 *tl++ = txdr_unsigned(delegstateid.seqid);
2836 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2838 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2839 if (rflags & NFSV4OPEN_RECALL)
2843 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2844 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2845 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2846 txdr_hyper(nva.na_size, tl);
2848 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2849 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2850 *tl++ = txdr_unsigned(0x0);
2851 acemask = NFSV4ACE_ALLFILESMASK;
2852 if (nva.na_mode & S_IRUSR)
2853 acemask |= NFSV4ACE_READMASK;
2854 if (nva.na_mode & S_IWUSR)
2855 acemask |= NFSV4ACE_WRITEMASK;
2856 if (nva.na_mode & S_IXUSR)
2857 acemask |= NFSV4ACE_EXECUTEMASK;
2858 *tl = txdr_unsigned(acemask);
2859 (void) nfsm_strtom(nd, "OWNER@", 6);
2867 #ifdef NFS4_ACL_EXTATTR_NAME
2870 NFSEXITCODE2(0, nd);
2874 #ifdef NFS4_ACL_EXTATTR_NAME
2878 FREE((caddr_t)stp, M_NFSDSTATE);
2879 NFSEXITCODE2(error, nd);
2884 * nfsv4 close service
2887 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2888 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2891 struct nfsstate st, *stp = &st;
2893 nfsv4stateid_t stateid;
2896 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2897 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2898 stp->ls_ownerlen = 0;
2899 stp->ls_op = nd->nd_rp;
2900 stp->ls_uid = nd->nd_cred->cr_uid;
2901 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2902 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2904 stp->ls_flags = NFSLCK_CLOSE;
2905 clientid.lval[0] = stp->ls_stateid.other[0];
2906 clientid.lval[1] = stp->ls_stateid.other[1];
2907 if (nd->nd_flag & ND_IMPLIEDCLID) {
2908 if (nd->nd_clientid.qval != clientid.qval)
2909 printf("EEK! multiple clids\n");
2911 nd->nd_flag |= ND_IMPLIEDCLID;
2912 nd->nd_clientid.qval = clientid.qval;
2914 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2916 if (!nd->nd_repstat) {
2917 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2918 *tl++ = txdr_unsigned(stateid.seqid);
2919 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2921 NFSEXITCODE2(0, nd);
2925 NFSEXITCODE2(error, nd);
2930 * nfsv4 delegpurge service
2933 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2934 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2940 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2941 nd->nd_repstat = NFSERR_WRONGSEC;
2944 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2945 clientid.lval[0] = *tl++;
2946 clientid.lval[1] = *tl;
2947 if (nd->nd_flag & ND_IMPLIEDCLID) {
2948 if (nd->nd_clientid.qval != clientid.qval)
2949 printf("EEK! multiple clids\n");
2951 nd->nd_flag |= ND_IMPLIEDCLID;
2952 nd->nd_clientid.qval = clientid.qval;
2954 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2955 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2957 NFSEXITCODE2(error, nd);
2962 * nfsv4 delegreturn service
2965 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2966 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2970 nfsv4stateid_t stateid;
2973 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2974 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2975 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2976 clientid.lval[0] = stateid.other[0];
2977 clientid.lval[1] = stateid.other[1];
2978 if (nd->nd_flag & ND_IMPLIEDCLID) {
2979 if (nd->nd_clientid.qval != clientid.qval)
2980 printf("EEK! multiple clids\n");
2982 nd->nd_flag |= ND_IMPLIEDCLID;
2983 nd->nd_clientid.qval = clientid.qval;
2985 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2986 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2989 NFSEXITCODE2(error, nd);
2994 * nfsv4 get file handle service
2997 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2998 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3002 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3004 if (!nd->nd_repstat)
3005 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3006 NFSEXITCODE2(0, nd);
3011 * nfsv4 open confirm service
3014 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3015 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3018 struct nfsstate st, *stp = &st;
3020 nfsv4stateid_t stateid;
3023 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3024 stp->ls_ownerlen = 0;
3025 stp->ls_op = nd->nd_rp;
3026 stp->ls_uid = nd->nd_cred->cr_uid;
3027 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3028 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3030 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3031 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3032 stp->ls_flags = NFSLCK_CONFIRM;
3033 clientid.lval[0] = stp->ls_stateid.other[0];
3034 clientid.lval[1] = stp->ls_stateid.other[1];
3035 if (nd->nd_flag & ND_IMPLIEDCLID) {
3036 if (nd->nd_clientid.qval != clientid.qval)
3037 printf("EEK! multiple clids\n");
3039 nd->nd_flag |= ND_IMPLIEDCLID;
3040 nd->nd_clientid.qval = clientid.qval;
3042 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3043 if (!nd->nd_repstat) {
3044 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3045 *tl++ = txdr_unsigned(stateid.seqid);
3046 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3050 NFSEXITCODE2(error, nd);
3055 * nfsv4 open downgrade service
3058 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3059 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3063 struct nfsstate st, *stp = &st;
3065 nfsv4stateid_t stateid;
3068 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3069 stp->ls_ownerlen = 0;
3070 stp->ls_op = nd->nd_rp;
3071 stp->ls_uid = nd->nd_cred->cr_uid;
3072 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3073 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3075 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3076 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3077 i = fxdr_unsigned(int, *tl++);
3079 case NFSV4OPEN_ACCESSREAD:
3080 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3082 case NFSV4OPEN_ACCESSWRITE:
3083 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3085 case NFSV4OPEN_ACCESSBOTH:
3086 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3090 nd->nd_repstat = NFSERR_BADXDR;
3092 i = fxdr_unsigned(int, *tl);
3094 case NFSV4OPEN_DENYNONE:
3096 case NFSV4OPEN_DENYREAD:
3097 stp->ls_flags |= NFSLCK_READDENY;
3099 case NFSV4OPEN_DENYWRITE:
3100 stp->ls_flags |= NFSLCK_WRITEDENY;
3102 case NFSV4OPEN_DENYBOTH:
3103 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3106 nd->nd_repstat = NFSERR_BADXDR;
3109 clientid.lval[0] = stp->ls_stateid.other[0];
3110 clientid.lval[1] = stp->ls_stateid.other[1];
3111 if (nd->nd_flag & ND_IMPLIEDCLID) {
3112 if (nd->nd_clientid.qval != clientid.qval)
3113 printf("EEK! multiple clids\n");
3115 nd->nd_flag |= ND_IMPLIEDCLID;
3116 nd->nd_clientid.qval = clientid.qval;
3118 if (!nd->nd_repstat)
3119 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3121 if (!nd->nd_repstat) {
3122 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3123 *tl++ = txdr_unsigned(stateid.seqid);
3124 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3128 NFSEXITCODE2(error, nd);
3133 * nfsv4 renew lease service
3136 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3137 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3143 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3144 nd->nd_repstat = NFSERR_WRONGSEC;
3147 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3148 clientid.lval[0] = *tl++;
3149 clientid.lval[1] = *tl;
3150 if (nd->nd_flag & ND_IMPLIEDCLID) {
3151 if (nd->nd_clientid.qval != clientid.qval)
3152 printf("EEK! multiple clids\n");
3154 nd->nd_flag |= ND_IMPLIEDCLID;
3155 nd->nd_clientid.qval = clientid.qval;
3157 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3158 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3160 NFSEXITCODE2(error, nd);
3165 * nfsv4 security info service
3168 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3169 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3173 struct nameidata named;
3174 vnode_t dirp = NULL, vp;
3176 struct nfsexstuff retnes;
3178 int error = 0, savflag, i;
3183 * All this just to get the export flags for the name.
3185 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3186 LOCKLEAF | SAVESTART);
3187 nfsvno_setpathbuf(&named, &bufp, &hashp);
3188 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3191 nfsvno_relpathbuf(&named);
3194 if (!nd->nd_repstat) {
3195 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3198 nfsvno_relpathbuf(&named);
3204 vrele(named.ni_startdir);
3205 nfsvno_relpathbuf(&named);
3206 fh.nfsrvfh_len = NFSX_MYFH;
3208 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3210 savflag = nd->nd_flag;
3211 if (!nd->nd_repstat) {
3212 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3216 nd->nd_flag = savflag;
3221 * Finally have the export flags for name, so we can create
3222 * the security info.
3225 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3226 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3227 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3229 *tl = txdr_unsigned(RPCAUTH_UNIX);
3231 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3233 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3234 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3235 nfsgss_mechlist[KERBV_MECH].len);
3236 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3237 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3238 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3240 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3241 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3242 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3243 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3244 nfsgss_mechlist[KERBV_MECH].len);
3245 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3246 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3247 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3249 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3250 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3251 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3252 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3253 nfsgss_mechlist[KERBV_MECH].len);
3254 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3255 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3256 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3260 *sizp = txdr_unsigned(len);
3263 NFSEXITCODE2(error, nd);
3268 * nfsv4 set client id service
3271 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3272 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3276 int error = 0, idlen;
3277 struct nfsclient *clp = NULL;
3278 struct sockaddr_in *rad;
3279 u_char *verf, *ucp, *ucp2, addrbuf[24];
3280 nfsquad_t clientid, confirm;
3282 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3283 nd->nd_repstat = NFSERR_WRONGSEC;
3286 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3287 verf = (u_char *)tl;
3288 tl += (NFSX_VERF / NFSX_UNSIGNED);
3289 i = fxdr_unsigned(int, *tl);
3290 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3291 nd->nd_repstat = NFSERR_BADXDR;
3295 if (nd->nd_flag & ND_GSS)
3296 i += nd->nd_princlen;
3297 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3298 M_NFSDCLIENT, M_WAITOK);
3299 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3300 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3301 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3302 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3303 clp->lc_req.nr_cred = NULL;
3304 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3305 clp->lc_idlen = idlen;
3306 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3309 if (nd->nd_flag & ND_GSS) {
3310 clp->lc_flags = LCL_GSS;
3311 if (nd->nd_flag & ND_GSSINTEGRITY)
3312 clp->lc_flags |= LCL_GSSINTEGRITY;
3313 else if (nd->nd_flag & ND_GSSPRIVACY)
3314 clp->lc_flags |= LCL_GSSPRIVACY;
3318 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3319 clp->lc_flags |= LCL_NAME;
3320 clp->lc_namelen = nd->nd_princlen;
3321 clp->lc_name = &clp->lc_id[idlen];
3322 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3324 clp->lc_uid = nd->nd_cred->cr_uid;
3325 clp->lc_gid = nd->nd_cred->cr_gid;
3327 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3328 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3329 error = nfsrv_getclientipaddr(nd, clp);
3332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3333 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3336 * nfsrv_setclient() does the actual work of adding it to the
3337 * client list. If there is no error, the structure has been
3338 * linked into the client list and clp should no longer be used
3339 * here. When an error is returned, it has not been linked in,
3340 * so it should be free'd.
3342 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3343 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3344 if (clp->lc_flags & LCL_TCPCALLBACK)
3345 (void) nfsm_strtom(nd, "tcp", 3);
3347 (void) nfsm_strtom(nd, "udp", 3);
3348 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3349 ucp = (u_char *)&rad->sin_addr.s_addr;
3350 ucp2 = (u_char *)&rad->sin_port;
3351 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3352 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3353 ucp2[0] & 0xff, ucp2[1] & 0xff);
3354 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3357 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3358 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3359 free((caddr_t)clp, M_NFSDCLIENT);
3361 if (!nd->nd_repstat) {
3362 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3363 *tl++ = clientid.lval[0];
3364 *tl++ = clientid.lval[1];
3365 *tl++ = confirm.lval[0];
3366 *tl = confirm.lval[1];
3370 NFSEXITCODE2(0, nd);
3374 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3375 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3376 free((caddr_t)clp, M_NFSDCLIENT);
3378 NFSEXITCODE2(error, nd);
3383 * nfsv4 set client id confirm service
3386 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3387 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3388 __unused struct nfsexstuff *exp)
3392 nfsquad_t clientid, confirm;
3394 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3395 nd->nd_repstat = NFSERR_WRONGSEC;
3398 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3399 clientid.lval[0] = *tl++;
3400 clientid.lval[1] = *tl++;
3401 confirm.lval[0] = *tl++;
3402 confirm.lval[1] = *tl;
3405 * nfsrv_getclient() searches the client list for a match and
3406 * returns the appropriate NFSERR status.
3408 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3409 NULL, confirm, nd, p);
3411 NFSEXITCODE2(error, nd);
3416 * nfsv4 verify service
3419 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3420 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3422 int error = 0, ret, fhsize = NFSX_MYFH;
3423 struct nfsvattr nva;
3425 struct nfsfsinfo fs;
3428 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3429 if (!nd->nd_repstat)
3430 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3431 if (!nd->nd_repstat)
3432 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3433 if (!nd->nd_repstat) {
3434 nfsvno_getfs(&fs, isdgram);
3435 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3436 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3438 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3440 nd->nd_repstat = NFSERR_SAME;
3441 else if (ret != NFSERR_NOTSAME)
3442 nd->nd_repstat = ret;
3444 nd->nd_repstat = ret;
3448 NFSEXITCODE2(error, nd);
3456 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3457 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3458 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3461 int error = 0, createdir;
3463 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3464 createdir = fxdr_unsigned(int, *tl);
3465 nd->nd_repstat = NFSERR_NOTSUPP;
3468 NFSEXITCODE2(error, nd);
3473 * nfsv4 release lock owner service
3476 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3477 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3480 struct nfsstate *stp = NULL;
3484 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3485 nd->nd_repstat = NFSERR_WRONGSEC;
3488 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3489 len = fxdr_unsigned(int, *(tl + 2));
3490 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3491 nd->nd_repstat = NFSERR_BADXDR;
3494 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3495 M_NFSDSTATE, M_WAITOK);
3496 stp->ls_ownerlen = len;
3498 stp->ls_flags = NFSLCK_RELEASE;
3499 stp->ls_uid = nd->nd_cred->cr_uid;
3500 clientid.lval[0] = *tl++;
3501 clientid.lval[1] = *tl;
3502 if (nd->nd_flag & ND_IMPLIEDCLID) {
3503 if (nd->nd_clientid.qval != clientid.qval)
3504 printf("EEK! multiple clids\n");
3506 nd->nd_flag |= ND_IMPLIEDCLID;
3507 nd->nd_clientid.qval = clientid.qval;
3509 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3512 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3513 FREE((caddr_t)stp, M_NFSDSTATE);
3515 NFSEXITCODE2(0, nd);
3519 free((caddr_t)stp, M_NFSDSTATE);
3520 NFSEXITCODE2(error, nd);