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);
1449 if (nd->nd_flag & ND_NFSV4) {
1452 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1454 tfh.nfsrvfh_len = 0;
1455 error = nfsrv_mtofh(nd, &tfh);
1457 error = nfsvno_getfh(dp, &fh, p);
1460 /* todp is always NULL except NFSv4 */
1461 nfsvno_relpathbuf(&fromnd);
1465 /* If this is the same file handle, just VREF() the vnode. */
1466 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1467 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1471 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1474 nd->nd_cred->cr_uid = nd->nd_saveduid;
1475 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1478 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1480 NFSVOPUNLOCK(tdp, 0);
1484 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1485 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1486 if (!nd->nd_repstat) {
1487 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1492 nfsvno_relpathbuf(&fromnd);
1493 nfsvno_relpathbuf(&tond);
1497 if (nd->nd_repstat) {
1498 if (nd->nd_flag & ND_NFSV3) {
1499 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1501 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1507 nfsvno_relpathbuf(&fromnd);
1508 nfsvno_relpathbuf(&tond);
1513 * Done parsing, now down to business.
1515 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1516 if (nd->nd_repstat) {
1517 if (nd->nd_flag & ND_NFSV3) {
1518 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1520 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1527 nfsvno_relpathbuf(&tond);
1530 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1531 tond.ni_cnd.cn_flags |= WILLBEDIR;
1532 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1533 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1534 nd->nd_flag, nd->nd_cred, p);
1536 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1539 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1545 if (nd->nd_flag & ND_NFSV3) {
1546 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1547 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1548 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1549 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1550 *tl++ = newnfs_false;
1551 txdr_hyper(fdirfor.na_filerev, tl);
1553 txdr_hyper(fdiraft.na_filerev, tl);
1555 *tl++ = newnfs_false;
1556 txdr_hyper(tdirfor.na_filerev, tl);
1558 txdr_hyper(tdiraft.na_filerev, tl);
1562 NFSEXITCODE2(error, nd);
1570 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1571 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1572 struct nfsexstuff *toexp)
1574 struct nameidata named;
1576 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1577 vnode_t dirp = NULL, dp = NULL;
1578 struct nfsvattr dirfor, diraft, at;
1579 struct nfsexstuff tnes;
1584 if (nd->nd_repstat) {
1585 nfsrv_postopattr(nd, getret, &at);
1586 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1589 NFSVOPUNLOCK(vp, 0);
1590 if (vnode_vtype(vp) == VDIR) {
1591 if (nd->nd_flag & ND_NFSV4)
1592 nd->nd_repstat = NFSERR_ISDIR;
1594 nd->nd_repstat = NFSERR_INVAL;
1597 } else if (vnode_vtype(vp) == VLNK) {
1598 if (nd->nd_flag & ND_NFSV2)
1599 nd->nd_repstat = NFSERR_INVAL;
1601 nd->nd_repstat = NFSERR_NOTSUPP;
1605 if (!nd->nd_repstat) {
1606 if (nd->nd_flag & ND_NFSV4) {
1610 error = nfsrv_mtofh(nd, &dfh);
1613 /* tovp is always NULL unless NFSv4 */
1616 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1619 NFSVOPUNLOCK(dp, 0);
1622 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1623 LOCKPARENT | SAVENAME);
1624 if (!nd->nd_repstat) {
1625 nfsvno_setpathbuf(&named, &bufp, &hashp);
1626 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1631 nfsvno_relpathbuf(&named);
1634 if (!nd->nd_repstat) {
1635 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1640 nfsvno_relpathbuf(&named);
1644 if (nd->nd_flag & ND_NFSV2) {
1648 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1652 if (!nd->nd_repstat)
1653 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1654 if (nd->nd_flag & ND_NFSV3)
1655 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1657 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1661 if (nd->nd_flag & ND_NFSV3) {
1662 nfsrv_postopattr(nd, getret, &at);
1663 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1664 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1665 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1666 *tl++ = newnfs_false;
1667 txdr_hyper(dirfor.na_filerev, tl);
1669 txdr_hyper(diraft.na_filerev, tl);
1673 NFSEXITCODE2(error, nd);
1678 * nfs symbolic link service
1681 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1682 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1683 struct nfsexstuff *exp)
1685 struct nfsvattr nva, dirfor, diraft;
1686 struct nameidata named;
1687 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1688 vnode_t dirp = NULL;
1689 char *bufp, *pathcp = NULL;
1692 if (nd->nd_repstat) {
1693 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1698 NFSVNO_ATTRINIT(&nva);
1699 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1700 LOCKPARENT | SAVESTART);
1701 nfsvno_setpathbuf(&named, &bufp, &hashp);
1702 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1703 if (!error && !nd->nd_repstat)
1704 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1707 nfsvno_relpathbuf(&named);
1710 if (!nd->nd_repstat) {
1711 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1714 nfsvno_relpathbuf(&named);
1716 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1722 * And call nfsrvd_symlinksub() to do the common code. It will
1723 * return EBADRPC upon a parsing error, 0 otherwise.
1725 if (!nd->nd_repstat) {
1727 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1729 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1730 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1732 } else if (dirp != NULL) {
1733 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1737 FREE(pathcp, M_TEMP);
1739 if (nd->nd_flag & ND_NFSV3) {
1740 if (!nd->nd_repstat) {
1741 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1742 nfsrv_postopattr(nd, 0, &nva);
1744 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1748 NFSEXITCODE2(error, nd);
1753 * Common code for creating a symbolic link.
1756 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1757 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1758 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1759 int *diraft_retp, nfsattrbit_t *attrbitp,
1760 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1765 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1766 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1767 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1768 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1769 if (nd->nd_flag & ND_NFSV3) {
1770 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1771 if (!nd->nd_repstat)
1772 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1773 nvap, nd->nd_cred, p, 1);
1775 if (vpp != NULL && nd->nd_repstat == 0) {
1776 NFSVOPUNLOCK(ndp->ni_vp, 0);
1782 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1785 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1786 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1787 *tl++ = newnfs_false;
1788 txdr_hyper(dirforp->na_filerev, tl);
1790 txdr_hyper(diraftp->na_filerev, tl);
1791 (void) nfsrv_putattrbit(nd, attrbitp);
1794 NFSEXITCODE2(0, nd);
1801 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1802 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1803 struct nfsexstuff *exp)
1805 struct nfsvattr nva, dirfor, diraft;
1806 struct nameidata named;
1808 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1809 vnode_t dirp = NULL;
1813 if (nd->nd_repstat) {
1814 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1817 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1818 LOCKPARENT | SAVENAME);
1819 nfsvno_setpathbuf(&named, &bufp, &hashp);
1820 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1823 if (!nd->nd_repstat) {
1824 NFSVNO_ATTRINIT(&nva);
1825 if (nd->nd_flag & ND_NFSV3) {
1826 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1830 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1831 nva.na_mode = nfstov_mode(*tl++);
1834 if (!nd->nd_repstat) {
1835 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1838 nfsvno_relpathbuf(&named);
1840 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1844 if (nd->nd_repstat) {
1846 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1850 if (nd->nd_flag & ND_NFSV3)
1851 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1856 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1859 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1861 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1862 &diraft_ret, NULL, NULL, p, exp);
1864 if (nd->nd_flag & ND_NFSV3) {
1865 if (!nd->nd_repstat) {
1866 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1867 nfsrv_postopattr(nd, 0, &nva);
1869 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1870 } else if (!nd->nd_repstat) {
1871 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1872 nfsrv_fillattr(nd, &nva);
1876 NFSEXITCODE2(0, nd);
1880 nfsvno_relpathbuf(&named);
1881 NFSEXITCODE2(error, nd);
1886 * Code common to mkdir for V2,3 and 4.
1889 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1890 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1891 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1892 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1893 NFSPROC_T *p, struct nfsexstuff *exp)
1898 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1899 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1900 nd->nd_cred, p, exp);
1901 if (!nd->nd_repstat) {
1903 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1904 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1905 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1906 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1908 if (vpp && !nd->nd_repstat) {
1909 NFSVOPUNLOCK(vp, 0);
1916 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1919 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1920 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1921 *tl++ = newnfs_false;
1922 txdr_hyper(dirforp->na_filerev, tl);
1924 txdr_hyper(diraftp->na_filerev, tl);
1925 (void) nfsrv_putattrbit(nd, attrbitp);
1928 NFSEXITCODE2(0, nd);
1932 * nfs commit service
1935 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1936 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1938 struct nfsvattr bfor, aft;
1940 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1943 if (nd->nd_repstat) {
1944 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1947 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1949 * XXX At this time VOP_FSYNC() does not accept offset and byte
1950 * count parameters, so these arguments are useless (someday maybe).
1952 off = fxdr_hyper(tl);
1954 cnt = fxdr_unsigned(int, *tl);
1955 if (nd->nd_flag & ND_NFSV3)
1956 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1957 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1958 if (nd->nd_flag & ND_NFSV3) {
1959 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1960 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1963 if (!nd->nd_repstat) {
1964 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1965 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1966 *tl = txdr_unsigned(nfsboottime.tv_usec);
1970 NFSEXITCODE2(0, nd);
1974 NFSEXITCODE2(error, nd);
1979 * nfs statfs service
1982 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1983 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1992 if (nd->nd_repstat) {
1993 nfsrv_postopattr(nd, getret, &at);
1997 nd->nd_repstat = nfsvno_statfs(vp, sf);
1998 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2000 if (nd->nd_flag & ND_NFSV3)
2001 nfsrv_postopattr(nd, getret, &at);
2004 if (nd->nd_flag & ND_NFSV2) {
2005 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2006 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2007 *tl++ = txdr_unsigned(sf->f_bsize);
2008 *tl++ = txdr_unsigned(sf->f_blocks);
2009 *tl++ = txdr_unsigned(sf->f_bfree);
2010 *tl = txdr_unsigned(sf->f_bavail);
2012 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2013 tval = (u_quad_t)sf->f_blocks;
2014 tval *= (u_quad_t)sf->f_bsize;
2015 txdr_hyper(tval, tl); tl += 2;
2016 tval = (u_quad_t)sf->f_bfree;
2017 tval *= (u_quad_t)sf->f_bsize;
2018 txdr_hyper(tval, tl); tl += 2;
2019 tval = (u_quad_t)sf->f_bavail;
2020 tval *= (u_quad_t)sf->f_bsize;
2021 txdr_hyper(tval, tl); tl += 2;
2022 tval = (u_quad_t)sf->f_files;
2023 txdr_hyper(tval, tl); tl += 2;
2024 tval = (u_quad_t)sf->f_ffree;
2025 txdr_hyper(tval, tl); tl += 2;
2026 tval = (u_quad_t)sf->f_ffree;
2027 txdr_hyper(tval, tl); tl += 2;
2032 NFSEXITCODE2(0, nd);
2037 * nfs fsinfo service
2040 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2041 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2044 struct nfsfsinfo fs;
2048 if (nd->nd_repstat) {
2049 nfsrv_postopattr(nd, getret, &at);
2052 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2053 nfsvno_getfs(&fs, isdgram);
2055 nfsrv_postopattr(nd, getret, &at);
2056 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2057 *tl++ = txdr_unsigned(fs.fs_rtmax);
2058 *tl++ = txdr_unsigned(fs.fs_rtpref);
2059 *tl++ = txdr_unsigned(fs.fs_rtmult);
2060 *tl++ = txdr_unsigned(fs.fs_wtmax);
2061 *tl++ = txdr_unsigned(fs.fs_wtpref);
2062 *tl++ = txdr_unsigned(fs.fs_wtmult);
2063 *tl++ = txdr_unsigned(fs.fs_dtpref);
2064 txdr_hyper(fs.fs_maxfilesize, tl);
2066 txdr_nfsv3time(&fs.fs_timedelta, tl);
2068 *tl = txdr_unsigned(fs.fs_properties);
2071 NFSEXITCODE2(0, nd);
2076 * nfs pathconf service
2079 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2080 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2082 struct nfsv3_pathconf *pc;
2084 register_t linkmax, namemax, chownres, notrunc;
2087 if (nd->nd_repstat) {
2088 nfsrv_postopattr(nd, getret, &at);
2091 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2093 if (!nd->nd_repstat)
2094 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2096 if (!nd->nd_repstat)
2097 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2098 &chownres, nd->nd_cred, p);
2099 if (!nd->nd_repstat)
2100 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2102 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2104 nfsrv_postopattr(nd, getret, &at);
2105 if (!nd->nd_repstat) {
2106 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2107 pc->pc_linkmax = txdr_unsigned(linkmax);
2108 pc->pc_namemax = txdr_unsigned(namemax);
2109 pc->pc_notrunc = txdr_unsigned(notrunc);
2110 pc->pc_chownrestricted = txdr_unsigned(chownres);
2113 * These should probably be supported by VOP_PATHCONF(), but
2114 * until msdosfs is exportable (why would you want to?), the
2115 * Unix defaults should be ok.
2117 pc->pc_caseinsensitive = newnfs_false;
2118 pc->pc_casepreserving = newnfs_true;
2122 NFSEXITCODE2(0, nd);
2127 * nfsv4 lock service
2130 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2131 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2135 struct nfsstate *stp = NULL;
2136 struct nfslock *lop;
2137 struct nfslockconflict cf;
2139 u_short flags = NFSLCK_LOCK, lflags;
2140 u_int64_t offset, len;
2141 nfsv4stateid_t stateid;
2144 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2145 i = fxdr_unsigned(int, *tl++);
2147 case NFSV4LOCKT_READW:
2148 flags |= NFSLCK_BLOCKING;
2149 case NFSV4LOCKT_READ:
2150 lflags = NFSLCK_READ;
2152 case NFSV4LOCKT_WRITEW:
2153 flags |= NFSLCK_BLOCKING;
2154 case NFSV4LOCKT_WRITE:
2155 lflags = NFSLCK_WRITE;
2158 nd->nd_repstat = NFSERR_BADXDR;
2161 if (*tl++ == newnfs_true)
2162 flags |= NFSLCK_RECLAIM;
2163 offset = fxdr_hyper(tl);
2165 len = fxdr_hyper(tl);
2167 if (*tl == newnfs_true)
2168 flags |= NFSLCK_OPENTOLOCK;
2169 if (flags & NFSLCK_OPENTOLOCK) {
2170 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2171 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2172 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2173 nd->nd_repstat = NFSERR_BADXDR;
2176 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2177 M_NFSDSTATE, M_WAITOK);
2178 stp->ls_ownerlen = i;
2179 stp->ls_op = nd->nd_rp;
2180 stp->ls_seq = fxdr_unsigned(int, *tl++);
2181 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2182 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2184 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2185 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2186 clientid.lval[0] = *tl++;
2187 clientid.lval[1] = *tl++;
2188 if (nd->nd_flag & ND_IMPLIEDCLID) {
2189 if (nd->nd_clientid.qval != clientid.qval)
2190 printf("EEK! multiple clids\n");
2192 nd->nd_flag |= ND_IMPLIEDCLID;
2193 nd->nd_clientid.qval = clientid.qval;
2195 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2199 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2200 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2201 M_NFSDSTATE, M_WAITOK);
2202 stp->ls_ownerlen = 0;
2203 stp->ls_op = nd->nd_rp;
2204 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2205 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2207 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2208 stp->ls_seq = fxdr_unsigned(int, *tl);
2209 clientid.lval[0] = stp->ls_stateid.other[0];
2210 clientid.lval[1] = stp->ls_stateid.other[1];
2211 if (nd->nd_flag & ND_IMPLIEDCLID) {
2212 if (nd->nd_clientid.qval != clientid.qval)
2213 printf("EEK! multiple clids\n");
2215 nd->nd_flag |= ND_IMPLIEDCLID;
2216 nd->nd_clientid.qval = clientid.qval;
2219 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2220 M_NFSDLOCK, M_WAITOK);
2221 lop->lo_first = offset;
2222 if (len == NFS64BITSSET) {
2223 lop->lo_end = NFS64BITSSET;
2225 lop->lo_end = offset + len;
2226 if (lop->lo_end <= lop->lo_first)
2227 nd->nd_repstat = NFSERR_INVAL;
2229 lop->lo_flags = lflags;
2230 stp->ls_flags = flags;
2231 stp->ls_uid = nd->nd_cred->cr_uid;
2234 * Do basic access checking.
2236 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2237 if (vnode_vtype(vp) == VDIR)
2238 nd->nd_repstat = NFSERR_ISDIR;
2240 nd->nd_repstat = NFSERR_INVAL;
2242 if (!nd->nd_repstat) {
2243 if (lflags & NFSLCK_WRITE) {
2244 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2245 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2246 NFSACCCHK_VPISLOCKED, NULL);
2248 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2249 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2250 NFSACCCHK_VPISLOCKED, NULL);
2252 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2253 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2254 NFSACCCHK_VPISLOCKED, NULL);
2259 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2260 * seqid# gets updated. nfsrv_lockctrl() will return the value
2261 * of nd_repstat, if it gets that far.
2263 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2264 &stateid, exp, nd, p);
2266 FREE((caddr_t)lop, M_NFSDLOCK);
2268 FREE((caddr_t)stp, M_NFSDSTATE);
2269 if (!nd->nd_repstat) {
2270 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2271 *tl++ = txdr_unsigned(stateid.seqid);
2272 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2273 } else if (nd->nd_repstat == NFSERR_DENIED) {
2274 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2275 txdr_hyper(cf.cl_first, tl);
2277 if (cf.cl_end == NFS64BITSSET)
2280 len = cf.cl_end - cf.cl_first;
2281 txdr_hyper(len, tl);
2283 if (cf.cl_flags == NFSLCK_WRITE)
2284 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2286 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2287 *tl++ = stateid.other[0];
2288 *tl = stateid.other[1];
2289 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2292 NFSEXITCODE2(0, nd);
2297 free((caddr_t)stp, M_NFSDSTATE);
2298 NFSEXITCODE2(error, nd);
2303 * nfsv4 lock test service
2306 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2307 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2311 struct nfsstate *stp = NULL;
2312 struct nfslock lo, *lop = &lo;
2313 struct nfslockconflict cf;
2315 nfsv4stateid_t stateid;
2319 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2320 i = fxdr_unsigned(int, *(tl + 7));
2321 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2322 nd->nd_repstat = NFSERR_BADXDR;
2325 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2326 M_NFSDSTATE, M_WAITOK);
2327 stp->ls_ownerlen = i;
2329 stp->ls_flags = NFSLCK_TEST;
2330 stp->ls_uid = nd->nd_cred->cr_uid;
2331 i = fxdr_unsigned(int, *tl++);
2333 case NFSV4LOCKT_READW:
2334 stp->ls_flags |= NFSLCK_BLOCKING;
2335 case NFSV4LOCKT_READ:
2336 lo.lo_flags = NFSLCK_READ;
2338 case NFSV4LOCKT_WRITEW:
2339 stp->ls_flags |= NFSLCK_BLOCKING;
2340 case NFSV4LOCKT_WRITE:
2341 lo.lo_flags = NFSLCK_WRITE;
2344 nd->nd_repstat = NFSERR_BADXDR;
2347 lo.lo_first = fxdr_hyper(tl);
2349 len = fxdr_hyper(tl);
2350 if (len == NFS64BITSSET) {
2351 lo.lo_end = NFS64BITSSET;
2353 lo.lo_end = lo.lo_first + len;
2354 if (lo.lo_end <= lo.lo_first)
2355 nd->nd_repstat = NFSERR_INVAL;
2358 clientid.lval[0] = *tl++;
2359 clientid.lval[1] = *tl;
2360 if (nd->nd_flag & ND_IMPLIEDCLID) {
2361 if (nd->nd_clientid.qval != clientid.qval)
2362 printf("EEK! multiple clids\n");
2364 nd->nd_flag |= ND_IMPLIEDCLID;
2365 nd->nd_clientid.qval = clientid.qval;
2367 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2370 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2371 if (vnode_vtype(vp) == VDIR)
2372 nd->nd_repstat = NFSERR_ISDIR;
2374 nd->nd_repstat = NFSERR_INVAL;
2376 if (!nd->nd_repstat)
2377 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2378 &stateid, exp, nd, p);
2380 FREE((caddr_t)stp, M_NFSDSTATE);
2381 if (nd->nd_repstat) {
2382 if (nd->nd_repstat == NFSERR_DENIED) {
2383 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2384 txdr_hyper(cf.cl_first, tl);
2386 if (cf.cl_end == NFS64BITSSET)
2389 len = cf.cl_end - cf.cl_first;
2390 txdr_hyper(len, tl);
2392 if (cf.cl_flags == NFSLCK_WRITE)
2393 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2395 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2396 *tl++ = stp->ls_stateid.other[0];
2397 *tl = stp->ls_stateid.other[1];
2398 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2402 NFSEXITCODE2(0, nd);
2407 free((caddr_t)stp, M_NFSDSTATE);
2408 NFSEXITCODE2(error, nd);
2413 * nfsv4 unlock service
2416 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2417 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2421 struct nfsstate *stp;
2422 struct nfslock *lop;
2424 nfsv4stateid_t stateid;
2428 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2429 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2430 M_NFSDSTATE, M_WAITOK);
2431 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2432 M_NFSDLOCK, M_WAITOK);
2433 stp->ls_flags = NFSLCK_UNLOCK;
2434 lop->lo_flags = NFSLCK_UNLOCK;
2435 stp->ls_op = nd->nd_rp;
2436 i = fxdr_unsigned(int, *tl++);
2438 case NFSV4LOCKT_READW:
2439 stp->ls_flags |= NFSLCK_BLOCKING;
2440 case NFSV4LOCKT_READ:
2442 case NFSV4LOCKT_WRITEW:
2443 stp->ls_flags |= NFSLCK_BLOCKING;
2444 case NFSV4LOCKT_WRITE:
2447 nd->nd_repstat = NFSERR_BADXDR;
2448 free(stp, M_NFSDSTATE);
2449 free(lop, M_NFSDLOCK);
2452 stp->ls_ownerlen = 0;
2453 stp->ls_uid = nd->nd_cred->cr_uid;
2454 stp->ls_seq = fxdr_unsigned(int, *tl++);
2455 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2456 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2458 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2459 lop->lo_first = fxdr_hyper(tl);
2461 len = fxdr_hyper(tl);
2462 if (len == NFS64BITSSET) {
2463 lop->lo_end = NFS64BITSSET;
2465 lop->lo_end = lop->lo_first + len;
2466 if (lop->lo_end <= lop->lo_first)
2467 nd->nd_repstat = NFSERR_INVAL;
2469 clientid.lval[0] = stp->ls_stateid.other[0];
2470 clientid.lval[1] = stp->ls_stateid.other[1];
2471 if (nd->nd_flag & ND_IMPLIEDCLID) {
2472 if (nd->nd_clientid.qval != clientid.qval)
2473 printf("EEK! multiple clids\n");
2475 nd->nd_flag |= ND_IMPLIEDCLID;
2476 nd->nd_clientid.qval = clientid.qval;
2478 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2479 if (vnode_vtype(vp) == VDIR)
2480 nd->nd_repstat = NFSERR_ISDIR;
2482 nd->nd_repstat = NFSERR_INVAL;
2485 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2486 * seqid# gets incremented. nfsrv_lockctrl() will return the
2487 * value of nd_repstat, if it gets that far.
2489 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2490 &stateid, exp, nd, p);
2492 FREE((caddr_t)stp, M_NFSDSTATE);
2494 free((caddr_t)lop, M_NFSDLOCK);
2495 if (!nd->nd_repstat) {
2496 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2497 *tl++ = txdr_unsigned(stateid.seqid);
2498 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2502 NFSEXITCODE2(error, nd);
2507 * nfsv4 open service
2510 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2511 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2512 struct nfsexstuff *exp)
2516 struct nfsstate *stp = NULL;
2517 int error = 0, create, claim, exclusive_flag = 0;
2518 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2519 int how = NFSCREATE_UNCHECKED;
2520 int32_t cverf[2], tverf[2] = { 0, 0 };
2521 vnode_t vp = NULL, dirp = NULL;
2522 struct nfsvattr nva, dirfor, diraft;
2523 struct nameidata named;
2524 nfsv4stateid_t stateid, delegstateid;
2525 nfsattrbit_t attrbits;
2529 NFSACL_T *aclp = NULL;
2531 #ifdef NFS4_ACL_EXTATTR_NAME
2532 aclp = acl_alloc(M_WAITOK);
2535 NFSZERO_ATTRBIT(&attrbits);
2536 named.ni_startdir = NULL;
2537 named.ni_cnd.cn_nameiop = 0;
2538 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2539 i = fxdr_unsigned(int, *(tl + 5));
2540 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2541 nd->nd_repstat = NFSERR_BADXDR;
2544 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2545 M_NFSDSTATE, M_WAITOK);
2546 stp->ls_ownerlen = i;
2547 stp->ls_op = nd->nd_rp;
2548 stp->ls_flags = NFSLCK_OPEN;
2549 stp->ls_uid = nd->nd_cred->cr_uid;
2550 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2551 i = fxdr_unsigned(int, *tl++);
2553 case NFSV4OPEN_ACCESSREAD:
2554 stp->ls_flags |= NFSLCK_READACCESS;
2556 case NFSV4OPEN_ACCESSWRITE:
2557 stp->ls_flags |= NFSLCK_WRITEACCESS;
2559 case NFSV4OPEN_ACCESSBOTH:
2560 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2563 nd->nd_repstat = NFSERR_INVAL;
2565 i = fxdr_unsigned(int, *tl++);
2567 case NFSV4OPEN_DENYNONE:
2569 case NFSV4OPEN_DENYREAD:
2570 stp->ls_flags |= NFSLCK_READDENY;
2572 case NFSV4OPEN_DENYWRITE:
2573 stp->ls_flags |= NFSLCK_WRITEDENY;
2575 case NFSV4OPEN_DENYBOTH:
2576 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2579 nd->nd_repstat = NFSERR_INVAL;
2581 clientid.lval[0] = *tl++;
2582 clientid.lval[1] = *tl;
2583 if (nd->nd_flag & ND_IMPLIEDCLID) {
2584 if (nd->nd_clientid.qval != clientid.qval)
2585 printf("EEK! multiple clids\n");
2587 nd->nd_flag |= ND_IMPLIEDCLID;
2588 nd->nd_clientid.qval = clientid.qval;
2590 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2593 NFSVNO_ATTRINIT(&nva);
2594 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2595 create = fxdr_unsigned(int, *tl);
2596 if (!nd->nd_repstat)
2597 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2598 if (create == NFSV4OPEN_CREATE) {
2601 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2602 how = fxdr_unsigned(int, *tl);
2604 case NFSCREATE_UNCHECKED:
2605 case NFSCREATE_GUARDED:
2606 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2610 * If the na_gid being set is the same as that of
2611 * the directory it is going in, clear it, since
2612 * that is what will be set by default. This allows
2613 * a user that isn't in that group to do the create.
2615 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2616 nva.na_gid == dirfor.na_gid)
2617 NFSVNO_UNSET(&nva, gid);
2618 if (!nd->nd_repstat)
2619 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2621 case NFSCREATE_EXCLUSIVE:
2622 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2627 nd->nd_repstat = NFSERR_BADXDR;
2630 } else if (create != NFSV4OPEN_NOCREATE) {
2631 nd->nd_repstat = NFSERR_BADXDR;
2636 * Now, handle the claim, which usually includes looking up a
2637 * name in the directory referenced by dp. The exception is
2638 * NFSV4OPEN_CLAIMPREVIOUS.
2640 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2641 claim = fxdr_unsigned(int, *tl);
2642 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2643 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2644 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2645 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2646 stp->ls_flags |= NFSLCK_DELEGCUR;
2647 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2648 stp->ls_flags |= NFSLCK_DELEGPREV;
2650 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2651 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2652 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2653 claim != NFSV4OPEN_CLAIMNULL)
2654 nd->nd_repstat = NFSERR_INVAL;
2655 if (nd->nd_repstat) {
2656 nd->nd_repstat = nfsrv_opencheck(clientid,
2657 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2660 if (create == NFSV4OPEN_CREATE)
2661 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2662 LOCKPARENT | LOCKLEAF | SAVESTART);
2664 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2665 LOCKLEAF | SAVESTART);
2666 nfsvno_setpathbuf(&named, &bufp, &hashp);
2667 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2670 #ifdef NFS4_ACL_EXTATTR_NAME
2673 FREE((caddr_t)stp, M_NFSDSTATE);
2674 nfsvno_relpathbuf(&named);
2675 NFSEXITCODE2(error, nd);
2678 if (!nd->nd_repstat) {
2679 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2683 nfsvno_relpathbuf(&named);
2685 if (create == NFSV4OPEN_CREATE) {
2687 case NFSCREATE_UNCHECKED:
2690 * Clear the setable attribute bits, except
2691 * for Size, if it is being truncated.
2693 NFSZERO_ATTRBIT(&attrbits);
2694 if (NFSVNO_ISSETSIZE(&nva))
2695 NFSSETBIT_ATTRBIT(&attrbits,
2699 case NFSCREATE_GUARDED:
2700 if (named.ni_vp && !nd->nd_repstat)
2701 nd->nd_repstat = EEXIST;
2703 case NFSCREATE_EXCLUSIVE:
2709 nfsvno_open(nd, &named, clientid, &stateid, stp,
2710 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2711 nd->nd_cred, p, exp, &vp);
2712 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2714 i = fxdr_unsigned(int, *tl);
2716 case NFSV4OPEN_DELEGATEREAD:
2717 stp->ls_flags |= NFSLCK_DELEGREAD;
2719 case NFSV4OPEN_DELEGATEWRITE:
2720 stp->ls_flags |= NFSLCK_DELEGWRITE;
2721 case NFSV4OPEN_DELEGATENONE:
2724 nd->nd_repstat = NFSERR_BADXDR;
2727 stp->ls_flags |= NFSLCK_RECLAIM;
2729 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2730 if ((vp->v_iflag & VI_DOOMED) == 0)
2731 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2732 stp, vp, nd, p, nd->nd_repstat);
2734 nd->nd_repstat = NFSERR_PERM;
2736 nd->nd_repstat = NFSERR_BADXDR;
2741 * Do basic access checking.
2743 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2745 * The IETF working group decided that this is the correct
2746 * error return for all non-regular files.
2748 nd->nd_repstat = NFSERR_SYMLINK;
2750 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2751 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2752 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2753 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2754 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2755 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2757 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2758 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2759 NFSACCCHK_VPISLOCKED, NULL);
2762 if (!nd->nd_repstat) {
2763 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2764 if (!nd->nd_repstat) {
2765 tverf[0] = nva.na_atime.tv_sec;
2766 tverf[1] = nva.na_atime.tv_nsec;
2769 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2770 cverf[1] != tverf[1]))
2771 nd->nd_repstat = EEXIST;
2773 * Do the open locking/delegation stuff.
2775 if (!nd->nd_repstat)
2776 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2777 &delegstateid, &rflags, exp, p, nva.na_filerev);
2780 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2781 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2782 * (ie: Leave the NFSVOPUNLOCK() about here.)
2785 NFSVOPUNLOCK(vp, 0);
2787 FREE((caddr_t)stp, M_NFSDSTATE);
2788 if (!nd->nd_repstat && dirp)
2789 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2791 if (!nd->nd_repstat) {
2792 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2793 *tl++ = txdr_unsigned(stateid.seqid);
2794 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2795 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2796 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2797 *tl++ = newnfs_true;
2803 *tl++ = newnfs_false; /* Since dirp is not locked */
2804 txdr_hyper(dirfor.na_filerev, tl);
2806 txdr_hyper(diraft.na_filerev, tl);
2809 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2810 (void) nfsrv_putattrbit(nd, &attrbits);
2811 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2812 if (rflags & NFSV4OPEN_READDELEGATE)
2813 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2814 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2815 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2817 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2818 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2819 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2820 *tl++ = txdr_unsigned(delegstateid.seqid);
2821 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2823 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2824 if (rflags & NFSV4OPEN_RECALL)
2828 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2829 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2830 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2831 txdr_hyper(nva.na_size, tl);
2833 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2834 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2835 *tl++ = txdr_unsigned(0x0);
2836 acemask = NFSV4ACE_ALLFILESMASK;
2837 if (nva.na_mode & S_IRUSR)
2838 acemask |= NFSV4ACE_READMASK;
2839 if (nva.na_mode & S_IWUSR)
2840 acemask |= NFSV4ACE_WRITEMASK;
2841 if (nva.na_mode & S_IXUSR)
2842 acemask |= NFSV4ACE_EXECUTEMASK;
2843 *tl = txdr_unsigned(acemask);
2844 (void) nfsm_strtom(nd, "OWNER@", 6);
2852 #ifdef NFS4_ACL_EXTATTR_NAME
2855 NFSEXITCODE2(0, nd);
2859 #ifdef NFS4_ACL_EXTATTR_NAME
2863 FREE((caddr_t)stp, M_NFSDSTATE);
2864 NFSEXITCODE2(error, nd);
2869 * nfsv4 close service
2872 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2873 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2876 struct nfsstate st, *stp = &st;
2878 nfsv4stateid_t stateid;
2881 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2882 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2883 stp->ls_ownerlen = 0;
2884 stp->ls_op = nd->nd_rp;
2885 stp->ls_uid = nd->nd_cred->cr_uid;
2886 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2887 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2889 stp->ls_flags = NFSLCK_CLOSE;
2890 clientid.lval[0] = stp->ls_stateid.other[0];
2891 clientid.lval[1] = stp->ls_stateid.other[1];
2892 if (nd->nd_flag & ND_IMPLIEDCLID) {
2893 if (nd->nd_clientid.qval != clientid.qval)
2894 printf("EEK! multiple clids\n");
2896 nd->nd_flag |= ND_IMPLIEDCLID;
2897 nd->nd_clientid.qval = clientid.qval;
2899 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2901 if (!nd->nd_repstat) {
2902 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2903 *tl++ = txdr_unsigned(stateid.seqid);
2904 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2906 NFSEXITCODE2(0, nd);
2910 NFSEXITCODE2(error, nd);
2915 * nfsv4 delegpurge service
2918 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2919 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2925 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2926 nd->nd_repstat = NFSERR_WRONGSEC;
2929 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2930 clientid.lval[0] = *tl++;
2931 clientid.lval[1] = *tl;
2932 if (nd->nd_flag & ND_IMPLIEDCLID) {
2933 if (nd->nd_clientid.qval != clientid.qval)
2934 printf("EEK! multiple clids\n");
2936 nd->nd_flag |= ND_IMPLIEDCLID;
2937 nd->nd_clientid.qval = clientid.qval;
2939 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2940 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2942 NFSEXITCODE2(error, nd);
2947 * nfsv4 delegreturn service
2950 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2951 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2955 nfsv4stateid_t stateid;
2958 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2959 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2960 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2961 clientid.lval[0] = stateid.other[0];
2962 clientid.lval[1] = stateid.other[1];
2963 if (nd->nd_flag & ND_IMPLIEDCLID) {
2964 if (nd->nd_clientid.qval != clientid.qval)
2965 printf("EEK! multiple clids\n");
2967 nd->nd_flag |= ND_IMPLIEDCLID;
2968 nd->nd_clientid.qval = clientid.qval;
2970 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2971 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2974 NFSEXITCODE2(error, nd);
2979 * nfsv4 get file handle service
2982 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2983 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2987 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2989 if (!nd->nd_repstat)
2990 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2991 NFSEXITCODE2(0, nd);
2996 * nfsv4 open confirm service
2999 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3000 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3003 struct nfsstate st, *stp = &st;
3005 nfsv4stateid_t stateid;
3008 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3009 stp->ls_ownerlen = 0;
3010 stp->ls_op = nd->nd_rp;
3011 stp->ls_uid = nd->nd_cred->cr_uid;
3012 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3013 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3015 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3016 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3017 stp->ls_flags = NFSLCK_CONFIRM;
3018 clientid.lval[0] = stp->ls_stateid.other[0];
3019 clientid.lval[1] = stp->ls_stateid.other[1];
3020 if (nd->nd_flag & ND_IMPLIEDCLID) {
3021 if (nd->nd_clientid.qval != clientid.qval)
3022 printf("EEK! multiple clids\n");
3024 nd->nd_flag |= ND_IMPLIEDCLID;
3025 nd->nd_clientid.qval = clientid.qval;
3027 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3028 if (!nd->nd_repstat) {
3029 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3030 *tl++ = txdr_unsigned(stateid.seqid);
3031 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3035 NFSEXITCODE2(error, nd);
3040 * nfsv4 open downgrade service
3043 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3044 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3048 struct nfsstate st, *stp = &st;
3050 nfsv4stateid_t stateid;
3053 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3054 stp->ls_ownerlen = 0;
3055 stp->ls_op = nd->nd_rp;
3056 stp->ls_uid = nd->nd_cred->cr_uid;
3057 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3058 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3060 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3061 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3062 i = fxdr_unsigned(int, *tl++);
3064 case NFSV4OPEN_ACCESSREAD:
3065 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3067 case NFSV4OPEN_ACCESSWRITE:
3068 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3070 case NFSV4OPEN_ACCESSBOTH:
3071 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3075 nd->nd_repstat = NFSERR_BADXDR;
3077 i = fxdr_unsigned(int, *tl);
3079 case NFSV4OPEN_DENYNONE:
3081 case NFSV4OPEN_DENYREAD:
3082 stp->ls_flags |= NFSLCK_READDENY;
3084 case NFSV4OPEN_DENYWRITE:
3085 stp->ls_flags |= NFSLCK_WRITEDENY;
3087 case NFSV4OPEN_DENYBOTH:
3088 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3091 nd->nd_repstat = NFSERR_BADXDR;
3094 clientid.lval[0] = stp->ls_stateid.other[0];
3095 clientid.lval[1] = stp->ls_stateid.other[1];
3096 if (nd->nd_flag & ND_IMPLIEDCLID) {
3097 if (nd->nd_clientid.qval != clientid.qval)
3098 printf("EEK! multiple clids\n");
3100 nd->nd_flag |= ND_IMPLIEDCLID;
3101 nd->nd_clientid.qval = clientid.qval;
3103 if (!nd->nd_repstat)
3104 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3106 if (!nd->nd_repstat) {
3107 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3108 *tl++ = txdr_unsigned(stateid.seqid);
3109 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3113 NFSEXITCODE2(error, nd);
3118 * nfsv4 renew lease service
3121 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3122 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3128 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3129 nd->nd_repstat = NFSERR_WRONGSEC;
3132 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3133 clientid.lval[0] = *tl++;
3134 clientid.lval[1] = *tl;
3135 if (nd->nd_flag & ND_IMPLIEDCLID) {
3136 if (nd->nd_clientid.qval != clientid.qval)
3137 printf("EEK! multiple clids\n");
3139 nd->nd_flag |= ND_IMPLIEDCLID;
3140 nd->nd_clientid.qval = clientid.qval;
3142 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3143 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3145 NFSEXITCODE2(error, nd);
3150 * nfsv4 security info service
3153 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3154 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3158 struct nameidata named;
3159 vnode_t dirp = NULL, vp;
3161 struct nfsexstuff retnes;
3163 int error = 0, savflag, i;
3168 * All this just to get the export flags for the name.
3170 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3171 LOCKLEAF | SAVESTART);
3172 nfsvno_setpathbuf(&named, &bufp, &hashp);
3173 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3176 nfsvno_relpathbuf(&named);
3179 if (!nd->nd_repstat) {
3180 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3183 nfsvno_relpathbuf(&named);
3189 vrele(named.ni_startdir);
3190 nfsvno_relpathbuf(&named);
3191 fh.nfsrvfh_len = NFSX_MYFH;
3193 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3195 savflag = nd->nd_flag;
3196 if (!nd->nd_repstat) {
3197 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3201 nd->nd_flag = savflag;
3206 * Finally have the export flags for name, so we can create
3207 * the security info.
3210 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3211 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3212 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3213 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3214 *tl = txdr_unsigned(RPCAUTH_UNIX);
3216 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3217 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3218 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3219 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3220 nfsgss_mechlist[KERBV_MECH].len);
3221 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3222 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3223 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3225 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3226 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3227 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3228 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3229 nfsgss_mechlist[KERBV_MECH].len);
3230 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3231 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3232 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3234 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3235 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3236 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3237 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3238 nfsgss_mechlist[KERBV_MECH].len);
3239 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3240 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3241 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3245 *sizp = txdr_unsigned(len);
3248 NFSEXITCODE2(error, nd);
3253 * nfsv4 set client id service
3256 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3257 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3261 int error = 0, idlen;
3262 struct nfsclient *clp = NULL;
3263 struct sockaddr_in *rad;
3264 u_char *verf, *ucp, *ucp2, addrbuf[24];
3265 nfsquad_t clientid, confirm;
3267 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3268 nd->nd_repstat = NFSERR_WRONGSEC;
3271 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3272 verf = (u_char *)tl;
3273 tl += (NFSX_VERF / NFSX_UNSIGNED);
3274 i = fxdr_unsigned(int, *tl);
3275 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3276 nd->nd_repstat = NFSERR_BADXDR;
3280 if (nd->nd_flag & ND_GSS)
3281 i += nd->nd_princlen;
3282 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3283 M_NFSDCLIENT, M_WAITOK);
3284 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3285 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3286 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3287 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3288 clp->lc_req.nr_cred = NULL;
3289 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3290 clp->lc_idlen = idlen;
3291 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3294 if (nd->nd_flag & ND_GSS) {
3295 clp->lc_flags = LCL_GSS;
3296 if (nd->nd_flag & ND_GSSINTEGRITY)
3297 clp->lc_flags |= LCL_GSSINTEGRITY;
3298 else if (nd->nd_flag & ND_GSSPRIVACY)
3299 clp->lc_flags |= LCL_GSSPRIVACY;
3303 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3304 clp->lc_flags |= LCL_NAME;
3305 clp->lc_namelen = nd->nd_princlen;
3306 clp->lc_name = &clp->lc_id[idlen];
3307 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3309 clp->lc_uid = nd->nd_cred->cr_uid;
3310 clp->lc_gid = nd->nd_cred->cr_gid;
3312 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3313 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3314 error = nfsrv_getclientipaddr(nd, clp);
3317 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3318 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3321 * nfsrv_setclient() does the actual work of adding it to the
3322 * client list. If there is no error, the structure has been
3323 * linked into the client list and clp should no longer be used
3324 * here. When an error is returned, it has not been linked in,
3325 * so it should be free'd.
3327 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3328 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3329 if (clp->lc_flags & LCL_TCPCALLBACK)
3330 (void) nfsm_strtom(nd, "tcp", 3);
3332 (void) nfsm_strtom(nd, "udp", 3);
3333 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3334 ucp = (u_char *)&rad->sin_addr.s_addr;
3335 ucp2 = (u_char *)&rad->sin_port;
3336 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3337 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3338 ucp2[0] & 0xff, ucp2[1] & 0xff);
3339 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3342 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3343 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3344 free((caddr_t)clp, M_NFSDCLIENT);
3346 if (!nd->nd_repstat) {
3347 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3348 *tl++ = clientid.lval[0];
3349 *tl++ = clientid.lval[1];
3350 *tl++ = confirm.lval[0];
3351 *tl = confirm.lval[1];
3355 NFSEXITCODE2(0, nd);
3359 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3360 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3361 free((caddr_t)clp, M_NFSDCLIENT);
3363 NFSEXITCODE2(error, nd);
3368 * nfsv4 set client id confirm service
3371 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3372 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3373 __unused struct nfsexstuff *exp)
3377 nfsquad_t clientid, confirm;
3379 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3380 nd->nd_repstat = NFSERR_WRONGSEC;
3383 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3384 clientid.lval[0] = *tl++;
3385 clientid.lval[1] = *tl++;
3386 confirm.lval[0] = *tl++;
3387 confirm.lval[1] = *tl;
3390 * nfsrv_getclient() searches the client list for a match and
3391 * returns the appropriate NFSERR status.
3393 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3394 NULL, confirm, nd, p);
3396 NFSEXITCODE2(error, nd);
3401 * nfsv4 verify service
3404 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3405 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3407 int error = 0, ret, fhsize = NFSX_MYFH;
3408 struct nfsvattr nva;
3410 struct nfsfsinfo fs;
3413 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3414 if (!nd->nd_repstat)
3415 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3416 if (!nd->nd_repstat)
3417 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3418 if (!nd->nd_repstat) {
3419 nfsvno_getfs(&fs, isdgram);
3420 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3421 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3423 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3425 nd->nd_repstat = NFSERR_SAME;
3426 else if (ret != NFSERR_NOTSAME)
3427 nd->nd_repstat = ret;
3429 nd->nd_repstat = ret;
3433 NFSEXITCODE2(error, nd);
3441 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3442 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3443 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3446 int error = 0, createdir;
3448 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3449 createdir = fxdr_unsigned(int, *tl);
3450 nd->nd_repstat = NFSERR_NOTSUPP;
3453 NFSEXITCODE2(error, nd);
3458 * nfsv4 release lock owner service
3461 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3462 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3465 struct nfsstate *stp = NULL;
3469 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3470 nd->nd_repstat = NFSERR_WRONGSEC;
3473 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3474 len = fxdr_unsigned(int, *(tl + 2));
3475 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3476 nd->nd_repstat = NFSERR_BADXDR;
3479 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3480 M_NFSDSTATE, M_WAITOK);
3481 stp->ls_ownerlen = len;
3483 stp->ls_flags = NFSLCK_RELEASE;
3484 stp->ls_uid = nd->nd_cred->cr_uid;
3485 clientid.lval[0] = *tl++;
3486 clientid.lval[1] = *tl;
3487 if (nd->nd_flag & ND_IMPLIEDCLID) {
3488 if (nd->nd_clientid.qval != clientid.qval)
3489 printf("EEK! multiple clids\n");
3491 nd->nd_flag |= ND_IMPLIEDCLID;
3492 nd->nd_clientid.qval = clientid.qval;
3494 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3497 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3498 FREE((caddr_t)stp, M_NFSDSTATE);
3500 NFSEXITCODE2(0, nd);
3504 free((caddr_t)stp, M_NFSDSTATE);
3505 NFSEXITCODE2(error, nd);