2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * nfs version 2, 3 and 4 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42 * function in nfsd_port.c
43 * 3 - build the rpc reply in an mbuf list
44 * For nfsv4, these functions are called for each Op within the Compound RPC.
48 #include <fs/nfs/nfsport.h>
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset;
55 extern int nfsrv_enable_crossmntpt;
56 #endif /* !APPLEKEXT */
58 static int nfs_async = 0;
59 SYSCTL_DECL(_vfs_nfsd);
60 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
61 "Tell client that writes were synced even though they were not");
64 * This list defines the GSS mechanisms supported.
65 * (Don't ask me how you get these strings from the RFC stuff like
66 * iso(1), org(3)... but someone did it, so I don't need to know.)
68 static struct nfsgss_mechlist nfsgss_mechlist[] = {
69 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
74 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
75 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
76 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
77 int *diraft_retp, nfsattrbit_t *attrbitp,
78 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
80 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
81 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
82 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
83 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
84 NFSPROC_T *p, struct nfsexstuff *exp);
87 * nfs access service (not a part of NFS V2)
90 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
91 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
94 int getret, error = 0;
96 u_int32_t testmode, nfsmode, supported = 0;
100 nfsrv_postopattr(nd, 1, &nva);
103 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
104 nfsmode = fxdr_unsigned(u_int32_t, *tl);
105 if ((nd->nd_flag & ND_NFSV4) &&
106 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
107 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
108 NFSACCESS_EXECUTE))) {
109 nd->nd_repstat = NFSERR_INVAL;
113 if (nfsmode & NFSACCESS_READ) {
114 supported |= NFSACCESS_READ;
115 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
116 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
117 nfsmode &= ~NFSACCESS_READ;
119 if (nfsmode & NFSACCESS_MODIFY) {
120 supported |= NFSACCESS_MODIFY;
121 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
122 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
123 nfsmode &= ~NFSACCESS_MODIFY;
125 if (nfsmode & NFSACCESS_EXTEND) {
126 supported |= NFSACCESS_EXTEND;
127 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
128 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
129 nfsmode &= ~NFSACCESS_EXTEND;
131 if (nfsmode & NFSACCESS_DELETE) {
132 supported |= NFSACCESS_DELETE;
133 if (vp->v_type == VDIR)
134 deletebit = VDELETE_CHILD;
137 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
138 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
139 nfsmode &= ~NFSACCESS_DELETE;
141 if (vnode_vtype(vp) == VDIR)
142 testmode = NFSACCESS_LOOKUP;
144 testmode = NFSACCESS_EXECUTE;
145 if (nfsmode & testmode) {
146 supported |= (nfsmode & testmode);
147 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
148 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
149 nfsmode &= ~testmode;
151 nfsmode &= supported;
152 if (nd->nd_flag & ND_NFSV3) {
153 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
154 nfsrv_postopattr(nd, getret, &nva);
157 if (nd->nd_flag & ND_NFSV4) {
158 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
159 *tl++ = txdr_unsigned(supported);
161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
162 *tl = txdr_unsigned(nfsmode);
169 NFSEXITCODE2(error, nd);
174 * nfs getattr service
177 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
178 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
182 int at_root = 0, error = 0, supports_nfsv4acls;
183 struct nfsreferral *refp;
184 nfsattrbit_t attrbits, tmpbits;
186 struct vnode *tvp = NULL;
188 uint64_t mounted_on_fileno = 0;
193 if (nd->nd_flag & ND_NFSV4) {
194 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
201 * Check for a referral.
203 refp = nfsv4root_getreferral(vp, NULL, 0);
205 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
210 if (nd->nd_repstat == 0) {
212 NFSSET_ATTRBIT(&tmpbits, &attrbits);
213 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
214 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
215 accmode |= VREAD_ACL;
217 if (NFSNONZERO_ATTRBIT(&tmpbits))
218 accmode |= VREAD_ATTRIBUTES;
220 nd->nd_repstat = nfsvno_accchk(vp, accmode,
221 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
222 NFSACCCHK_VPISLOCKED, NULL);
226 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
227 if (!nd->nd_repstat) {
228 if (nd->nd_flag & ND_NFSV4) {
229 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
230 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
232 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
233 &nva, &attrbits, nd->nd_cred, p);
234 if (nd->nd_repstat == 0) {
235 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
237 if (nfsrv_enable_crossmntpt != 0 &&
238 vp->v_type == VDIR &&
239 (vp->v_vflag & VV_ROOT) != 0 &&
241 tvp = mp->mnt_vnodecovered;
249 if ((nd->nd_repstat =
250 NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
251 nd->nd_repstat = VOP_GETATTR(
252 tvp, &va, nd->nd_cred);
256 if (nd->nd_repstat == 0)
257 mounted_on_fileno = (uint64_t)
262 if (nd->nd_repstat == 0)
263 nd->nd_repstat = vfs_busy(mp, 0);
265 if (nd->nd_repstat == 0) {
266 (void)nfsvno_fillattr(nd, mp, vp, &nva,
267 &fh, 0, &attrbits, nd->nd_cred, p,
268 isdgram, 1, supports_nfsv4acls,
269 at_root, mounted_on_fileno);
276 nfsrv_fillattr(nd, &nva);
284 NFSEXITCODE2(error, nd);
289 * nfs setattr service
292 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
293 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
295 struct nfsvattr nva, nva2;
297 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
298 struct timespec guard = { 0, 0 };
299 nfsattrbit_t attrbits, retbits;
300 nfsv4stateid_t stateid;
301 NFSACL_T *aclp = NULL;
303 if (nd->nd_repstat) {
304 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
307 #ifdef NFS4_ACL_EXTATTR_NAME
308 aclp = acl_alloc(M_WAITOK);
311 NFSVNO_ATTRINIT(&nva);
312 NFSZERO_ATTRBIT(&retbits);
313 if (nd->nd_flag & ND_NFSV4) {
314 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
315 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
316 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
318 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
321 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
323 nd->nd_repstat = preat_ret;
324 if (nd->nd_flag & ND_NFSV3) {
325 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
326 gcheck = fxdr_unsigned(int, *tl);
328 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
329 fxdr_nfsv3time(tl, &guard);
331 if (!nd->nd_repstat && gcheck &&
332 (nva2.na_ctime.tv_sec != guard.tv_sec ||
333 nva2.na_ctime.tv_nsec != guard.tv_nsec))
334 nd->nd_repstat = NFSERR_NOT_SYNC;
335 if (nd->nd_repstat) {
337 #ifdef NFS4_ACL_EXTATTR_NAME
340 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
343 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
344 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
347 * Now that we have all the fields, lets do it.
348 * If the size is being changed write access is required, otherwise
349 * just check for a read only file system.
351 if (!nd->nd_repstat) {
352 if (NFSVNO_NOTSETSIZE(&nva)) {
353 if (NFSVNO_EXRDONLY(exp) ||
354 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
355 nd->nd_repstat = EROFS;
357 if (vnode_vtype(vp) != VREG)
358 nd->nd_repstat = EINVAL;
359 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
360 NFSVNO_EXSTRICTACCESS(exp))
361 nd->nd_repstat = nfsvno_accchk(vp,
362 VWRITE, nd->nd_cred, exp, p,
363 NFSACCCHK_NOOVERRIDE,
364 NFSACCCHK_VPISLOCKED, NULL);
367 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
368 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
369 &nva, &attrbits, exp, p);
371 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
373 * For V4, try setting the attrbutes in sets, so that the
374 * reply bitmap will be correct for an error case.
376 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
377 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
378 NFSVNO_ATTRINIT(&nva2);
379 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
380 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
381 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
383 if (!nd->nd_repstat) {
384 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
385 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
386 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
387 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
390 if (!nd->nd_repstat &&
391 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
392 NFSVNO_ATTRINIT(&nva2);
393 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
394 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
397 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
399 if (!nd->nd_repstat &&
400 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
401 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
402 NFSVNO_ATTRINIT(&nva2);
403 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
404 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
405 if (nva.na_vaflags & VA_UTIMES_NULL) {
406 nva2.na_vaflags |= VA_UTIMES_NULL;
407 NFSVNO_SETACTIVE(&nva2, vaflags);
409 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
411 if (!nd->nd_repstat) {
412 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
413 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
414 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
415 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
418 if (!nd->nd_repstat &&
419 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
420 NFSVNO_ATTRINIT(&nva2);
421 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
422 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
425 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
428 #ifdef NFS4_ACL_EXTATTR_NAME
429 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
430 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
431 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
433 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
436 } else if (!nd->nd_repstat) {
437 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
440 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
441 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
443 nd->nd_repstat = postat_ret;
446 #ifdef NFS4_ACL_EXTATTR_NAME
449 if (nd->nd_flag & ND_NFSV3)
450 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
451 else if (nd->nd_flag & ND_NFSV4)
452 (void) nfsrv_putattrbit(nd, &retbits);
453 else if (!nd->nd_repstat)
454 nfsrv_fillattr(nd, &nva);
461 #ifdef NFS4_ACL_EXTATTR_NAME
464 if (nd->nd_flag & ND_NFSV4) {
466 * For all nd_repstat, the V4 reply includes a bitmap,
467 * even NFSERR_BADXDR, which is what this will end up
470 (void) nfsrv_putattrbit(nd, &retbits);
472 NFSEXITCODE2(error, nd);
478 * (Also performs lookup parent for v4)
481 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
482 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
483 struct nfsexstuff *exp)
485 struct nameidata named;
486 vnode_t vp, dirp = NULL;
487 int error = 0, dattr_ret = 1;
488 struct nfsvattr nva, dattr;
492 if (nd->nd_repstat) {
493 nfsrv_postopattr(nd, dattr_ret, &dattr);
498 * For some reason, if dp is a symlink, the error
499 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
501 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
502 nd->nd_repstat = NFSERR_SYMLINK;
507 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
508 LOCKLEAF | SAVESTART);
509 nfsvno_setpathbuf(&named, &bufp, &hashp);
510 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
513 nfsvno_relpathbuf(&named);
516 if (!nd->nd_repstat) {
517 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
520 nfsvno_relpathbuf(&named);
522 if (nd->nd_repstat) {
524 if (nd->nd_flag & ND_NFSV3)
525 dattr_ret = nfsvno_getattr(dirp, &dattr,
529 if (nd->nd_flag & ND_NFSV3)
530 nfsrv_postopattr(nd, dattr_ret, &dattr);
533 if (named.ni_startdir)
534 vrele(named.ni_startdir);
535 nfsvno_relpathbuf(&named);
537 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
538 vp->v_type != VDIR && vp->v_type != VLNK)
540 * Only allow lookup of VDIR and VLNK for traversal of
541 * non-exported volumes during NFSv4 mounting.
543 nd->nd_repstat = ENOENT;
544 if (nd->nd_repstat == 0)
545 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
546 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
547 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
548 if (vpp != NULL && nd->nd_repstat == 0)
553 if (nd->nd_flag & ND_NFSV3)
554 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
558 if (nd->nd_repstat) {
559 if (nd->nd_flag & ND_NFSV3)
560 nfsrv_postopattr(nd, dattr_ret, &dattr);
563 if (nd->nd_flag & ND_NFSV2) {
564 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
565 nfsrv_fillattr(nd, &nva);
566 } else if (nd->nd_flag & ND_NFSV3) {
567 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
568 nfsrv_postopattr(nd, 0, &nva);
569 nfsrv_postopattr(nd, dattr_ret, &dattr);
573 NFSEXITCODE2(error, nd);
578 * nfs readlink service
581 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
582 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
585 mbuf_t mp = NULL, mpend = NULL;
589 if (nd->nd_repstat) {
590 nfsrv_postopattr(nd, getret, &nva);
593 if (vnode_vtype(vp) != VLNK) {
594 if (nd->nd_flag & ND_NFSV2)
595 nd->nd_repstat = ENXIO;
597 nd->nd_repstat = EINVAL;
600 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
602 if (nd->nd_flag & ND_NFSV3)
603 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
605 if (nd->nd_flag & ND_NFSV3)
606 nfsrv_postopattr(nd, getret, &nva);
609 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
610 *tl = txdr_unsigned(len);
611 mbuf_setnext(nd->nd_mb, mp);
613 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
624 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
625 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
628 int error = 0, cnt, getret = 1, reqlen, eof = 0;
632 struct nfsstate st, *stp = &st;
633 struct nfslock lo, *lop = &lo;
634 nfsv4stateid_t stateid;
637 if (nd->nd_repstat) {
638 nfsrv_postopattr(nd, getret, &nva);
641 if (nd->nd_flag & ND_NFSV2) {
642 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
643 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
644 reqlen = fxdr_unsigned(int, *tl);
645 } else if (nd->nd_flag & ND_NFSV3) {
646 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
647 off = fxdr_hyper(tl);
649 reqlen = fxdr_unsigned(int, *tl);
651 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
652 reqlen = fxdr_unsigned(int, *(tl + 6));
654 if (reqlen > NFS_SRVMAXDATA(nd)) {
655 reqlen = NFS_SRVMAXDATA(nd);
656 } else if (reqlen < 0) {
660 if (nd->nd_flag & ND_NFSV4) {
661 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
662 lop->lo_flags = NFSLCK_READ;
663 stp->ls_ownerlen = 0;
665 stp->ls_uid = nd->nd_cred->cr_uid;
666 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
667 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
668 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
669 if (nd->nd_flag & ND_IMPLIEDCLID) {
670 if (nd->nd_clientid.qval != clientid.qval)
671 printf("EEK! multiple clids\n");
673 nd->nd_flag |= ND_IMPLIEDCLID;
674 nd->nd_clientid.qval = clientid.qval;
676 stp->ls_stateid.other[2] = *tl++;
677 off = fxdr_hyper(tl);
680 lop->lo_end = off + reqlen;
682 * Paranoia, just in case it wraps around.
684 if (lop->lo_end < off)
685 lop->lo_end = NFS64BITSSET;
687 if (vnode_vtype(vp) != VREG) {
688 if (nd->nd_flag & ND_NFSV3)
689 nd->nd_repstat = EINVAL;
691 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
694 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
696 nd->nd_repstat = getret;
697 if (!nd->nd_repstat &&
698 (nva.na_uid != nd->nd_cred->cr_uid ||
699 NFSVNO_EXSTRICTACCESS(exp))) {
700 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
702 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
704 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
705 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
706 NFSACCCHK_VPISLOCKED, NULL);
708 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
709 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
710 &stateid, exp, nd, p);
711 if (nd->nd_repstat) {
713 if (nd->nd_flag & ND_NFSV3)
714 nfsrv_postopattr(nd, getret, &nva);
717 if (off >= nva.na_size) {
720 } else if (reqlen == 0)
722 else if ((off + reqlen) >= nva.na_size) {
723 cnt = nva.na_size - off;
729 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
731 if (!(nd->nd_flag & ND_NFSV4)) {
732 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
734 nd->nd_repstat = getret;
736 if (nd->nd_repstat) {
740 if (nd->nd_flag & ND_NFSV3)
741 nfsrv_postopattr(nd, getret, &nva);
746 if (nd->nd_flag & ND_NFSV2) {
747 nfsrv_fillattr(nd, &nva);
748 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
750 if (nd->nd_flag & ND_NFSV3) {
751 nfsrv_postopattr(nd, getret, &nva);
752 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
753 *tl++ = txdr_unsigned(cnt);
755 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
759 *tl++ = newnfs_false;
761 *tl = txdr_unsigned(cnt);
763 mbuf_setnext(nd->nd_mb, m3);
765 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
773 NFSEXITCODE2(error, nd);
781 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
782 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
787 struct nfsvattr nva, forat;
788 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
789 int stable = NFSWRITE_FILESYNC;
791 struct nfsstate st, *stp = &st;
792 struct nfslock lo, *lop = &lo;
793 nfsv4stateid_t stateid;
796 if (nd->nd_repstat) {
797 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
800 if (nd->nd_flag & ND_NFSV2) {
801 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
802 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
804 retlen = len = fxdr_unsigned(int32_t, *tl);
805 } else if (nd->nd_flag & ND_NFSV3) {
806 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
807 off = fxdr_hyper(tl);
809 stable = fxdr_unsigned(int, *tl++);
810 retlen = len = fxdr_unsigned(int32_t, *tl);
812 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
813 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
814 lop->lo_flags = NFSLCK_WRITE;
815 stp->ls_ownerlen = 0;
817 stp->ls_uid = nd->nd_cred->cr_uid;
818 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
819 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
820 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
821 if (nd->nd_flag & ND_IMPLIEDCLID) {
822 if (nd->nd_clientid.qval != clientid.qval)
823 printf("EEK! multiple clids\n");
825 nd->nd_flag |= ND_IMPLIEDCLID;
826 nd->nd_clientid.qval = clientid.qval;
828 stp->ls_stateid.other[2] = *tl++;
829 off = fxdr_hyper(tl);
832 stable = fxdr_unsigned(int, *tl++);
833 retlen = len = fxdr_unsigned(int32_t, *tl);
834 lop->lo_end = off + len;
836 * Paranoia, just in case it wraps around, which shouldn't
837 * ever happen anyhow.
839 if (lop->lo_end < lop->lo_first)
840 lop->lo_end = NFS64BITSSET;
844 * Loop through the mbuf chain, counting how many mbufs are a
845 * part of this write operation, so the iovec size is known.
849 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
865 if (retlen > NFS_MAXDATA || retlen < 0)
866 nd->nd_repstat = EIO;
867 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
868 if (nd->nd_flag & ND_NFSV3)
869 nd->nd_repstat = EINVAL;
871 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
874 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
876 nd->nd_repstat = forat_ret;
877 if (!nd->nd_repstat &&
878 (forat.na_uid != nd->nd_cred->cr_uid ||
879 NFSVNO_EXSTRICTACCESS(exp)))
880 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
882 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
883 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
884 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
885 &stateid, exp, nd, p);
887 if (nd->nd_repstat) {
889 if (nd->nd_flag & ND_NFSV3)
890 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
895 * For NFS Version 2, it is not obvious what a write of zero length
896 * should do, but I might as well be consistent with Version 3,
897 * which is to return ok so long as there are no permission problems.
900 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
901 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
902 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
904 panic("nfsrv_write mbuf");
906 if (nd->nd_flag & ND_NFSV4)
909 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
912 nd->nd_repstat = aftat_ret;
913 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
914 if (nd->nd_flag & ND_NFSV3)
915 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
918 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
919 *tl++ = txdr_unsigned(retlen);
921 * If nfs_async is set, then pretend the write was FILESYNC.
922 * Warning: Doing this violates RFC1813 and runs a risk
923 * of data written by a client being lost when the server
926 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
927 *tl++ = txdr_unsigned(stable);
929 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
931 * Actually, there is no need to txdr these fields,
932 * but it may make the values more human readable,
933 * for debugging purposes.
935 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
936 *tl = txdr_unsigned(nfsboottime.tv_usec);
937 } else if (!nd->nd_repstat)
938 nfsrv_fillattr(nd, &nva);
945 NFSEXITCODE2(error, nd);
950 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
951 * now does a truncate to 0 length via. setattr if it already exists
952 * The core creation routine has been extracted out into nfsrv_creatsub(),
953 * so it can also be used by nfsrv_open() for V4.
956 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
957 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
959 struct nfsvattr nva, dirfor, diraft;
960 struct nfsv2_sattr *sp;
961 struct nameidata named;
963 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
964 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
966 vnode_t vp = NULL, dirp = NULL;
971 int32_t cverf[2], tverf[2] = { 0, 0 };
973 if (nd->nd_repstat) {
974 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
977 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
978 LOCKPARENT | LOCKLEAF | SAVESTART);
979 nfsvno_setpathbuf(&named, &bufp, &hashp);
980 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
983 if (!nd->nd_repstat) {
984 NFSVNO_ATTRINIT(&nva);
985 if (nd->nd_flag & ND_NFSV2) {
986 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
987 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
990 NFSVNO_SETATTRVAL(&nva, type, vtyp);
991 NFSVNO_SETATTRVAL(&nva, mode,
992 nfstov_mode(sp->sa_mode));
993 switch (nva.na_type) {
995 tsize = fxdr_unsigned(int32_t, sp->sa_size);
997 NFSVNO_SETATTRVAL(&nva, size,
1003 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1010 how = fxdr_unsigned(int, *tl);
1012 case NFSCREATE_GUARDED:
1013 case NFSCREATE_UNCHECKED:
1014 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1018 case NFSCREATE_EXCLUSIVE:
1019 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1025 NFSVNO_SETATTRVAL(&nva, type, VREG);
1028 if (nd->nd_repstat) {
1029 nfsvno_relpathbuf(&named);
1030 if (nd->nd_flag & ND_NFSV3) {
1031 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1033 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1040 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1042 if (nd->nd_flag & ND_NFSV2) {
1046 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1050 if (nd->nd_repstat) {
1051 if (nd->nd_flag & ND_NFSV3)
1052 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1059 if (!(nd->nd_flag & ND_NFSV2)) {
1061 case NFSCREATE_GUARDED:
1063 nd->nd_repstat = EEXIST;
1065 case NFSCREATE_UNCHECKED:
1067 case NFSCREATE_EXCLUSIVE:
1068 if (named.ni_vp == NULL)
1069 NFSVNO_SETATTRVAL(&nva, mode, 0);
1075 * Iff doesn't exist, create it
1076 * otherwise just truncate to 0 length
1077 * should I set the mode too ?
1079 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1080 &exclusive_flag, cverf, rdev, p, exp);
1082 if (!nd->nd_repstat) {
1083 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1084 if (!nd->nd_repstat)
1085 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1088 if (!nd->nd_repstat) {
1089 tverf[0] = nva.na_atime.tv_sec;
1090 tverf[1] = nva.na_atime.tv_nsec;
1093 if (nd->nd_flag & ND_NFSV2) {
1094 if (!nd->nd_repstat) {
1095 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1096 nfsrv_fillattr(nd, &nva);
1099 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1100 || cverf[1] != tverf[1]))
1101 nd->nd_repstat = EEXIST;
1102 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1104 if (!nd->nd_repstat) {
1105 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1106 nfsrv_postopattr(nd, 0, &nva);
1108 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1112 NFSEXITCODE2(0, nd);
1116 nfsvno_relpathbuf(&named);
1117 NFSEXITCODE2(error, nd);
1122 * nfs v3 mknod service (and v4 create)
1125 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1126 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1127 struct nfsexstuff *exp)
1129 struct nfsvattr nva, dirfor, diraft;
1131 struct nameidata named;
1132 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1133 u_int32_t major, minor;
1134 enum vtype vtyp = VNON;
1135 nfstype nfs4type = NFNON;
1136 vnode_t vp, dirp = NULL;
1137 nfsattrbit_t attrbits;
1138 char *bufp = NULL, *pathcp = NULL;
1139 u_long *hashp, cnflags;
1140 NFSACL_T *aclp = NULL;
1142 NFSVNO_ATTRINIT(&nva);
1143 cnflags = (LOCKPARENT | SAVESTART);
1144 if (nd->nd_repstat) {
1145 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1148 #ifdef NFS4_ACL_EXTATTR_NAME
1149 aclp = acl_alloc(M_WAITOK);
1154 * For V4, the creation stuff is here, Yuck!
1156 if (nd->nd_flag & ND_NFSV4) {
1157 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1158 vtyp = nfsv34tov_type(*tl);
1159 nfs4type = fxdr_unsigned(nfstype, *tl);
1162 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1169 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1170 major = fxdr_unsigned(u_int32_t, *tl++);
1171 minor = fxdr_unsigned(u_int32_t, *tl);
1172 nva.na_rdev = NFSMAKEDEV(major, minor);
1178 cnflags = (LOCKPARENT | SAVENAME);
1181 nd->nd_repstat = NFSERR_BADTYPE;
1183 #ifdef NFS4_ACL_EXTATTR_NAME
1189 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1190 nfsvno_setpathbuf(&named, &bufp, &hashp);
1191 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1194 if (!nd->nd_repstat) {
1195 if (nd->nd_flag & ND_NFSV3) {
1196 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1197 vtyp = nfsv34tov_type(*tl);
1199 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1203 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1204 (vtyp == VCHR || vtyp == VBLK)) {
1205 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1206 major = fxdr_unsigned(u_int32_t, *tl++);
1207 minor = fxdr_unsigned(u_int32_t, *tl);
1208 nva.na_rdev = NFSMAKEDEV(major, minor);
1212 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1213 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1214 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1215 dirfor.na_gid == nva.na_gid)
1216 NFSVNO_UNSET(&nva, gid);
1217 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1219 if (nd->nd_repstat) {
1221 #ifdef NFS4_ACL_EXTATTR_NAME
1224 nfsvno_relpathbuf(&named);
1226 FREE(pathcp, M_TEMP);
1227 if (nd->nd_flag & ND_NFSV3)
1228 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1234 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1235 * in va_mode, so we'll have to set a default here.
1237 if (NFSVNO_NOTSETMODE(&nva)) {
1245 named.ni_cnd.cn_flags |= WILLBEDIR;
1246 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1247 if (nd->nd_repstat) {
1249 if (nd->nd_flag & ND_NFSV3)
1250 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1254 #ifdef NFS4_ACL_EXTATTR_NAME
1257 if (nd->nd_flag & ND_NFSV3)
1258 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1263 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1265 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1267 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1268 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1270 #ifdef NFS4_ACL_EXTATTR_NAME
1274 } else if (vtyp == VLNK) {
1275 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1276 &dirfor, &diraft, &diraft_ret, &attrbits,
1277 aclp, p, exp, pathcp, pathlen);
1278 #ifdef NFS4_ACL_EXTATTR_NAME
1281 FREE(pathcp, M_TEMP);
1286 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1287 if (!nd->nd_repstat) {
1289 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1290 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1291 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1292 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1294 if (vpp != NULL && nd->nd_repstat == 0) {
1295 NFSVOPUNLOCK(vp, 0);
1301 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1303 if (!nd->nd_repstat) {
1304 if (nd->nd_flag & ND_NFSV3) {
1305 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1306 nfsrv_postopattr(nd, 0, &nva);
1308 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1309 *tl++ = newnfs_false;
1310 txdr_hyper(dirfor.na_filerev, tl);
1312 txdr_hyper(diraft.na_filerev, tl);
1313 (void) nfsrv_putattrbit(nd, &attrbits);
1316 if (nd->nd_flag & ND_NFSV3)
1317 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1318 #ifdef NFS4_ACL_EXTATTR_NAME
1323 NFSEXITCODE2(0, nd);
1327 #ifdef NFS4_ACL_EXTATTR_NAME
1331 nfsvno_relpathbuf(&named);
1333 FREE(pathcp, M_TEMP);
1335 NFSEXITCODE2(error, nd);
1340 * nfs remove service
1343 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1344 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1346 struct nameidata named;
1348 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1349 vnode_t dirp = NULL;
1350 struct nfsvattr dirfor, diraft;
1354 if (nd->nd_repstat) {
1355 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1358 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1359 LOCKPARENT | LOCKLEAF);
1360 nfsvno_setpathbuf(&named, &bufp, &hashp);
1361 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1364 nfsvno_relpathbuf(&named);
1367 if (!nd->nd_repstat) {
1368 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1371 nfsvno_relpathbuf(&named);
1374 if (!(nd->nd_flag & ND_NFSV2)) {
1375 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1382 if (!nd->nd_repstat) {
1383 if (nd->nd_flag & ND_NFSV4) {
1384 if (vnode_vtype(named.ni_vp) == VDIR)
1385 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1386 nd->nd_cred, p, exp);
1388 nd->nd_repstat = nfsvno_removesub(&named, 1,
1389 nd->nd_cred, p, exp);
1390 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1391 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1392 nd->nd_cred, p, exp);
1394 nd->nd_repstat = nfsvno_removesub(&named, 0,
1395 nd->nd_cred, p, exp);
1398 if (!(nd->nd_flag & ND_NFSV2)) {
1400 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1404 if (nd->nd_flag & ND_NFSV3) {
1405 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1407 } else if (!nd->nd_repstat) {
1408 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1409 *tl++ = newnfs_false;
1410 txdr_hyper(dirfor.na_filerev, tl);
1412 txdr_hyper(diraft.na_filerev, tl);
1417 NFSEXITCODE2(error, nd);
1422 * nfs rename service
1425 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1426 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1427 struct nfsexstuff *toexp)
1430 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1431 int tdirfor_ret = 1, tdiraft_ret = 1;
1432 struct nameidata fromnd, tond;
1433 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1434 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1435 struct nfsexstuff tnes;
1437 char *bufp, *tbufp = NULL;
1441 if (nd->nd_repstat) {
1442 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1443 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1446 if (!(nd->nd_flag & ND_NFSV2))
1447 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1448 tond.ni_cnd.cn_nameiop = 0;
1449 tond.ni_startdir = NULL;
1450 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1451 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1452 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1457 nfsvno_relpathbuf(&fromnd);
1460 if (nd->nd_flag & ND_NFSV4) {
1463 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1465 tfh.nfsrvfh_len = 0;
1466 error = nfsrv_mtofh(nd, &tfh);
1468 error = nfsvno_getfh(dp, &fh, p);
1471 /* todp is always NULL except NFSv4 */
1472 nfsvno_relpathbuf(&fromnd);
1476 /* If this is the same file handle, just VREF() the vnode. */
1477 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1478 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1482 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1485 nd->nd_cred->cr_uid = nd->nd_saveduid;
1486 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1489 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1491 NFSVOPUNLOCK(tdp, 0);
1495 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1496 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1497 if (!nd->nd_repstat) {
1498 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1503 nfsvno_relpathbuf(&fromnd);
1504 nfsvno_relpathbuf(&tond);
1508 if (nd->nd_repstat) {
1509 if (nd->nd_flag & ND_NFSV3) {
1510 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1512 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1518 nfsvno_relpathbuf(&fromnd);
1519 nfsvno_relpathbuf(&tond);
1524 * Done parsing, now down to business.
1526 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1527 if (nd->nd_repstat) {
1528 if (nd->nd_flag & ND_NFSV3) {
1529 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1531 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1538 nfsvno_relpathbuf(&tond);
1541 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1542 tond.ni_cnd.cn_flags |= WILLBEDIR;
1543 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1544 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1545 nd->nd_flag, nd->nd_cred, p);
1547 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1550 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1556 if (nd->nd_flag & ND_NFSV3) {
1557 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1558 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1559 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1560 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1561 *tl++ = newnfs_false;
1562 txdr_hyper(fdirfor.na_filerev, tl);
1564 txdr_hyper(fdiraft.na_filerev, tl);
1566 *tl++ = newnfs_false;
1567 txdr_hyper(tdirfor.na_filerev, tl);
1569 txdr_hyper(tdiraft.na_filerev, tl);
1573 NFSEXITCODE2(error, nd);
1581 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1582 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1583 struct nfsexstuff *toexp)
1585 struct nameidata named;
1587 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1588 vnode_t dirp = NULL, dp = NULL;
1589 struct nfsvattr dirfor, diraft, at;
1590 struct nfsexstuff tnes;
1595 if (nd->nd_repstat) {
1596 nfsrv_postopattr(nd, getret, &at);
1597 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1600 NFSVOPUNLOCK(vp, 0);
1601 if (vnode_vtype(vp) == VDIR) {
1602 if (nd->nd_flag & ND_NFSV4)
1603 nd->nd_repstat = NFSERR_ISDIR;
1605 nd->nd_repstat = NFSERR_INVAL;
1608 } else if (vnode_vtype(vp) == VLNK) {
1609 if (nd->nd_flag & ND_NFSV2)
1610 nd->nd_repstat = NFSERR_INVAL;
1612 nd->nd_repstat = NFSERR_NOTSUPP;
1616 if (!nd->nd_repstat) {
1617 if (nd->nd_flag & ND_NFSV4) {
1621 error = nfsrv_mtofh(nd, &dfh);
1624 /* tovp is always NULL unless NFSv4 */
1627 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1630 NFSVOPUNLOCK(dp, 0);
1633 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1634 LOCKPARENT | SAVENAME);
1635 if (!nd->nd_repstat) {
1636 nfsvno_setpathbuf(&named, &bufp, &hashp);
1637 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1642 nfsvno_relpathbuf(&named);
1645 if (!nd->nd_repstat) {
1646 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1651 nfsvno_relpathbuf(&named);
1655 if (nd->nd_flag & ND_NFSV2) {
1659 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1663 if (!nd->nd_repstat)
1664 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1665 if (nd->nd_flag & ND_NFSV3)
1666 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1668 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1672 if (nd->nd_flag & ND_NFSV3) {
1673 nfsrv_postopattr(nd, getret, &at);
1674 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1675 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1676 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1677 *tl++ = newnfs_false;
1678 txdr_hyper(dirfor.na_filerev, tl);
1680 txdr_hyper(diraft.na_filerev, tl);
1684 NFSEXITCODE2(error, nd);
1689 * nfs symbolic link service
1692 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1693 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1694 struct nfsexstuff *exp)
1696 struct nfsvattr nva, dirfor, diraft;
1697 struct nameidata named;
1698 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1699 vnode_t dirp = NULL;
1700 char *bufp, *pathcp = NULL;
1703 if (nd->nd_repstat) {
1704 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1709 NFSVNO_ATTRINIT(&nva);
1710 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1711 LOCKPARENT | SAVESTART);
1712 nfsvno_setpathbuf(&named, &bufp, &hashp);
1713 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1714 if (!error && !nd->nd_repstat)
1715 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1718 nfsvno_relpathbuf(&named);
1721 if (!nd->nd_repstat) {
1722 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1725 nfsvno_relpathbuf(&named);
1727 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1733 * And call nfsrvd_symlinksub() to do the common code. It will
1734 * return EBADRPC upon a parsing error, 0 otherwise.
1736 if (!nd->nd_repstat) {
1738 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1740 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1741 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1743 } else if (dirp != NULL) {
1744 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1748 FREE(pathcp, M_TEMP);
1750 if (nd->nd_flag & ND_NFSV3) {
1751 if (!nd->nd_repstat) {
1752 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1753 nfsrv_postopattr(nd, 0, &nva);
1755 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1759 NFSEXITCODE2(error, nd);
1764 * Common code for creating a symbolic link.
1767 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1768 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1769 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1770 int *diraft_retp, nfsattrbit_t *attrbitp,
1771 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1776 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1777 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1778 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1779 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1780 if (nd->nd_flag & ND_NFSV3) {
1781 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1782 if (!nd->nd_repstat)
1783 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1784 nvap, nd->nd_cred, p, 1);
1786 if (vpp != NULL && nd->nd_repstat == 0) {
1787 NFSVOPUNLOCK(ndp->ni_vp, 0);
1793 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1796 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1797 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1798 *tl++ = newnfs_false;
1799 txdr_hyper(dirforp->na_filerev, tl);
1801 txdr_hyper(diraftp->na_filerev, tl);
1802 (void) nfsrv_putattrbit(nd, attrbitp);
1805 NFSEXITCODE2(0, nd);
1812 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1813 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1814 struct nfsexstuff *exp)
1816 struct nfsvattr nva, dirfor, diraft;
1817 struct nameidata named;
1819 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1820 vnode_t dirp = NULL;
1824 if (nd->nd_repstat) {
1825 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1828 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1829 LOCKPARENT | SAVENAME);
1830 nfsvno_setpathbuf(&named, &bufp, &hashp);
1831 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1834 if (!nd->nd_repstat) {
1835 NFSVNO_ATTRINIT(&nva);
1836 if (nd->nd_flag & ND_NFSV3) {
1837 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1841 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1842 nva.na_mode = nfstov_mode(*tl++);
1845 if (!nd->nd_repstat) {
1846 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1849 nfsvno_relpathbuf(&named);
1851 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1855 if (nd->nd_repstat) {
1857 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1861 if (nd->nd_flag & ND_NFSV3)
1862 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1867 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1870 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1872 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1873 &diraft_ret, NULL, NULL, p, exp);
1875 if (nd->nd_flag & ND_NFSV3) {
1876 if (!nd->nd_repstat) {
1877 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1878 nfsrv_postopattr(nd, 0, &nva);
1880 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1881 } else if (!nd->nd_repstat) {
1882 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1883 nfsrv_fillattr(nd, &nva);
1887 NFSEXITCODE2(0, nd);
1891 nfsvno_relpathbuf(&named);
1892 NFSEXITCODE2(error, nd);
1897 * Code common to mkdir for V2,3 and 4.
1900 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1901 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1902 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1903 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1904 NFSPROC_T *p, struct nfsexstuff *exp)
1909 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1910 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1911 nd->nd_cred, p, exp);
1912 if (!nd->nd_repstat) {
1914 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1915 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1916 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1917 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1919 if (vpp && !nd->nd_repstat) {
1920 NFSVOPUNLOCK(vp, 0);
1927 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1930 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1931 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1932 *tl++ = newnfs_false;
1933 txdr_hyper(dirforp->na_filerev, tl);
1935 txdr_hyper(diraftp->na_filerev, tl);
1936 (void) nfsrv_putattrbit(nd, attrbitp);
1939 NFSEXITCODE2(0, nd);
1943 * nfs commit service
1946 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1947 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1949 struct nfsvattr bfor, aft;
1951 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1954 if (nd->nd_repstat) {
1955 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1958 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1960 * XXX At this time VOP_FSYNC() does not accept offset and byte
1961 * count parameters, so these arguments are useless (someday maybe).
1963 off = fxdr_hyper(tl);
1965 cnt = fxdr_unsigned(int, *tl);
1966 if (nd->nd_flag & ND_NFSV3)
1967 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1968 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1969 if (nd->nd_flag & ND_NFSV3) {
1970 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1971 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1974 if (!nd->nd_repstat) {
1975 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1976 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1977 *tl = txdr_unsigned(nfsboottime.tv_usec);
1981 NFSEXITCODE2(0, nd);
1985 NFSEXITCODE2(error, nd);
1990 * nfs statfs service
1993 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1994 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2003 if (nd->nd_repstat) {
2004 nfsrv_postopattr(nd, getret, &at);
2008 nd->nd_repstat = nfsvno_statfs(vp, sf);
2009 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2011 if (nd->nd_flag & ND_NFSV3)
2012 nfsrv_postopattr(nd, getret, &at);
2015 if (nd->nd_flag & ND_NFSV2) {
2016 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2017 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2018 *tl++ = txdr_unsigned(sf->f_bsize);
2019 *tl++ = txdr_unsigned(sf->f_blocks);
2020 *tl++ = txdr_unsigned(sf->f_bfree);
2021 *tl = txdr_unsigned(sf->f_bavail);
2023 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2024 tval = (u_quad_t)sf->f_blocks;
2025 tval *= (u_quad_t)sf->f_bsize;
2026 txdr_hyper(tval, tl); tl += 2;
2027 tval = (u_quad_t)sf->f_bfree;
2028 tval *= (u_quad_t)sf->f_bsize;
2029 txdr_hyper(tval, tl); tl += 2;
2030 tval = (u_quad_t)sf->f_bavail;
2031 tval *= (u_quad_t)sf->f_bsize;
2032 txdr_hyper(tval, tl); tl += 2;
2033 tval = (u_quad_t)sf->f_files;
2034 txdr_hyper(tval, tl); tl += 2;
2035 tval = (u_quad_t)sf->f_ffree;
2036 txdr_hyper(tval, tl); tl += 2;
2037 tval = (u_quad_t)sf->f_ffree;
2038 txdr_hyper(tval, tl); tl += 2;
2043 NFSEXITCODE2(0, nd);
2048 * nfs fsinfo service
2051 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2052 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2055 struct nfsfsinfo fs;
2059 if (nd->nd_repstat) {
2060 nfsrv_postopattr(nd, getret, &at);
2063 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2064 nfsvno_getfs(&fs, isdgram);
2066 nfsrv_postopattr(nd, getret, &at);
2067 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2068 *tl++ = txdr_unsigned(fs.fs_rtmax);
2069 *tl++ = txdr_unsigned(fs.fs_rtpref);
2070 *tl++ = txdr_unsigned(fs.fs_rtmult);
2071 *tl++ = txdr_unsigned(fs.fs_wtmax);
2072 *tl++ = txdr_unsigned(fs.fs_wtpref);
2073 *tl++ = txdr_unsigned(fs.fs_wtmult);
2074 *tl++ = txdr_unsigned(fs.fs_dtpref);
2075 txdr_hyper(fs.fs_maxfilesize, tl);
2077 txdr_nfsv3time(&fs.fs_timedelta, tl);
2079 *tl = txdr_unsigned(fs.fs_properties);
2082 NFSEXITCODE2(0, nd);
2087 * nfs pathconf service
2090 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2091 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2093 struct nfsv3_pathconf *pc;
2095 register_t linkmax, namemax, chownres, notrunc;
2098 if (nd->nd_repstat) {
2099 nfsrv_postopattr(nd, getret, &at);
2102 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2104 if (!nd->nd_repstat)
2105 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2107 if (!nd->nd_repstat)
2108 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2109 &chownres, nd->nd_cred, p);
2110 if (!nd->nd_repstat)
2111 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2113 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2115 nfsrv_postopattr(nd, getret, &at);
2116 if (!nd->nd_repstat) {
2117 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2118 pc->pc_linkmax = txdr_unsigned(linkmax);
2119 pc->pc_namemax = txdr_unsigned(namemax);
2120 pc->pc_notrunc = txdr_unsigned(notrunc);
2121 pc->pc_chownrestricted = txdr_unsigned(chownres);
2124 * These should probably be supported by VOP_PATHCONF(), but
2125 * until msdosfs is exportable (why would you want to?), the
2126 * Unix defaults should be ok.
2128 pc->pc_caseinsensitive = newnfs_false;
2129 pc->pc_casepreserving = newnfs_true;
2133 NFSEXITCODE2(0, nd);
2138 * nfsv4 lock service
2141 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2142 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2146 struct nfsstate *stp = NULL;
2147 struct nfslock *lop;
2148 struct nfslockconflict cf;
2150 u_short flags = NFSLCK_LOCK, lflags;
2151 u_int64_t offset, len;
2152 nfsv4stateid_t stateid;
2155 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2156 i = fxdr_unsigned(int, *tl++);
2158 case NFSV4LOCKT_READW:
2159 flags |= NFSLCK_BLOCKING;
2160 case NFSV4LOCKT_READ:
2161 lflags = NFSLCK_READ;
2163 case NFSV4LOCKT_WRITEW:
2164 flags |= NFSLCK_BLOCKING;
2165 case NFSV4LOCKT_WRITE:
2166 lflags = NFSLCK_WRITE;
2169 nd->nd_repstat = NFSERR_BADXDR;
2172 if (*tl++ == newnfs_true)
2173 flags |= NFSLCK_RECLAIM;
2174 offset = fxdr_hyper(tl);
2176 len = fxdr_hyper(tl);
2178 if (*tl == newnfs_true)
2179 flags |= NFSLCK_OPENTOLOCK;
2180 if (flags & NFSLCK_OPENTOLOCK) {
2181 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2182 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2183 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2184 nd->nd_repstat = NFSERR_BADXDR;
2187 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2188 M_NFSDSTATE, M_WAITOK);
2189 stp->ls_ownerlen = i;
2190 stp->ls_op = nd->nd_rp;
2191 stp->ls_seq = fxdr_unsigned(int, *tl++);
2192 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2193 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2195 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2196 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2197 clientid.lval[0] = *tl++;
2198 clientid.lval[1] = *tl++;
2199 if (nd->nd_flag & ND_IMPLIEDCLID) {
2200 if (nd->nd_clientid.qval != clientid.qval)
2201 printf("EEK! multiple clids\n");
2203 nd->nd_flag |= ND_IMPLIEDCLID;
2204 nd->nd_clientid.qval = clientid.qval;
2206 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2210 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2211 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2212 M_NFSDSTATE, M_WAITOK);
2213 stp->ls_ownerlen = 0;
2214 stp->ls_op = nd->nd_rp;
2215 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2216 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2218 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2219 stp->ls_seq = fxdr_unsigned(int, *tl);
2220 clientid.lval[0] = stp->ls_stateid.other[0];
2221 clientid.lval[1] = stp->ls_stateid.other[1];
2222 if (nd->nd_flag & ND_IMPLIEDCLID) {
2223 if (nd->nd_clientid.qval != clientid.qval)
2224 printf("EEK! multiple clids\n");
2226 nd->nd_flag |= ND_IMPLIEDCLID;
2227 nd->nd_clientid.qval = clientid.qval;
2230 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2231 M_NFSDLOCK, M_WAITOK);
2232 lop->lo_first = offset;
2233 if (len == NFS64BITSSET) {
2234 lop->lo_end = NFS64BITSSET;
2236 lop->lo_end = offset + len;
2237 if (lop->lo_end <= lop->lo_first)
2238 nd->nd_repstat = NFSERR_INVAL;
2240 lop->lo_flags = lflags;
2241 stp->ls_flags = flags;
2242 stp->ls_uid = nd->nd_cred->cr_uid;
2245 * Do basic access checking.
2247 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2248 if (vnode_vtype(vp) == VDIR)
2249 nd->nd_repstat = NFSERR_ISDIR;
2251 nd->nd_repstat = NFSERR_INVAL;
2253 if (!nd->nd_repstat) {
2254 if (lflags & NFSLCK_WRITE) {
2255 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2256 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2257 NFSACCCHK_VPISLOCKED, NULL);
2259 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2260 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2261 NFSACCCHK_VPISLOCKED, NULL);
2263 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2264 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2265 NFSACCCHK_VPISLOCKED, NULL);
2270 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2271 * seqid# gets updated. nfsrv_lockctrl() will return the value
2272 * of nd_repstat, if it gets that far.
2274 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2275 &stateid, exp, nd, p);
2277 FREE((caddr_t)lop, M_NFSDLOCK);
2279 FREE((caddr_t)stp, M_NFSDSTATE);
2280 if (!nd->nd_repstat) {
2281 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2282 *tl++ = txdr_unsigned(stateid.seqid);
2283 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2284 } else if (nd->nd_repstat == NFSERR_DENIED) {
2285 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2286 txdr_hyper(cf.cl_first, tl);
2288 if (cf.cl_end == NFS64BITSSET)
2291 len = cf.cl_end - cf.cl_first;
2292 txdr_hyper(len, tl);
2294 if (cf.cl_flags == NFSLCK_WRITE)
2295 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2297 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2298 *tl++ = stateid.other[0];
2299 *tl = stateid.other[1];
2300 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2303 NFSEXITCODE2(0, nd);
2308 free((caddr_t)stp, M_NFSDSTATE);
2309 NFSEXITCODE2(error, nd);
2314 * nfsv4 lock test service
2317 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2318 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2322 struct nfsstate *stp = NULL;
2323 struct nfslock lo, *lop = &lo;
2324 struct nfslockconflict cf;
2326 nfsv4stateid_t stateid;
2330 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2331 i = fxdr_unsigned(int, *(tl + 7));
2332 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2333 nd->nd_repstat = NFSERR_BADXDR;
2336 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2337 M_NFSDSTATE, M_WAITOK);
2338 stp->ls_ownerlen = i;
2340 stp->ls_flags = NFSLCK_TEST;
2341 stp->ls_uid = nd->nd_cred->cr_uid;
2342 i = fxdr_unsigned(int, *tl++);
2344 case NFSV4LOCKT_READW:
2345 stp->ls_flags |= NFSLCK_BLOCKING;
2346 case NFSV4LOCKT_READ:
2347 lo.lo_flags = NFSLCK_READ;
2349 case NFSV4LOCKT_WRITEW:
2350 stp->ls_flags |= NFSLCK_BLOCKING;
2351 case NFSV4LOCKT_WRITE:
2352 lo.lo_flags = NFSLCK_WRITE;
2355 nd->nd_repstat = NFSERR_BADXDR;
2358 lo.lo_first = fxdr_hyper(tl);
2360 len = fxdr_hyper(tl);
2361 if (len == NFS64BITSSET) {
2362 lo.lo_end = NFS64BITSSET;
2364 lo.lo_end = lo.lo_first + len;
2365 if (lo.lo_end <= lo.lo_first)
2366 nd->nd_repstat = NFSERR_INVAL;
2369 clientid.lval[0] = *tl++;
2370 clientid.lval[1] = *tl;
2371 if (nd->nd_flag & ND_IMPLIEDCLID) {
2372 if (nd->nd_clientid.qval != clientid.qval)
2373 printf("EEK! multiple clids\n");
2375 nd->nd_flag |= ND_IMPLIEDCLID;
2376 nd->nd_clientid.qval = clientid.qval;
2378 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2381 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2382 if (vnode_vtype(vp) == VDIR)
2383 nd->nd_repstat = NFSERR_ISDIR;
2385 nd->nd_repstat = NFSERR_INVAL;
2387 if (!nd->nd_repstat)
2388 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2389 &stateid, exp, nd, p);
2391 FREE((caddr_t)stp, M_NFSDSTATE);
2392 if (nd->nd_repstat) {
2393 if (nd->nd_repstat == NFSERR_DENIED) {
2394 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2395 txdr_hyper(cf.cl_first, tl);
2397 if (cf.cl_end == NFS64BITSSET)
2400 len = cf.cl_end - cf.cl_first;
2401 txdr_hyper(len, tl);
2403 if (cf.cl_flags == NFSLCK_WRITE)
2404 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2406 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2407 *tl++ = stp->ls_stateid.other[0];
2408 *tl = stp->ls_stateid.other[1];
2409 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2413 NFSEXITCODE2(0, nd);
2418 free((caddr_t)stp, M_NFSDSTATE);
2419 NFSEXITCODE2(error, nd);
2424 * nfsv4 unlock service
2427 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2428 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2432 struct nfsstate *stp;
2433 struct nfslock *lop;
2435 nfsv4stateid_t stateid;
2439 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2440 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2441 M_NFSDSTATE, M_WAITOK);
2442 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2443 M_NFSDLOCK, M_WAITOK);
2444 stp->ls_flags = NFSLCK_UNLOCK;
2445 lop->lo_flags = NFSLCK_UNLOCK;
2446 stp->ls_op = nd->nd_rp;
2447 i = fxdr_unsigned(int, *tl++);
2449 case NFSV4LOCKT_READW:
2450 stp->ls_flags |= NFSLCK_BLOCKING;
2451 case NFSV4LOCKT_READ:
2453 case NFSV4LOCKT_WRITEW:
2454 stp->ls_flags |= NFSLCK_BLOCKING;
2455 case NFSV4LOCKT_WRITE:
2458 nd->nd_repstat = NFSERR_BADXDR;
2459 free(stp, M_NFSDSTATE);
2460 free(lop, M_NFSDLOCK);
2463 stp->ls_ownerlen = 0;
2464 stp->ls_uid = nd->nd_cred->cr_uid;
2465 stp->ls_seq = fxdr_unsigned(int, *tl++);
2466 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2467 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2469 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2470 lop->lo_first = fxdr_hyper(tl);
2472 len = fxdr_hyper(tl);
2473 if (len == NFS64BITSSET) {
2474 lop->lo_end = NFS64BITSSET;
2476 lop->lo_end = lop->lo_first + len;
2477 if (lop->lo_end <= lop->lo_first)
2478 nd->nd_repstat = NFSERR_INVAL;
2480 clientid.lval[0] = stp->ls_stateid.other[0];
2481 clientid.lval[1] = stp->ls_stateid.other[1];
2482 if (nd->nd_flag & ND_IMPLIEDCLID) {
2483 if (nd->nd_clientid.qval != clientid.qval)
2484 printf("EEK! multiple clids\n");
2486 nd->nd_flag |= ND_IMPLIEDCLID;
2487 nd->nd_clientid.qval = clientid.qval;
2489 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2490 if (vnode_vtype(vp) == VDIR)
2491 nd->nd_repstat = NFSERR_ISDIR;
2493 nd->nd_repstat = NFSERR_INVAL;
2496 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2497 * seqid# gets incremented. nfsrv_lockctrl() will return the
2498 * value of nd_repstat, if it gets that far.
2500 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2501 &stateid, exp, nd, p);
2503 FREE((caddr_t)stp, M_NFSDSTATE);
2505 free((caddr_t)lop, M_NFSDLOCK);
2506 if (!nd->nd_repstat) {
2507 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2508 *tl++ = txdr_unsigned(stateid.seqid);
2509 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2513 NFSEXITCODE2(error, nd);
2518 * nfsv4 open service
2521 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2522 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2523 struct nfsexstuff *exp)
2527 struct nfsstate *stp = NULL;
2528 int error = 0, create, claim, exclusive_flag = 0;
2529 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2530 int how = NFSCREATE_UNCHECKED;
2531 int32_t cverf[2], tverf[2] = { 0, 0 };
2532 vnode_t vp = NULL, dirp = NULL;
2533 struct nfsvattr nva, dirfor, diraft;
2534 struct nameidata named;
2535 nfsv4stateid_t stateid, delegstateid;
2536 nfsattrbit_t attrbits;
2540 NFSACL_T *aclp = NULL;
2542 #ifdef NFS4_ACL_EXTATTR_NAME
2543 aclp = acl_alloc(M_WAITOK);
2546 NFSZERO_ATTRBIT(&attrbits);
2547 named.ni_startdir = NULL;
2548 named.ni_cnd.cn_nameiop = 0;
2549 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2550 i = fxdr_unsigned(int, *(tl + 5));
2551 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2552 nd->nd_repstat = NFSERR_BADXDR;
2555 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2556 M_NFSDSTATE, M_WAITOK);
2557 stp->ls_ownerlen = i;
2558 stp->ls_op = nd->nd_rp;
2559 stp->ls_flags = NFSLCK_OPEN;
2560 stp->ls_uid = nd->nd_cred->cr_uid;
2561 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2562 i = fxdr_unsigned(int, *tl++);
2564 case NFSV4OPEN_ACCESSREAD:
2565 stp->ls_flags |= NFSLCK_READACCESS;
2567 case NFSV4OPEN_ACCESSWRITE:
2568 stp->ls_flags |= NFSLCK_WRITEACCESS;
2570 case NFSV4OPEN_ACCESSBOTH:
2571 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2574 nd->nd_repstat = NFSERR_INVAL;
2576 i = fxdr_unsigned(int, *tl++);
2578 case NFSV4OPEN_DENYNONE:
2580 case NFSV4OPEN_DENYREAD:
2581 stp->ls_flags |= NFSLCK_READDENY;
2583 case NFSV4OPEN_DENYWRITE:
2584 stp->ls_flags |= NFSLCK_WRITEDENY;
2586 case NFSV4OPEN_DENYBOTH:
2587 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2590 nd->nd_repstat = NFSERR_INVAL;
2592 clientid.lval[0] = *tl++;
2593 clientid.lval[1] = *tl;
2594 if (nd->nd_flag & ND_IMPLIEDCLID) {
2595 if (nd->nd_clientid.qval != clientid.qval)
2596 printf("EEK! multiple clids\n");
2598 nd->nd_flag |= ND_IMPLIEDCLID;
2599 nd->nd_clientid.qval = clientid.qval;
2601 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2604 NFSVNO_ATTRINIT(&nva);
2605 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2606 create = fxdr_unsigned(int, *tl);
2607 if (!nd->nd_repstat)
2608 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2609 if (create == NFSV4OPEN_CREATE) {
2612 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2613 how = fxdr_unsigned(int, *tl);
2615 case NFSCREATE_UNCHECKED:
2616 case NFSCREATE_GUARDED:
2617 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2621 * If the na_gid being set is the same as that of
2622 * the directory it is going in, clear it, since
2623 * that is what will be set by default. This allows
2624 * a user that isn't in that group to do the create.
2626 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2627 nva.na_gid == dirfor.na_gid)
2628 NFSVNO_UNSET(&nva, gid);
2629 if (!nd->nd_repstat)
2630 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2632 case NFSCREATE_EXCLUSIVE:
2633 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2638 nd->nd_repstat = NFSERR_BADXDR;
2641 } else if (create != NFSV4OPEN_NOCREATE) {
2642 nd->nd_repstat = NFSERR_BADXDR;
2647 * Now, handle the claim, which usually includes looking up a
2648 * name in the directory referenced by dp. The exception is
2649 * NFSV4OPEN_CLAIMPREVIOUS.
2651 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2652 claim = fxdr_unsigned(int, *tl);
2653 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2654 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2655 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2656 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2657 stp->ls_flags |= NFSLCK_DELEGCUR;
2658 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2659 stp->ls_flags |= NFSLCK_DELEGPREV;
2661 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2662 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2663 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2664 claim != NFSV4OPEN_CLAIMNULL)
2665 nd->nd_repstat = NFSERR_INVAL;
2666 if (nd->nd_repstat) {
2667 nd->nd_repstat = nfsrv_opencheck(clientid,
2668 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2671 if (create == NFSV4OPEN_CREATE)
2672 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2673 LOCKPARENT | LOCKLEAF | SAVESTART);
2675 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2676 LOCKLEAF | SAVESTART);
2677 nfsvno_setpathbuf(&named, &bufp, &hashp);
2678 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2681 #ifdef NFS4_ACL_EXTATTR_NAME
2684 FREE((caddr_t)stp, M_NFSDSTATE);
2685 nfsvno_relpathbuf(&named);
2686 NFSEXITCODE2(error, nd);
2689 if (!nd->nd_repstat) {
2690 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2694 nfsvno_relpathbuf(&named);
2696 if (create == NFSV4OPEN_CREATE) {
2698 case NFSCREATE_UNCHECKED:
2701 * Clear the setable attribute bits, except
2702 * for Size, if it is being truncated.
2704 NFSZERO_ATTRBIT(&attrbits);
2705 if (NFSVNO_ISSETSIZE(&nva))
2706 NFSSETBIT_ATTRBIT(&attrbits,
2710 case NFSCREATE_GUARDED:
2711 if (named.ni_vp && !nd->nd_repstat)
2712 nd->nd_repstat = EEXIST;
2714 case NFSCREATE_EXCLUSIVE:
2720 nfsvno_open(nd, &named, clientid, &stateid, stp,
2721 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2722 nd->nd_cred, p, exp, &vp);
2723 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2724 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2725 i = fxdr_unsigned(int, *tl);
2727 case NFSV4OPEN_DELEGATEREAD:
2728 stp->ls_flags |= NFSLCK_DELEGREAD;
2730 case NFSV4OPEN_DELEGATEWRITE:
2731 stp->ls_flags |= NFSLCK_DELEGWRITE;
2732 case NFSV4OPEN_DELEGATENONE:
2735 nd->nd_repstat = NFSERR_BADXDR;
2738 stp->ls_flags |= NFSLCK_RECLAIM;
2740 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2741 if ((vp->v_iflag & VI_DOOMED) == 0)
2742 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2743 stp, vp, nd, p, nd->nd_repstat);
2745 nd->nd_repstat = NFSERR_PERM;
2747 nd->nd_repstat = NFSERR_BADXDR;
2752 * Do basic access checking.
2754 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2756 * The IETF working group decided that this is the correct
2757 * error return for all non-regular files.
2759 nd->nd_repstat = NFSERR_SYMLINK;
2761 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2762 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2763 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2764 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2765 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2766 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2768 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2769 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2770 NFSACCCHK_VPISLOCKED, NULL);
2773 if (!nd->nd_repstat) {
2774 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2775 if (!nd->nd_repstat) {
2776 tverf[0] = nva.na_atime.tv_sec;
2777 tverf[1] = nva.na_atime.tv_nsec;
2780 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2781 cverf[1] != tverf[1]))
2782 nd->nd_repstat = EEXIST;
2784 * Do the open locking/delegation stuff.
2786 if (!nd->nd_repstat)
2787 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2788 &delegstateid, &rflags, exp, p, nva.na_filerev);
2791 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2792 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2793 * (ie: Leave the NFSVOPUNLOCK() about here.)
2796 NFSVOPUNLOCK(vp, 0);
2798 FREE((caddr_t)stp, M_NFSDSTATE);
2799 if (!nd->nd_repstat && dirp)
2800 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2802 if (!nd->nd_repstat) {
2803 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2804 *tl++ = txdr_unsigned(stateid.seqid);
2805 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2806 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2807 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2808 *tl++ = newnfs_true;
2814 *tl++ = newnfs_false; /* Since dirp is not locked */
2815 txdr_hyper(dirfor.na_filerev, tl);
2817 txdr_hyper(diraft.na_filerev, tl);
2820 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2821 (void) nfsrv_putattrbit(nd, &attrbits);
2822 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2823 if (rflags & NFSV4OPEN_READDELEGATE)
2824 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2825 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2826 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2828 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2829 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2830 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2831 *tl++ = txdr_unsigned(delegstateid.seqid);
2832 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2834 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2835 if (rflags & NFSV4OPEN_RECALL)
2839 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2840 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2841 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2842 txdr_hyper(nva.na_size, tl);
2844 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2845 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2846 *tl++ = txdr_unsigned(0x0);
2847 acemask = NFSV4ACE_ALLFILESMASK;
2848 if (nva.na_mode & S_IRUSR)
2849 acemask |= NFSV4ACE_READMASK;
2850 if (nva.na_mode & S_IWUSR)
2851 acemask |= NFSV4ACE_WRITEMASK;
2852 if (nva.na_mode & S_IXUSR)
2853 acemask |= NFSV4ACE_EXECUTEMASK;
2854 *tl = txdr_unsigned(acemask);
2855 (void) nfsm_strtom(nd, "OWNER@", 6);
2863 #ifdef NFS4_ACL_EXTATTR_NAME
2866 NFSEXITCODE2(0, nd);
2870 #ifdef NFS4_ACL_EXTATTR_NAME
2874 FREE((caddr_t)stp, M_NFSDSTATE);
2875 NFSEXITCODE2(error, nd);
2880 * nfsv4 close service
2883 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2884 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2887 struct nfsstate st, *stp = &st;
2889 nfsv4stateid_t stateid;
2892 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2893 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2894 stp->ls_ownerlen = 0;
2895 stp->ls_op = nd->nd_rp;
2896 stp->ls_uid = nd->nd_cred->cr_uid;
2897 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2898 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2900 stp->ls_flags = NFSLCK_CLOSE;
2901 clientid.lval[0] = stp->ls_stateid.other[0];
2902 clientid.lval[1] = stp->ls_stateid.other[1];
2903 if (nd->nd_flag & ND_IMPLIEDCLID) {
2904 if (nd->nd_clientid.qval != clientid.qval)
2905 printf("EEK! multiple clids\n");
2907 nd->nd_flag |= ND_IMPLIEDCLID;
2908 nd->nd_clientid.qval = clientid.qval;
2910 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2912 if (!nd->nd_repstat) {
2913 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2914 *tl++ = txdr_unsigned(stateid.seqid);
2915 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2917 NFSEXITCODE2(0, nd);
2921 NFSEXITCODE2(error, nd);
2926 * nfsv4 delegpurge service
2929 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2930 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2936 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2937 nd->nd_repstat = NFSERR_WRONGSEC;
2940 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2941 clientid.lval[0] = *tl++;
2942 clientid.lval[1] = *tl;
2943 if (nd->nd_flag & ND_IMPLIEDCLID) {
2944 if (nd->nd_clientid.qval != clientid.qval)
2945 printf("EEK! multiple clids\n");
2947 nd->nd_flag |= ND_IMPLIEDCLID;
2948 nd->nd_clientid.qval = clientid.qval;
2950 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2951 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2953 NFSEXITCODE2(error, nd);
2958 * nfsv4 delegreturn service
2961 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2962 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2966 nfsv4stateid_t stateid;
2969 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2970 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2971 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2972 clientid.lval[0] = stateid.other[0];
2973 clientid.lval[1] = stateid.other[1];
2974 if (nd->nd_flag & ND_IMPLIEDCLID) {
2975 if (nd->nd_clientid.qval != clientid.qval)
2976 printf("EEK! multiple clids\n");
2978 nd->nd_flag |= ND_IMPLIEDCLID;
2979 nd->nd_clientid.qval = clientid.qval;
2981 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2982 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2985 NFSEXITCODE2(error, nd);
2990 * nfsv4 get file handle service
2993 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2994 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2998 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3000 if (!nd->nd_repstat)
3001 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3002 NFSEXITCODE2(0, nd);
3007 * nfsv4 open confirm service
3010 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3011 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3014 struct nfsstate st, *stp = &st;
3016 nfsv4stateid_t stateid;
3019 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3020 stp->ls_ownerlen = 0;
3021 stp->ls_op = nd->nd_rp;
3022 stp->ls_uid = nd->nd_cred->cr_uid;
3023 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3024 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3026 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3027 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3028 stp->ls_flags = NFSLCK_CONFIRM;
3029 clientid.lval[0] = stp->ls_stateid.other[0];
3030 clientid.lval[1] = stp->ls_stateid.other[1];
3031 if (nd->nd_flag & ND_IMPLIEDCLID) {
3032 if (nd->nd_clientid.qval != clientid.qval)
3033 printf("EEK! multiple clids\n");
3035 nd->nd_flag |= ND_IMPLIEDCLID;
3036 nd->nd_clientid.qval = clientid.qval;
3038 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3039 if (!nd->nd_repstat) {
3040 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3041 *tl++ = txdr_unsigned(stateid.seqid);
3042 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3046 NFSEXITCODE2(error, nd);
3051 * nfsv4 open downgrade service
3054 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3055 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3059 struct nfsstate st, *stp = &st;
3061 nfsv4stateid_t stateid;
3064 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3065 stp->ls_ownerlen = 0;
3066 stp->ls_op = nd->nd_rp;
3067 stp->ls_uid = nd->nd_cred->cr_uid;
3068 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3069 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3071 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3072 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3073 i = fxdr_unsigned(int, *tl++);
3075 case NFSV4OPEN_ACCESSREAD:
3076 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3078 case NFSV4OPEN_ACCESSWRITE:
3079 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3081 case NFSV4OPEN_ACCESSBOTH:
3082 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3086 nd->nd_repstat = NFSERR_BADXDR;
3088 i = fxdr_unsigned(int, *tl);
3090 case NFSV4OPEN_DENYNONE:
3092 case NFSV4OPEN_DENYREAD:
3093 stp->ls_flags |= NFSLCK_READDENY;
3095 case NFSV4OPEN_DENYWRITE:
3096 stp->ls_flags |= NFSLCK_WRITEDENY;
3098 case NFSV4OPEN_DENYBOTH:
3099 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3102 nd->nd_repstat = NFSERR_BADXDR;
3105 clientid.lval[0] = stp->ls_stateid.other[0];
3106 clientid.lval[1] = stp->ls_stateid.other[1];
3107 if (nd->nd_flag & ND_IMPLIEDCLID) {
3108 if (nd->nd_clientid.qval != clientid.qval)
3109 printf("EEK! multiple clids\n");
3111 nd->nd_flag |= ND_IMPLIEDCLID;
3112 nd->nd_clientid.qval = clientid.qval;
3114 if (!nd->nd_repstat)
3115 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3117 if (!nd->nd_repstat) {
3118 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3119 *tl++ = txdr_unsigned(stateid.seqid);
3120 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3124 NFSEXITCODE2(error, nd);
3129 * nfsv4 renew lease service
3132 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3133 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3139 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3140 nd->nd_repstat = NFSERR_WRONGSEC;
3143 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3144 clientid.lval[0] = *tl++;
3145 clientid.lval[1] = *tl;
3146 if (nd->nd_flag & ND_IMPLIEDCLID) {
3147 if (nd->nd_clientid.qval != clientid.qval)
3148 printf("EEK! multiple clids\n");
3150 nd->nd_flag |= ND_IMPLIEDCLID;
3151 nd->nd_clientid.qval = clientid.qval;
3153 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3154 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3156 NFSEXITCODE2(error, nd);
3161 * nfsv4 security info service
3164 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3165 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3169 struct nameidata named;
3170 vnode_t dirp = NULL, vp;
3172 struct nfsexstuff retnes;
3174 int error = 0, savflag, i;
3179 * All this just to get the export flags for the name.
3181 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3182 LOCKLEAF | SAVESTART);
3183 nfsvno_setpathbuf(&named, &bufp, &hashp);
3184 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3187 nfsvno_relpathbuf(&named);
3190 if (!nd->nd_repstat) {
3191 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3194 nfsvno_relpathbuf(&named);
3200 vrele(named.ni_startdir);
3201 nfsvno_relpathbuf(&named);
3202 fh.nfsrvfh_len = NFSX_MYFH;
3204 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3206 savflag = nd->nd_flag;
3207 if (!nd->nd_repstat) {
3208 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3212 nd->nd_flag = savflag;
3217 * Finally have the export flags for name, so we can create
3218 * the security info.
3221 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3222 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3223 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3225 *tl = txdr_unsigned(RPCAUTH_UNIX);
3227 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3229 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3230 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3231 nfsgss_mechlist[KERBV_MECH].len);
3232 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3233 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3234 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3236 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3237 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3238 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3239 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3240 nfsgss_mechlist[KERBV_MECH].len);
3241 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3242 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3243 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3245 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3246 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3247 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3248 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3249 nfsgss_mechlist[KERBV_MECH].len);
3250 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3251 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3252 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3256 *sizp = txdr_unsigned(len);
3259 NFSEXITCODE2(error, nd);
3264 * nfsv4 set client id service
3267 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3268 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3272 int error = 0, idlen;
3273 struct nfsclient *clp = NULL;
3274 struct sockaddr_in *rad;
3275 u_char *verf, *ucp, *ucp2, addrbuf[24];
3276 nfsquad_t clientid, confirm;
3278 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3279 nd->nd_repstat = NFSERR_WRONGSEC;
3282 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3283 verf = (u_char *)tl;
3284 tl += (NFSX_VERF / NFSX_UNSIGNED);
3285 i = fxdr_unsigned(int, *tl);
3286 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3287 nd->nd_repstat = NFSERR_BADXDR;
3291 if (nd->nd_flag & ND_GSS)
3292 i += nd->nd_princlen;
3293 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3294 M_NFSDCLIENT, M_WAITOK);
3295 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3296 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3297 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3298 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3299 clp->lc_req.nr_cred = NULL;
3300 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3301 clp->lc_idlen = idlen;
3302 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3305 if (nd->nd_flag & ND_GSS) {
3306 clp->lc_flags = LCL_GSS;
3307 if (nd->nd_flag & ND_GSSINTEGRITY)
3308 clp->lc_flags |= LCL_GSSINTEGRITY;
3309 else if (nd->nd_flag & ND_GSSPRIVACY)
3310 clp->lc_flags |= LCL_GSSPRIVACY;
3314 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3315 clp->lc_flags |= LCL_NAME;
3316 clp->lc_namelen = nd->nd_princlen;
3317 clp->lc_name = &clp->lc_id[idlen];
3318 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3320 clp->lc_uid = nd->nd_cred->cr_uid;
3321 clp->lc_gid = nd->nd_cred->cr_gid;
3323 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3324 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3325 error = nfsrv_getclientipaddr(nd, clp);
3328 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3329 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3332 * nfsrv_setclient() does the actual work of adding it to the
3333 * client list. If there is no error, the structure has been
3334 * linked into the client list and clp should no longer be used
3335 * here. When an error is returned, it has not been linked in,
3336 * so it should be free'd.
3338 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3339 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3340 if (clp->lc_flags & LCL_TCPCALLBACK)
3341 (void) nfsm_strtom(nd, "tcp", 3);
3343 (void) nfsm_strtom(nd, "udp", 3);
3344 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3345 ucp = (u_char *)&rad->sin_addr.s_addr;
3346 ucp2 = (u_char *)&rad->sin_port;
3347 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3348 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3349 ucp2[0] & 0xff, ucp2[1] & 0xff);
3350 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3353 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3354 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3355 free((caddr_t)clp, M_NFSDCLIENT);
3357 if (!nd->nd_repstat) {
3358 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3359 *tl++ = clientid.lval[0];
3360 *tl++ = clientid.lval[1];
3361 *tl++ = confirm.lval[0];
3362 *tl = confirm.lval[1];
3366 NFSEXITCODE2(0, nd);
3370 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3371 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3372 free((caddr_t)clp, M_NFSDCLIENT);
3374 NFSEXITCODE2(error, nd);
3379 * nfsv4 set client id confirm service
3382 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3383 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3384 __unused struct nfsexstuff *exp)
3388 nfsquad_t clientid, confirm;
3390 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3391 nd->nd_repstat = NFSERR_WRONGSEC;
3394 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3395 clientid.lval[0] = *tl++;
3396 clientid.lval[1] = *tl++;
3397 confirm.lval[0] = *tl++;
3398 confirm.lval[1] = *tl;
3401 * nfsrv_getclient() searches the client list for a match and
3402 * returns the appropriate NFSERR status.
3404 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3405 NULL, confirm, nd, p);
3407 NFSEXITCODE2(error, nd);
3412 * nfsv4 verify service
3415 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3416 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3418 int error = 0, ret, fhsize = NFSX_MYFH;
3419 struct nfsvattr nva;
3421 struct nfsfsinfo fs;
3424 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3425 if (!nd->nd_repstat)
3426 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3427 if (!nd->nd_repstat)
3428 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3429 if (!nd->nd_repstat) {
3430 nfsvno_getfs(&fs, isdgram);
3431 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3432 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3434 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3436 nd->nd_repstat = NFSERR_SAME;
3437 else if (ret != NFSERR_NOTSAME)
3438 nd->nd_repstat = ret;
3440 nd->nd_repstat = ret;
3444 NFSEXITCODE2(error, nd);
3452 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3453 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3454 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3457 int error = 0, createdir;
3459 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3460 createdir = fxdr_unsigned(int, *tl);
3461 nd->nd_repstat = NFSERR_NOTSUPP;
3464 NFSEXITCODE2(error, nd);
3469 * nfsv4 release lock owner service
3472 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3473 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3476 struct nfsstate *stp = NULL;
3480 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3481 nd->nd_repstat = NFSERR_WRONGSEC;
3484 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3485 len = fxdr_unsigned(int, *(tl + 2));
3486 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3487 nd->nd_repstat = NFSERR_BADXDR;
3490 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3491 M_NFSDSTATE, M_WAITOK);
3492 stp->ls_ownerlen = len;
3494 stp->ls_flags = NFSLCK_RELEASE;
3495 stp->ls_uid = nd->nd_cred->cr_uid;
3496 clientid.lval[0] = *tl++;
3497 clientid.lval[1] = *tl;
3498 if (nd->nd_flag & ND_IMPLIEDCLID) {
3499 if (nd->nd_clientid.qval != clientid.qval)
3500 printf("EEK! multiple clids\n");
3502 nd->nd_flag |= ND_IMPLIEDCLID;
3503 nd->nd_clientid.qval = clientid.qval;
3505 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3508 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3509 FREE((caddr_t)stp, M_NFSDSTATE);
3511 NFSEXITCODE2(0, nd);
3515 free((caddr_t)stp, M_NFSDSTATE);
3516 NFSEXITCODE2(error, nd);