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);
165 * nfs getattr service
168 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
169 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
173 int at_root = 0, error = 0, supports_nfsv4acls;
174 struct nfsreferral *refp;
175 nfsattrbit_t attrbits;
177 struct vnode *tvp = NULL;
179 uint64_t mounted_on_fileno = 0;
183 if (nd->nd_flag & ND_NFSV4) {
184 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
191 * Check for a referral.
193 refp = nfsv4root_getreferral(vp, NULL, 0);
195 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
201 nd->nd_repstat = nfsvno_accchk(vp,
203 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
204 NFSACCCHK_VPISLOCKED, NULL);
207 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
208 if (!nd->nd_repstat) {
209 if (nd->nd_flag & ND_NFSV4) {
210 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
211 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
213 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
214 &nva, &attrbits, nd->nd_cred, p);
215 if (nd->nd_repstat == 0) {
216 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
218 if (nfsrv_enable_crossmntpt != 0 &&
219 vp->v_type == VDIR &&
220 (vp->v_vflag & VV_ROOT) != 0 &&
222 tvp = mp->mnt_vnodecovered;
230 if ((nd->nd_repstat =
231 vn_lock(tvp, LK_SHARED)) == 0) {
232 nd->nd_repstat = VOP_GETATTR(
233 tvp, &va, nd->nd_cred);
237 if (nd->nd_repstat == 0)
238 mounted_on_fileno = (uint64_t)
243 if (nd->nd_repstat == 0)
244 nd->nd_repstat = vfs_busy(mp, 0);
246 if (nd->nd_repstat == 0) {
247 (void)nfsvno_fillattr(nd, mp, vp, &nva,
248 &fh, 0, &attrbits, nd->nd_cred, p,
249 isdgram, 1, supports_nfsv4acls,
250 at_root, mounted_on_fileno);
257 nfsrv_fillattr(nd, &nva);
267 * nfs setattr service
270 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
271 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
273 struct nfsvattr nva, nva2;
275 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
276 struct timespec guard = { 0, 0 };
277 nfsattrbit_t attrbits, retbits;
278 nfsv4stateid_t stateid;
279 NFSACL_T *aclp = NULL;
281 if (nd->nd_repstat) {
282 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
285 #ifdef NFS4_ACL_EXTATTR_NAME
286 aclp = acl_alloc(M_WAITOK);
289 NFSVNO_ATTRINIT(&nva);
290 NFSZERO_ATTRBIT(&retbits);
291 if (nd->nd_flag & ND_NFSV4) {
292 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
293 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
294 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
296 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
299 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
301 nd->nd_repstat = preat_ret;
302 if (nd->nd_flag & ND_NFSV3) {
303 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
304 gcheck = fxdr_unsigned(int, *tl);
306 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
307 fxdr_nfsv3time(tl, &guard);
309 if (!nd->nd_repstat && gcheck &&
310 (nva2.na_ctime.tv_sec != guard.tv_sec ||
311 nva2.na_ctime.tv_nsec != guard.tv_nsec))
312 nd->nd_repstat = NFSERR_NOT_SYNC;
313 if (nd->nd_repstat) {
315 #ifdef NFS4_ACL_EXTATTR_NAME
318 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
321 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
322 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
325 * Now that we have all the fields, lets do it.
326 * If the size is being changed write access is required, otherwise
327 * just check for a read only file system.
329 if (!nd->nd_repstat) {
330 if (NFSVNO_NOTSETSIZE(&nva)) {
331 if (NFSVNO_EXRDONLY(exp) ||
332 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
333 nd->nd_repstat = EROFS;
335 if (vnode_vtype(vp) != VREG)
336 nd->nd_repstat = EINVAL;
337 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
338 NFSVNO_EXSTRICTACCESS(exp))
339 nd->nd_repstat = nfsvno_accchk(vp,
340 VWRITE, nd->nd_cred, exp, p,
341 NFSACCCHK_NOOVERRIDE,
342 NFSACCCHK_VPISLOCKED, NULL);
345 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
346 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
347 &nva, &attrbits, exp, p);
349 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
351 * For V4, try setting the attrbutes in sets, so that the
352 * reply bitmap will be correct for an error case.
354 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
355 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
356 NFSVNO_ATTRINIT(&nva2);
357 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
358 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
359 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
361 if (!nd->nd_repstat) {
362 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
363 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
364 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
365 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
368 if (!nd->nd_repstat &&
369 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
370 NFSVNO_ATTRINIT(&nva2);
371 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
372 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
375 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
377 if (!nd->nd_repstat &&
378 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
379 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
380 NFSVNO_ATTRINIT(&nva2);
381 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
382 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
383 if (nva.na_vaflags & VA_UTIMES_NULL) {
384 nva2.na_vaflags |= VA_UTIMES_NULL;
385 NFSVNO_SETACTIVE(&nva2, vaflags);
387 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
389 if (!nd->nd_repstat) {
390 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
391 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
392 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
393 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
396 if (!nd->nd_repstat &&
397 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
398 NFSVNO_ATTRINIT(&nva2);
399 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
400 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
403 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
406 #ifdef NFS4_ACL_EXTATTR_NAME
407 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
408 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
409 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
411 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
414 } else if (!nd->nd_repstat) {
415 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
418 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
419 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
421 nd->nd_repstat = postat_ret;
424 #ifdef NFS4_ACL_EXTATTR_NAME
427 if (nd->nd_flag & ND_NFSV3)
428 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
429 else if (nd->nd_flag & ND_NFSV4)
430 (void) nfsrv_putattrbit(nd, &retbits);
431 else if (!nd->nd_repstat)
432 nfsrv_fillattr(nd, &nva);
436 #ifdef NFS4_ACL_EXTATTR_NAME
439 if (nd->nd_flag & ND_NFSV4) {
441 * For all nd_repstat, the V4 reply includes a bitmap,
442 * even NFSERR_BADXDR, which is what this will end up
445 (void) nfsrv_putattrbit(nd, &retbits);
452 * (Also performs lookup parent for v4)
455 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
456 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
457 __unused struct nfsexstuff *exp)
459 struct nameidata named;
460 vnode_t vp, dirp = NULL;
461 int error, dattr_ret = 1;
462 struct nfsvattr nva, dattr;
466 if (nd->nd_repstat) {
467 nfsrv_postopattr(nd, dattr_ret, &dattr);
472 * For some reason, if dp is a symlink, the error
473 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
475 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
476 nd->nd_repstat = NFSERR_SYMLINK;
481 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
482 LOCKLEAF | SAVESTART);
483 nfsvno_setpathbuf(&named, &bufp, &hashp);
484 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
487 nfsvno_relpathbuf(&named);
490 if (!nd->nd_repstat) {
491 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
494 nfsvno_relpathbuf(&named);
496 if (nd->nd_repstat) {
498 if (nd->nd_flag & ND_NFSV3)
499 dattr_ret = nfsvno_getattr(dirp, &dattr,
503 if (nd->nd_flag & ND_NFSV3)
504 nfsrv_postopattr(nd, dattr_ret, &dattr);
507 if (named.ni_startdir)
508 vrele(named.ni_startdir);
509 nfsvno_relpathbuf(&named);
511 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
512 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
513 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
514 if (vpp != NULL && nd->nd_repstat == 0)
519 if (nd->nd_flag & ND_NFSV3)
520 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
524 if (nd->nd_repstat) {
525 if (nd->nd_flag & ND_NFSV3)
526 nfsrv_postopattr(nd, dattr_ret, &dattr);
529 if (nd->nd_flag & ND_NFSV2) {
530 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
531 nfsrv_fillattr(nd, &nva);
532 } else if (nd->nd_flag & ND_NFSV3) {
533 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
534 nfsrv_postopattr(nd, 0, &nva);
535 nfsrv_postopattr(nd, dattr_ret, &dattr);
541 * nfs readlink service
544 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
545 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
548 mbuf_t mp = NULL, mpend = NULL;
552 if (nd->nd_repstat) {
553 nfsrv_postopattr(nd, getret, &nva);
556 if (vnode_vtype(vp) != VLNK) {
557 if (nd->nd_flag & ND_NFSV2)
558 nd->nd_repstat = ENXIO;
560 nd->nd_repstat = EINVAL;
563 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
565 if (nd->nd_flag & ND_NFSV3)
566 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
568 if (nd->nd_flag & ND_NFSV3)
569 nfsrv_postopattr(nd, getret, &nva);
572 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
573 *tl = txdr_unsigned(len);
574 mbuf_setnext(nd->nd_mb, mp);
576 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
584 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
585 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
588 int error = 0, cnt, len, getret = 1, reqlen, eof = 0;
592 struct nfsstate st, *stp = &st;
593 struct nfslock lo, *lop = &lo;
594 nfsv4stateid_t stateid;
597 if (nd->nd_repstat) {
598 nfsrv_postopattr(nd, getret, &nva);
601 if (nd->nd_flag & ND_NFSV2) {
602 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
603 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
604 reqlen = fxdr_unsigned(int, *tl);
605 } else if (nd->nd_flag & ND_NFSV3) {
606 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
607 off = fxdr_hyper(tl);
609 reqlen = fxdr_unsigned(int, *tl);
611 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
612 reqlen = fxdr_unsigned(int, *(tl + 6));
614 if (reqlen > NFS_SRVMAXDATA(nd)) {
615 reqlen = NFS_SRVMAXDATA(nd);
616 } else if (reqlen < 0) {
620 if (nd->nd_flag & ND_NFSV4) {
621 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
622 lop->lo_flags = NFSLCK_READ;
623 stp->ls_ownerlen = 0;
625 stp->ls_uid = nd->nd_cred->cr_uid;
626 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
627 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
628 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
629 if (nd->nd_flag & ND_IMPLIEDCLID) {
630 if (nd->nd_clientid.qval != clientid.qval)
631 printf("EEK! multiple clids\n");
633 nd->nd_flag |= ND_IMPLIEDCLID;
634 nd->nd_clientid.qval = clientid.qval;
636 stp->ls_stateid.other[2] = *tl++;
637 off = fxdr_hyper(tl);
640 lop->lo_end = off + reqlen;
642 * Paranoia, just in case it wraps around.
644 if (lop->lo_end < off)
645 lop->lo_end = NFS64BITSSET;
647 if (vnode_vtype(vp) != VREG) {
648 if (nd->nd_flag & ND_NFSV3)
649 nd->nd_repstat = EINVAL;
651 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
654 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
656 nd->nd_repstat = getret;
657 if (!nd->nd_repstat &&
658 (nva.na_uid != nd->nd_cred->cr_uid ||
659 NFSVNO_EXSTRICTACCESS(exp))) {
660 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
662 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
664 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
665 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
666 NFSACCCHK_VPISLOCKED, NULL);
668 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
669 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
670 &stateid, exp, nd, p);
671 if (nd->nd_repstat) {
673 if (nd->nd_flag & ND_NFSV3)
674 nfsrv_postopattr(nd, getret, &nva);
677 if (off >= nva.na_size) {
680 } else if (reqlen == 0)
682 else if ((off + reqlen) > nva.na_size)
683 cnt = nva.na_size - off;
686 len = NFSM_RNDUP(cnt);
689 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
691 if (!(nd->nd_flag & ND_NFSV4)) {
692 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
694 nd->nd_repstat = getret;
696 if (nd->nd_repstat) {
700 if (nd->nd_flag & ND_NFSV3)
701 nfsrv_postopattr(nd, getret, &nva);
706 if (nd->nd_flag & ND_NFSV2) {
707 nfsrv_fillattr(nd, &nva);
708 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
710 if (nd->nd_flag & ND_NFSV3) {
711 nfsrv_postopattr(nd, getret, &nva);
712 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
713 *tl++ = txdr_unsigned(cnt);
715 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
716 if (len < reqlen || eof)
719 *tl++ = newnfs_false;
721 *tl = txdr_unsigned(cnt);
723 mbuf_setnext(nd->nd_mb, m3);
725 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
737 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
738 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
743 struct nfsvattr nva, forat;
744 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
745 int stable = NFSWRITE_FILESYNC;
747 struct nfsstate st, *stp = &st;
748 struct nfslock lo, *lop = &lo;
749 nfsv4stateid_t stateid;
752 if (nd->nd_repstat) {
753 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
756 if (nd->nd_flag & ND_NFSV2) {
757 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
758 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
760 retlen = len = fxdr_unsigned(int32_t, *tl);
761 } else if (nd->nd_flag & ND_NFSV3) {
762 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
763 off = fxdr_hyper(tl);
765 stable = fxdr_unsigned(int, *tl++);
766 retlen = len = fxdr_unsigned(int32_t, *tl);
768 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
769 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
770 lop->lo_flags = NFSLCK_WRITE;
771 stp->ls_ownerlen = 0;
773 stp->ls_uid = nd->nd_cred->cr_uid;
774 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
775 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
776 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
777 if (nd->nd_flag & ND_IMPLIEDCLID) {
778 if (nd->nd_clientid.qval != clientid.qval)
779 printf("EEK! multiple clids\n");
781 nd->nd_flag |= ND_IMPLIEDCLID;
782 nd->nd_clientid.qval = clientid.qval;
784 stp->ls_stateid.other[2] = *tl++;
785 off = fxdr_hyper(tl);
788 stable = fxdr_unsigned(int, *tl++);
789 retlen = len = fxdr_unsigned(int32_t, *tl);
790 lop->lo_end = off + len;
792 * Paranoia, just in case it wraps around, which shouldn't
793 * ever happen anyhow.
795 if (lop->lo_end < lop->lo_first)
796 lop->lo_end = NFS64BITSSET;
800 * Loop through the mbuf chain, counting how many mbufs are a
801 * part of this write operation, so the iovec size is known.
805 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
821 if (retlen > NFS_MAXDATA || retlen < 0)
822 nd->nd_repstat = EIO;
823 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
824 if (nd->nd_flag & ND_NFSV3)
825 nd->nd_repstat = EINVAL;
827 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
830 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
832 nd->nd_repstat = forat_ret;
833 if (!nd->nd_repstat &&
834 (forat.na_uid != nd->nd_cred->cr_uid ||
835 NFSVNO_EXSTRICTACCESS(exp)))
836 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
838 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
839 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
840 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
841 &stateid, exp, nd, p);
843 if (nd->nd_repstat) {
845 if (nd->nd_flag & ND_NFSV3)
846 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
851 * For NFS Version 2, it is not obvious what a write of zero length
852 * should do, but I might as well be consistent with Version 3,
853 * which is to return ok so long as there are no permission problems.
856 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
857 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
858 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
860 panic("nfsrv_write mbuf");
862 if (nd->nd_flag & ND_NFSV4)
865 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
868 nd->nd_repstat = aftat_ret;
869 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
870 if (nd->nd_flag & ND_NFSV3)
871 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
874 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
875 *tl++ = txdr_unsigned(retlen);
876 if (stable == NFSWRITE_UNSTABLE)
877 *tl++ = txdr_unsigned(stable);
879 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
881 * Actually, there is no need to txdr these fields,
882 * but it may make the values more human readable,
883 * for debugging purposes.
885 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
886 *tl = txdr_unsigned(nfsboottime.tv_usec);
887 } else if (!nd->nd_repstat)
888 nfsrv_fillattr(nd, &nva);
896 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
897 * now does a truncate to 0 length via. setattr if it already exists
898 * The core creation routine has been extracted out into nfsrv_creatsub(),
899 * so it can also be used by nfsrv_open() for V4.
902 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
903 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
905 struct nfsvattr nva, dirfor, diraft;
906 struct nfsv2_sattr *sp;
907 struct nameidata named;
909 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
910 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
912 vnode_t vp = NULL, dirp = NULL;
917 int32_t cverf[2], tverf[2] = { 0, 0 };
919 if (nd->nd_repstat) {
920 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
923 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
924 LOCKPARENT | LOCKLEAF | SAVESTART);
925 nfsvno_setpathbuf(&named, &bufp, &hashp);
926 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
929 nfsvno_relpathbuf(&named);
932 if (!nd->nd_repstat) {
933 NFSVNO_ATTRINIT(&nva);
934 if (nd->nd_flag & ND_NFSV2) {
935 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
936 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
939 NFSVNO_SETATTRVAL(&nva, type, vtyp);
940 NFSVNO_SETATTRVAL(&nva, mode,
941 nfstov_mode(sp->sa_mode));
942 switch (nva.na_type) {
944 tsize = fxdr_unsigned(int32_t, sp->sa_size);
946 NFSVNO_SETATTRVAL(&nva, size,
952 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
958 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
959 how = fxdr_unsigned(int, *tl);
961 case NFSCREATE_GUARDED:
962 case NFSCREATE_UNCHECKED:
963 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
967 case NFSCREATE_EXCLUSIVE:
968 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
974 NFSVNO_SETATTRVAL(&nva, type, VREG);
977 if (nd->nd_repstat) {
978 nfsvno_relpathbuf(&named);
979 if (nd->nd_flag & ND_NFSV3) {
980 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
982 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
989 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
991 if (nd->nd_flag & ND_NFSV2) {
995 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
999 if (nd->nd_repstat) {
1000 if (nd->nd_flag & ND_NFSV3)
1001 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1008 if (!(nd->nd_flag & ND_NFSV2)) {
1010 case NFSCREATE_GUARDED:
1012 nd->nd_repstat = EEXIST;
1014 case NFSCREATE_UNCHECKED:
1016 case NFSCREATE_EXCLUSIVE:
1017 if (named.ni_vp == NULL)
1018 NFSVNO_SETATTRVAL(&nva, mode, 0);
1024 * Iff doesn't exist, create it
1025 * otherwise just truncate to 0 length
1026 * should I set the mode too ?
1028 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1029 &exclusive_flag, cverf, rdev, p, exp);
1031 if (!nd->nd_repstat) {
1032 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1033 if (!nd->nd_repstat)
1034 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1037 if (!nd->nd_repstat) {
1038 tverf[0] = nva.na_atime.tv_sec;
1039 tverf[1] = nva.na_atime.tv_nsec;
1042 if (nd->nd_flag & ND_NFSV2) {
1043 if (!nd->nd_repstat) {
1044 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1045 nfsrv_fillattr(nd, &nva);
1048 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1049 || cverf[1] != tverf[1]))
1050 nd->nd_repstat = EEXIST;
1051 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1053 if (!nd->nd_repstat) {
1054 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1055 nfsrv_postopattr(nd, 0, &nva);
1057 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1062 nfsvno_relpathbuf(&named);
1067 * nfs v3 mknod service (and v4 create)
1070 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1071 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1072 struct nfsexstuff *exp)
1074 struct nfsvattr nva, dirfor, diraft;
1076 struct nameidata named;
1077 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1078 u_int32_t major, minor;
1079 enum vtype vtyp = VNON;
1080 nfstype nfs4type = NFNON;
1081 vnode_t vp, dirp = NULL;
1082 nfsattrbit_t attrbits;
1083 char *bufp = NULL, *pathcp = NULL;
1084 u_long *hashp, cnflags;
1085 NFSACL_T *aclp = NULL;
1087 NFSVNO_ATTRINIT(&nva);
1088 cnflags = (LOCKPARENT | SAVESTART);
1089 if (nd->nd_repstat) {
1090 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1093 #ifdef NFS4_ACL_EXTATTR_NAME
1094 aclp = acl_alloc(M_WAITOK);
1099 * For V4, the creation stuff is here, Yuck!
1101 if (nd->nd_flag & ND_NFSV4) {
1102 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1103 vtyp = nfsv34tov_type(*tl);
1104 nfs4type = fxdr_unsigned(nfstype, *tl);
1107 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1111 #ifdef NFS4_ACL_EXTATTR_NAME
1119 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1120 major = fxdr_unsigned(u_int32_t, *tl++);
1121 minor = fxdr_unsigned(u_int32_t, *tl);
1122 nva.na_rdev = NFSMAKEDEV(major, minor);
1128 cnflags = (LOCKPARENT | SAVENAME);
1131 nd->nd_repstat = NFSERR_BADTYPE;
1133 #ifdef NFS4_ACL_EXTATTR_NAME
1139 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1140 nfsvno_setpathbuf(&named, &bufp, &hashp);
1141 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1144 #ifdef NFS4_ACL_EXTATTR_NAME
1147 nfsvno_relpathbuf(&named);
1149 FREE(pathcp, M_TEMP);
1152 if (!nd->nd_repstat) {
1153 if (nd->nd_flag & ND_NFSV3) {
1154 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1155 vtyp = nfsv34tov_type(*tl);
1157 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1160 #ifdef NFS4_ACL_EXTATTR_NAME
1163 nfsvno_relpathbuf(&named);
1165 FREE(pathcp, M_TEMP);
1169 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1170 (vtyp == VCHR || vtyp == VBLK)) {
1171 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1172 major = fxdr_unsigned(u_int32_t, *tl++);
1173 minor = fxdr_unsigned(u_int32_t, *tl);
1174 nva.na_rdev = NFSMAKEDEV(major, minor);
1178 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1179 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1180 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1181 dirfor.na_gid == nva.na_gid)
1182 NFSVNO_UNSET(&nva, gid);
1183 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1185 if (nd->nd_repstat) {
1187 #ifdef NFS4_ACL_EXTATTR_NAME
1190 nfsvno_relpathbuf(&named);
1192 FREE(pathcp, M_TEMP);
1193 if (nd->nd_flag & ND_NFSV3)
1194 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1200 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1201 * in va_mode, so we'll have to set a default here.
1203 if (NFSVNO_NOTSETMODE(&nva)) {
1211 named.ni_cnd.cn_flags |= WILLBEDIR;
1212 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1213 if (nd->nd_repstat) {
1215 if (nd->nd_flag & ND_NFSV3)
1216 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1220 #ifdef NFS4_ACL_EXTATTR_NAME
1223 if (nd->nd_flag & ND_NFSV3)
1224 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1229 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1231 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1233 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1234 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1236 #ifdef NFS4_ACL_EXTATTR_NAME
1240 } else if (vtyp == VLNK) {
1241 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1242 &dirfor, &diraft, &diraft_ret, &attrbits,
1243 aclp, p, exp, pathcp, pathlen);
1244 #ifdef NFS4_ACL_EXTATTR_NAME
1247 FREE(pathcp, M_TEMP);
1252 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1253 if (!nd->nd_repstat) {
1255 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1256 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1257 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1258 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1260 if (vpp != NULL && nd->nd_repstat == 0) {
1267 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1269 if (!nd->nd_repstat) {
1270 if (nd->nd_flag & ND_NFSV3) {
1271 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1272 nfsrv_postopattr(nd, 0, &nva);
1274 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1275 *tl++ = newnfs_false;
1276 txdr_hyper(dirfor.na_filerev, tl);
1278 txdr_hyper(diraft.na_filerev, tl);
1279 (void) nfsrv_putattrbit(nd, &attrbits);
1282 if (nd->nd_flag & ND_NFSV3)
1283 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1284 #ifdef NFS4_ACL_EXTATTR_NAME
1290 #ifdef NFS4_ACL_EXTATTR_NAME
1294 nfsvno_relpathbuf(&named);
1296 FREE(pathcp, M_TEMP);
1301 * nfs remove service
1304 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1305 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1307 struct nameidata named;
1309 int error, dirfor_ret = 1, diraft_ret = 1;
1310 vnode_t dirp = NULL;
1311 struct nfsvattr dirfor, diraft;
1315 if (nd->nd_repstat) {
1316 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1319 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1320 LOCKPARENT | LOCKLEAF);
1321 nfsvno_setpathbuf(&named, &bufp, &hashp);
1322 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1325 nfsvno_relpathbuf(&named);
1328 if (!nd->nd_repstat) {
1329 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1332 nfsvno_relpathbuf(&named);
1335 if (!(nd->nd_flag & ND_NFSV2)) {
1336 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1343 if (!nd->nd_repstat) {
1344 if (nd->nd_flag & ND_NFSV4) {
1345 if (vnode_vtype(named.ni_vp) == VDIR)
1346 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1347 nd->nd_cred, p, exp);
1349 nd->nd_repstat = nfsvno_removesub(&named, 1,
1350 nd->nd_cred, p, exp);
1351 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1352 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1353 nd->nd_cred, p, exp);
1355 nd->nd_repstat = nfsvno_removesub(&named, 0,
1356 nd->nd_cred, p, exp);
1359 if (!(nd->nd_flag & ND_NFSV2)) {
1361 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1365 if (nd->nd_flag & ND_NFSV3) {
1366 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1368 } else if (!nd->nd_repstat) {
1369 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1370 *tl++ = newnfs_false;
1371 txdr_hyper(dirfor.na_filerev, tl);
1373 txdr_hyper(diraft.na_filerev, tl);
1380 * nfs rename service
1383 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1384 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1385 struct nfsexstuff *toexp)
1388 int error, fdirfor_ret = 1, fdiraft_ret = 1;
1389 int tdirfor_ret = 1, tdiraft_ret = 1;
1390 struct nameidata fromnd, tond;
1391 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1392 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1393 struct nfsexstuff tnes;
1395 char *bufp, *tbufp = NULL;
1398 if (nd->nd_repstat) {
1399 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1400 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1403 if (!(nd->nd_flag & ND_NFSV2))
1404 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1405 tond.ni_cnd.cn_nameiop = 0;
1406 tond.ni_startdir = NULL;
1407 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1408 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1409 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1414 nfsvno_relpathbuf(&fromnd);
1417 if (nd->nd_flag & ND_NFSV4) {
1420 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1422 error = nfsrv_mtofh(nd, &tfh);
1425 /* todp is always NULL except NFSv4 */
1426 nfsvno_relpathbuf(&fromnd);
1429 nd->nd_cred->cr_uid = nd->nd_saveduid;
1430 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p);
1432 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1434 NFSVOPUNLOCK(tdp, 0, p);
1437 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1438 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1439 if (!nd->nd_repstat) {
1440 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1445 nfsvno_relpathbuf(&fromnd);
1446 nfsvno_relpathbuf(&tond);
1450 if (nd->nd_repstat) {
1451 if (nd->nd_flag & ND_NFSV3) {
1452 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1454 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1460 nfsvno_relpathbuf(&fromnd);
1461 nfsvno_relpathbuf(&tond);
1466 * Done parsing, now down to business.
1468 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1469 if (nd->nd_repstat) {
1470 if (nd->nd_flag & ND_NFSV3) {
1471 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1473 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1480 nfsvno_relpathbuf(&tond);
1483 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1484 tond.ni_cnd.cn_flags |= WILLBEDIR;
1485 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1486 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1487 nd->nd_flag, nd->nd_cred, p);
1489 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1492 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1498 if (nd->nd_flag & ND_NFSV3) {
1499 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1500 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1501 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1502 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1503 *tl++ = newnfs_false;
1504 txdr_hyper(fdirfor.na_filerev, tl);
1506 txdr_hyper(fdiraft.na_filerev, tl);
1508 *tl++ = newnfs_false;
1509 txdr_hyper(tdirfor.na_filerev, tl);
1511 txdr_hyper(tdiraft.na_filerev, tl);
1520 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1521 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1522 struct nfsexstuff *toexp)
1524 struct nameidata named;
1526 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1527 vnode_t dirp = NULL, dp = NULL;
1528 struct nfsvattr dirfor, diraft, at;
1529 struct nfsexstuff tnes;
1534 if (nd->nd_repstat) {
1535 nfsrv_postopattr(nd, getret, &at);
1536 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1539 NFSVOPUNLOCK(vp, 0, p);
1540 if (vnode_vtype(vp) == VDIR) {
1541 if (nd->nd_flag & ND_NFSV4)
1542 nd->nd_repstat = NFSERR_ISDIR;
1544 nd->nd_repstat = NFSERR_INVAL;
1547 } else if (vnode_vtype(vp) == VLNK) {
1548 if (nd->nd_flag & ND_NFSV2)
1549 nd->nd_repstat = NFSERR_INVAL;
1551 nd->nd_repstat = NFSERR_NOTSUPP;
1555 if (!nd->nd_repstat) {
1556 if (nd->nd_flag & ND_NFSV4) {
1560 error = nfsrv_mtofh(nd, &dfh);
1563 /* tovp is always NULL unless NFSv4 */
1566 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1569 NFSVOPUNLOCK(dp, 0, p);
1572 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1573 LOCKPARENT | SAVENAME);
1574 if (!nd->nd_repstat) {
1575 nfsvno_setpathbuf(&named, &bufp, &hashp);
1576 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1581 nfsvno_relpathbuf(&named);
1584 if (!nd->nd_repstat) {
1585 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1590 nfsvno_relpathbuf(&named);
1594 if (nd->nd_flag & ND_NFSV2) {
1598 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1602 if (!nd->nd_repstat)
1603 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1604 if (nd->nd_flag & ND_NFSV3)
1605 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1607 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1611 if (nd->nd_flag & ND_NFSV3) {
1612 nfsrv_postopattr(nd, getret, &at);
1613 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1614 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1615 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1616 *tl++ = newnfs_false;
1617 txdr_hyper(dirfor.na_filerev, tl);
1619 txdr_hyper(diraft.na_filerev, tl);
1625 * nfs symbolic link service
1628 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1629 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1630 struct nfsexstuff *exp)
1632 struct nfsvattr nva, dirfor, diraft;
1633 struct nameidata named;
1634 int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1635 vnode_t dirp = NULL;
1636 char *bufp, *pathcp = NULL;
1639 if (nd->nd_repstat) {
1640 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1645 NFSVNO_ATTRINIT(&nva);
1646 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1647 LOCKPARENT | SAVESTART);
1648 nfsvno_setpathbuf(&named, &bufp, &hashp);
1649 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1650 if (!error && !nd->nd_repstat)
1651 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1654 nfsvno_relpathbuf(&named);
1657 if (!nd->nd_repstat) {
1658 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1661 nfsvno_relpathbuf(&named);
1663 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1669 * And call nfsrvd_symlinksub() to do the common code. It will
1670 * return EBADRPC upon a parsing error, 0 otherwise.
1672 if (!nd->nd_repstat) {
1674 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1676 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1677 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1679 } else if (dirp != NULL) {
1680 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1684 FREE(pathcp, M_TEMP);
1686 if (nd->nd_flag & ND_NFSV3) {
1687 if (!nd->nd_repstat) {
1688 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1689 nfsrv_postopattr(nd, 0, &nva);
1691 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1697 * Common code for creating a symbolic link.
1700 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1701 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1702 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1703 int *diraft_retp, nfsattrbit_t *attrbitp,
1704 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1709 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1710 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1711 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1712 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1713 if (nd->nd_flag & ND_NFSV3) {
1714 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1715 if (!nd->nd_repstat)
1716 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1717 nvap, nd->nd_cred, p, 1);
1719 if (vpp != NULL && nd->nd_repstat == 0) {
1720 VOP_UNLOCK(ndp->ni_vp, 0);
1726 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1729 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1730 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1731 *tl++ = newnfs_false;
1732 txdr_hyper(dirforp->na_filerev, tl);
1734 txdr_hyper(diraftp->na_filerev, tl);
1735 (void) nfsrv_putattrbit(nd, attrbitp);
1743 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1744 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1745 struct nfsexstuff *exp)
1747 struct nfsvattr nva, dirfor, diraft;
1748 struct nameidata named;
1750 int error, dirfor_ret = 1, diraft_ret = 1;
1751 vnode_t dirp = NULL;
1755 if (nd->nd_repstat) {
1756 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1759 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1760 LOCKPARENT | SAVENAME);
1761 nfsvno_setpathbuf(&named, &bufp, &hashp);
1762 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1765 nfsvno_relpathbuf(&named);
1768 if (!nd->nd_repstat) {
1769 NFSVNO_ATTRINIT(&nva);
1770 if (nd->nd_flag & ND_NFSV3) {
1771 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1774 nfsvno_relpathbuf(&named);
1778 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1779 nva.na_mode = nfstov_mode(*tl++);
1782 if (!nd->nd_repstat) {
1783 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1786 nfsvno_relpathbuf(&named);
1788 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1792 if (nd->nd_repstat) {
1794 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1798 if (nd->nd_flag & ND_NFSV3)
1799 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1804 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1807 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1809 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1810 &diraft_ret, NULL, NULL, p, exp);
1812 if (nd->nd_flag & ND_NFSV3) {
1813 if (!nd->nd_repstat) {
1814 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1815 nfsrv_postopattr(nd, 0, &nva);
1817 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1818 } else if (!nd->nd_repstat) {
1819 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1820 nfsrv_fillattr(nd, &nva);
1825 nfsvno_relpathbuf(&named);
1830 * Code common to mkdir for V2,3 and 4.
1833 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1834 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1835 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1836 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1837 NFSPROC_T *p, struct nfsexstuff *exp)
1842 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1843 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1844 nd->nd_cred, p, exp);
1845 if (!nd->nd_repstat) {
1847 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1848 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1849 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1850 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1852 if (vpp && !nd->nd_repstat) {
1853 NFSVOPUNLOCK(vp, 0, p);
1860 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1863 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1864 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1865 *tl++ = newnfs_false;
1866 txdr_hyper(dirforp->na_filerev, tl);
1868 txdr_hyper(diraftp->na_filerev, tl);
1869 (void) nfsrv_putattrbit(nd, attrbitp);
1874 * nfs commit service
1877 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1878 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1880 struct nfsvattr bfor, aft;
1882 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1885 if (nd->nd_repstat) {
1886 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1889 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1891 * XXX At this time VOP_FSYNC() does not accept offset and byte
1892 * count parameters, so these arguments are useless (someday maybe).
1894 off = fxdr_hyper(tl);
1896 cnt = fxdr_unsigned(int, *tl);
1897 if (nd->nd_flag & ND_NFSV3)
1898 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1899 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1900 if (nd->nd_flag & ND_NFSV3) {
1901 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1902 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1905 if (!nd->nd_repstat) {
1906 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1907 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1908 *tl = txdr_unsigned(nfsboottime.tv_usec);
1917 * nfs statfs service
1920 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1921 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1930 if (nd->nd_repstat) {
1931 nfsrv_postopattr(nd, getret, &at);
1935 nd->nd_repstat = nfsvno_statfs(vp, sf);
1936 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1938 if (nd->nd_flag & ND_NFSV3)
1939 nfsrv_postopattr(nd, getret, &at);
1942 if (nd->nd_flag & ND_NFSV2) {
1943 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1944 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1945 *tl++ = txdr_unsigned(sf->f_bsize);
1946 *tl++ = txdr_unsigned(sf->f_blocks);
1947 *tl++ = txdr_unsigned(sf->f_bfree);
1948 *tl = txdr_unsigned(sf->f_bavail);
1950 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1951 tval = (u_quad_t)sf->f_blocks;
1952 tval *= (u_quad_t)sf->f_bsize;
1953 txdr_hyper(tval, tl); tl += 2;
1954 tval = (u_quad_t)sf->f_bfree;
1955 tval *= (u_quad_t)sf->f_bsize;
1956 txdr_hyper(tval, tl); tl += 2;
1957 tval = (u_quad_t)sf->f_bavail;
1958 tval *= (u_quad_t)sf->f_bsize;
1959 txdr_hyper(tval, tl); tl += 2;
1960 tval = (u_quad_t)sf->f_files;
1961 txdr_hyper(tval, tl); tl += 2;
1962 tval = (u_quad_t)sf->f_ffree;
1963 txdr_hyper(tval, tl); tl += 2;
1964 tval = (u_quad_t)sf->f_ffree;
1965 txdr_hyper(tval, tl); tl += 2;
1972 * nfs fsinfo service
1975 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1976 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1979 struct nfsfsinfo fs;
1983 if (nd->nd_repstat) {
1984 nfsrv_postopattr(nd, getret, &at);
1987 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1988 nfsvno_getfs(&fs, isdgram);
1990 nfsrv_postopattr(nd, getret, &at);
1991 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1992 *tl++ = txdr_unsigned(fs.fs_rtmax);
1993 *tl++ = txdr_unsigned(fs.fs_rtpref);
1994 *tl++ = txdr_unsigned(fs.fs_rtmult);
1995 *tl++ = txdr_unsigned(fs.fs_wtmax);
1996 *tl++ = txdr_unsigned(fs.fs_wtpref);
1997 *tl++ = txdr_unsigned(fs.fs_wtmult);
1998 *tl++ = txdr_unsigned(fs.fs_dtpref);
1999 txdr_hyper(fs.fs_maxfilesize, tl);
2001 txdr_nfsv3time(&fs.fs_timedelta, tl);
2003 *tl = txdr_unsigned(fs.fs_properties);
2008 * nfs pathconf service
2011 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2012 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2014 struct nfsv3_pathconf *pc;
2016 register_t linkmax, namemax, chownres, notrunc;
2019 if (nd->nd_repstat) {
2020 nfsrv_postopattr(nd, getret, &at);
2023 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2025 if (!nd->nd_repstat)
2026 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2028 if (!nd->nd_repstat)
2029 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2030 &chownres, nd->nd_cred, p);
2031 if (!nd->nd_repstat)
2032 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2034 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2036 nfsrv_postopattr(nd, getret, &at);
2037 if (!nd->nd_repstat) {
2038 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2039 pc->pc_linkmax = txdr_unsigned(linkmax);
2040 pc->pc_namemax = txdr_unsigned(namemax);
2041 pc->pc_notrunc = txdr_unsigned(notrunc);
2042 pc->pc_chownrestricted = txdr_unsigned(chownres);
2045 * These should probably be supported by VOP_PATHCONF(), but
2046 * until msdosfs is exportable (why would you want to?), the
2047 * Unix defaults should be ok.
2049 pc->pc_caseinsensitive = newnfs_false;
2050 pc->pc_casepreserving = newnfs_true;
2056 * nfsv4 lock service
2059 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2060 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2064 struct nfsstate *stp = NULL;
2065 struct nfslock *lop;
2066 struct nfslockconflict cf;
2068 u_short flags = NFSLCK_LOCK, lflags;
2069 u_int64_t offset, len;
2070 nfsv4stateid_t stateid;
2073 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2074 i = fxdr_unsigned(int, *tl++);
2076 case NFSV4LOCKT_READW:
2077 flags |= NFSLCK_BLOCKING;
2078 case NFSV4LOCKT_READ:
2079 lflags = NFSLCK_READ;
2081 case NFSV4LOCKT_WRITEW:
2082 flags |= NFSLCK_BLOCKING;
2083 case NFSV4LOCKT_WRITE:
2084 lflags = NFSLCK_WRITE;
2087 nd->nd_repstat = NFSERR_BADXDR;
2090 if (*tl++ == newnfs_true)
2091 flags |= NFSLCK_RECLAIM;
2092 offset = fxdr_hyper(tl);
2094 len = fxdr_hyper(tl);
2096 if (*tl == newnfs_true)
2097 flags |= NFSLCK_OPENTOLOCK;
2098 if (flags & NFSLCK_OPENTOLOCK) {
2099 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2100 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2101 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2102 nd->nd_repstat = NFSERR_BADXDR;
2105 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2106 M_NFSDSTATE, M_WAITOK);
2107 stp->ls_ownerlen = i;
2108 stp->ls_op = nd->nd_rp;
2109 stp->ls_seq = fxdr_unsigned(int, *tl++);
2110 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2111 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2113 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2114 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2115 clientid.lval[0] = *tl++;
2116 clientid.lval[1] = *tl++;
2117 if (nd->nd_flag & ND_IMPLIEDCLID) {
2118 if (nd->nd_clientid.qval != clientid.qval)
2119 printf("EEK! multiple clids\n");
2121 nd->nd_flag |= ND_IMPLIEDCLID;
2122 nd->nd_clientid.qval = clientid.qval;
2124 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2128 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2129 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2130 M_NFSDSTATE, M_WAITOK);
2131 stp->ls_ownerlen = 0;
2132 stp->ls_op = nd->nd_rp;
2133 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2134 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2136 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2137 stp->ls_seq = fxdr_unsigned(int, *tl);
2138 clientid.lval[0] = stp->ls_stateid.other[0];
2139 clientid.lval[1] = stp->ls_stateid.other[1];
2140 if (nd->nd_flag & ND_IMPLIEDCLID) {
2141 if (nd->nd_clientid.qval != clientid.qval)
2142 printf("EEK! multiple clids\n");
2144 nd->nd_flag |= ND_IMPLIEDCLID;
2145 nd->nd_clientid.qval = clientid.qval;
2148 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2149 M_NFSDLOCK, M_WAITOK);
2150 lop->lo_first = offset;
2151 if (len == NFS64BITSSET) {
2152 lop->lo_end = NFS64BITSSET;
2154 lop->lo_end = offset + len;
2155 if (lop->lo_end <= lop->lo_first)
2156 nd->nd_repstat = NFSERR_INVAL;
2158 lop->lo_flags = lflags;
2159 stp->ls_flags = flags;
2160 stp->ls_uid = nd->nd_cred->cr_uid;
2163 * Do basic access checking.
2165 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2166 if (vnode_vtype(vp) == VDIR)
2167 nd->nd_repstat = NFSERR_ISDIR;
2169 nd->nd_repstat = NFSERR_INVAL;
2171 if (!nd->nd_repstat) {
2172 if (lflags & NFSLCK_WRITE) {
2173 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2174 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2175 NFSACCCHK_VPISLOCKED, NULL);
2177 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2178 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2179 NFSACCCHK_VPISLOCKED, NULL);
2181 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2182 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2183 NFSACCCHK_VPISLOCKED, NULL);
2188 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2189 * seqid# gets updated. nfsrv_lockctrl() will return the value
2190 * of nd_repstat, if it gets that far.
2192 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2193 &stateid, exp, nd, p);
2195 FREE((caddr_t)lop, M_NFSDLOCK);
2197 FREE((caddr_t)stp, M_NFSDSTATE);
2198 if (!nd->nd_repstat) {
2199 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2200 *tl++ = txdr_unsigned(stateid.seqid);
2201 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2202 } else if (nd->nd_repstat == NFSERR_DENIED) {
2203 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2204 txdr_hyper(cf.cl_first, tl);
2206 if (cf.cl_end == NFS64BITSSET)
2209 len = cf.cl_end - cf.cl_first;
2210 txdr_hyper(len, tl);
2212 if (cf.cl_flags == NFSLCK_WRITE)
2213 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2215 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2216 *tl++ = stateid.other[0];
2217 *tl = stateid.other[1];
2218 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2225 free((caddr_t)stp, M_NFSDSTATE);
2230 * nfsv4 lock test service
2233 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2234 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2238 struct nfsstate *stp = NULL;
2239 struct nfslock lo, *lop = &lo;
2240 struct nfslockconflict cf;
2242 nfsv4stateid_t stateid;
2246 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2247 i = fxdr_unsigned(int, *(tl + 7));
2248 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2249 nd->nd_repstat = NFSERR_BADXDR;
2252 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2253 M_NFSDSTATE, M_WAITOK);
2254 stp->ls_ownerlen = i;
2256 stp->ls_flags = NFSLCK_TEST;
2257 stp->ls_uid = nd->nd_cred->cr_uid;
2258 i = fxdr_unsigned(int, *tl++);
2260 case NFSV4LOCKT_READW:
2261 stp->ls_flags |= NFSLCK_BLOCKING;
2262 case NFSV4LOCKT_READ:
2263 lo.lo_flags = NFSLCK_READ;
2265 case NFSV4LOCKT_WRITEW:
2266 stp->ls_flags |= NFSLCK_BLOCKING;
2267 case NFSV4LOCKT_WRITE:
2268 lo.lo_flags = NFSLCK_WRITE;
2271 nd->nd_repstat = NFSERR_BADXDR;
2274 lo.lo_first = fxdr_hyper(tl);
2276 len = fxdr_hyper(tl);
2277 if (len == NFS64BITSSET) {
2278 lo.lo_end = NFS64BITSSET;
2280 lo.lo_end = lo.lo_first + len;
2281 if (lo.lo_end <= lo.lo_first)
2282 nd->nd_repstat = NFSERR_INVAL;
2285 clientid.lval[0] = *tl++;
2286 clientid.lval[1] = *tl;
2287 if (nd->nd_flag & ND_IMPLIEDCLID) {
2288 if (nd->nd_clientid.qval != clientid.qval)
2289 printf("EEK! multiple clids\n");
2291 nd->nd_flag |= ND_IMPLIEDCLID;
2292 nd->nd_clientid.qval = clientid.qval;
2294 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2297 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2298 if (vnode_vtype(vp) == VDIR)
2299 nd->nd_repstat = NFSERR_ISDIR;
2301 nd->nd_repstat = NFSERR_INVAL;
2303 if (!nd->nd_repstat)
2304 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2305 &stateid, exp, nd, p);
2307 FREE((caddr_t)stp, M_NFSDSTATE);
2308 if (nd->nd_repstat) {
2309 if (nd->nd_repstat == NFSERR_DENIED) {
2310 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2311 txdr_hyper(cf.cl_first, tl);
2313 if (cf.cl_end == NFS64BITSSET)
2316 len = cf.cl_end - cf.cl_first;
2317 txdr_hyper(len, tl);
2319 if (cf.cl_flags == NFSLCK_WRITE)
2320 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2322 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2323 *tl++ = stp->ls_stateid.other[0];
2324 *tl = stp->ls_stateid.other[1];
2325 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2333 free((caddr_t)stp, M_NFSDSTATE);
2338 * nfsv4 unlock service
2341 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2342 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2346 struct nfsstate *stp;
2347 struct nfslock *lop;
2349 nfsv4stateid_t stateid;
2353 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2354 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2355 M_NFSDSTATE, M_WAITOK);
2356 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2357 M_NFSDLOCK, M_WAITOK);
2358 stp->ls_flags = NFSLCK_UNLOCK;
2359 lop->lo_flags = NFSLCK_UNLOCK;
2360 stp->ls_op = nd->nd_rp;
2361 i = fxdr_unsigned(int, *tl++);
2363 case NFSV4LOCKT_READW:
2364 stp->ls_flags |= NFSLCK_BLOCKING;
2365 case NFSV4LOCKT_READ:
2367 case NFSV4LOCKT_WRITEW:
2368 stp->ls_flags |= NFSLCK_BLOCKING;
2369 case NFSV4LOCKT_WRITE:
2372 nd->nd_repstat = NFSERR_BADXDR;
2373 free(stp, M_NFSDSTATE);
2374 free(lop, M_NFSDLOCK);
2377 stp->ls_ownerlen = 0;
2378 stp->ls_uid = nd->nd_cred->cr_uid;
2379 stp->ls_seq = fxdr_unsigned(int, *tl++);
2380 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2381 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2383 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2384 lop->lo_first = fxdr_hyper(tl);
2386 len = fxdr_hyper(tl);
2387 if (len == NFS64BITSSET) {
2388 lop->lo_end = NFS64BITSSET;
2390 lop->lo_end = lop->lo_first + len;
2391 if (lop->lo_end <= lop->lo_first)
2392 nd->nd_repstat = NFSERR_INVAL;
2394 clientid.lval[0] = stp->ls_stateid.other[0];
2395 clientid.lval[1] = stp->ls_stateid.other[1];
2396 if (nd->nd_flag & ND_IMPLIEDCLID) {
2397 if (nd->nd_clientid.qval != clientid.qval)
2398 printf("EEK! multiple clids\n");
2400 nd->nd_flag |= ND_IMPLIEDCLID;
2401 nd->nd_clientid.qval = clientid.qval;
2403 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2404 if (vnode_vtype(vp) == VDIR)
2405 nd->nd_repstat = NFSERR_ISDIR;
2407 nd->nd_repstat = NFSERR_INVAL;
2410 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2411 * seqid# gets incremented. nfsrv_lockctrl() will return the
2412 * value of nd_repstat, if it gets that far.
2414 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2415 &stateid, exp, nd, p);
2417 FREE((caddr_t)stp, M_NFSDSTATE);
2419 free((caddr_t)lop, M_NFSDLOCK);
2420 if (!nd->nd_repstat) {
2421 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2422 *tl++ = txdr_unsigned(stateid.seqid);
2423 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2431 * nfsv4 open service
2434 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2435 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2436 struct nfsexstuff *exp)
2440 struct nfsstate *stp = NULL;
2441 int error = 0, create, claim, exclusive_flag = 0;
2442 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2443 int how = NFSCREATE_UNCHECKED;
2444 int32_t cverf[2], tverf[2] = { 0, 0 };
2445 vnode_t vp = NULL, dirp = NULL;
2446 struct nfsvattr nva, dirfor, diraft;
2447 struct nameidata named;
2448 nfsv4stateid_t stateid, delegstateid;
2449 nfsattrbit_t attrbits;
2453 NFSACL_T *aclp = NULL;
2455 #ifdef NFS4_ACL_EXTATTR_NAME
2456 aclp = acl_alloc(M_WAITOK);
2459 NFSZERO_ATTRBIT(&attrbits);
2460 named.ni_startdir = NULL;
2461 named.ni_cnd.cn_nameiop = 0;
2462 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2463 i = fxdr_unsigned(int, *(tl + 5));
2464 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2465 nd->nd_repstat = NFSERR_BADXDR;
2467 #ifdef NFS4_ACL_EXTATTR_NAME
2472 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2473 M_NFSDSTATE, M_WAITOK);
2474 stp->ls_ownerlen = i;
2475 stp->ls_op = nd->nd_rp;
2476 stp->ls_flags = NFSLCK_OPEN;
2477 stp->ls_uid = nd->nd_cred->cr_uid;
2478 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2479 i = fxdr_unsigned(int, *tl++);
2481 case NFSV4OPEN_ACCESSREAD:
2482 stp->ls_flags |= NFSLCK_READACCESS;
2484 case NFSV4OPEN_ACCESSWRITE:
2485 stp->ls_flags |= NFSLCK_WRITEACCESS;
2487 case NFSV4OPEN_ACCESSBOTH:
2488 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2491 nd->nd_repstat = NFSERR_INVAL;
2493 i = fxdr_unsigned(int, *tl++);
2495 case NFSV4OPEN_DENYNONE:
2497 case NFSV4OPEN_DENYREAD:
2498 stp->ls_flags |= NFSLCK_READDENY;
2500 case NFSV4OPEN_DENYWRITE:
2501 stp->ls_flags |= NFSLCK_WRITEDENY;
2503 case NFSV4OPEN_DENYBOTH:
2504 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2507 nd->nd_repstat = NFSERR_INVAL;
2509 clientid.lval[0] = *tl++;
2510 clientid.lval[1] = *tl;
2511 if (nd->nd_flag & ND_IMPLIEDCLID) {
2512 if (nd->nd_clientid.qval != clientid.qval)
2513 printf("EEK! multiple clids\n");
2515 nd->nd_flag |= ND_IMPLIEDCLID;
2516 nd->nd_clientid.qval = clientid.qval;
2518 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2521 #ifdef NFS4_ACL_EXTATTR_NAME
2524 FREE((caddr_t)stp, M_NFSDSTATE);
2527 NFSVNO_ATTRINIT(&nva);
2528 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2529 create = fxdr_unsigned(int, *tl);
2530 if (!nd->nd_repstat)
2531 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2532 if (create == NFSV4OPEN_CREATE) {
2535 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2536 how = fxdr_unsigned(int, *tl);
2538 case NFSCREATE_UNCHECKED:
2539 case NFSCREATE_GUARDED:
2540 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2543 #ifdef NFS4_ACL_EXTATTR_NAME
2546 FREE((caddr_t)stp, M_NFSDSTATE);
2550 * If the na_gid being set is the same as that of
2551 * the directory it is going in, clear it, since
2552 * that is what will be set by default. This allows
2553 * a user that isn't in that group to do the create.
2555 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2556 nva.na_gid == dirfor.na_gid)
2557 NFSVNO_UNSET(&nva, gid);
2558 if (!nd->nd_repstat)
2559 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2561 case NFSCREATE_EXCLUSIVE:
2562 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2567 nd->nd_repstat = NFSERR_BADXDR;
2569 #ifdef NFS4_ACL_EXTATTR_NAME
2572 FREE((caddr_t)stp, M_NFSDSTATE);
2575 } else if (create != NFSV4OPEN_NOCREATE) {
2576 nd->nd_repstat = NFSERR_BADXDR;
2578 #ifdef NFS4_ACL_EXTATTR_NAME
2581 FREE((caddr_t)stp, M_NFSDSTATE);
2586 * Now, handle the claim, which usually includes looking up a
2587 * name in the directory referenced by dp. The exception is
2588 * NFSV4OPEN_CLAIMPREVIOUS.
2590 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2591 claim = fxdr_unsigned(int, *tl);
2592 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2593 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2594 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2595 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2596 stp->ls_flags |= NFSLCK_DELEGCUR;
2597 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2598 stp->ls_flags |= NFSLCK_DELEGPREV;
2600 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2601 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2602 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2603 claim != NFSV4OPEN_CLAIMNULL)
2604 nd->nd_repstat = NFSERR_INVAL;
2605 if (nd->nd_repstat) {
2606 nd->nd_repstat = nfsrv_opencheck(clientid,
2607 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2609 #ifdef NFS4_ACL_EXTATTR_NAME
2612 FREE((caddr_t)stp, M_NFSDSTATE);
2615 if (create == NFSV4OPEN_CREATE)
2616 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2617 LOCKPARENT | LOCKLEAF | SAVESTART);
2619 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2620 LOCKLEAF | SAVESTART);
2621 nfsvno_setpathbuf(&named, &bufp, &hashp);
2622 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2625 #ifdef NFS4_ACL_EXTATTR_NAME
2628 FREE((caddr_t)stp, M_NFSDSTATE);
2629 nfsvno_relpathbuf(&named);
2632 if (!nd->nd_repstat) {
2633 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2637 nfsvno_relpathbuf(&named);
2639 if (create == NFSV4OPEN_CREATE) {
2641 case NFSCREATE_UNCHECKED:
2644 * Clear the setable attribute bits, except
2645 * for Size, if it is being truncated.
2647 NFSZERO_ATTRBIT(&attrbits);
2648 if (NFSVNO_ISSETSIZE(&nva))
2649 NFSSETBIT_ATTRBIT(&attrbits,
2653 case NFSCREATE_GUARDED:
2654 if (named.ni_vp && !nd->nd_repstat)
2655 nd->nd_repstat = EEXIST;
2657 case NFSCREATE_EXCLUSIVE:
2663 nfsvno_open(nd, &named, clientid, &stateid, stp,
2664 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2665 nd->nd_cred, p, exp, &vp);
2666 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2667 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2668 i = fxdr_unsigned(int, *tl);
2670 case NFSV4OPEN_DELEGATEREAD:
2671 stp->ls_flags |= NFSLCK_DELEGREAD;
2673 case NFSV4OPEN_DELEGATEWRITE:
2674 stp->ls_flags |= NFSLCK_DELEGWRITE;
2675 case NFSV4OPEN_DELEGATENONE:
2678 nd->nd_repstat = NFSERR_BADXDR;
2680 #ifdef NFS4_ACL_EXTATTR_NAME
2683 FREE((caddr_t)stp, M_NFSDSTATE);
2686 stp->ls_flags |= NFSLCK_RECLAIM;
2688 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2689 if ((vp->v_iflag & VI_DOOMED) == 0)
2690 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2691 stp, vp, nd, p, nd->nd_repstat);
2693 nd->nd_repstat = NFSERR_PERM;
2695 nd->nd_repstat = NFSERR_BADXDR;
2697 #ifdef NFS4_ACL_EXTATTR_NAME
2700 FREE((caddr_t)stp, M_NFSDSTATE);
2705 * Do basic access checking.
2707 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2708 if (vnode_vtype(vp) == VDIR)
2709 nd->nd_repstat = NFSERR_ISDIR;
2710 else if (vnode_vtype(vp) == VLNK)
2711 nd->nd_repstat = NFSERR_SYMLINK;
2713 nd->nd_repstat = NFSERR_INVAL;
2715 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2716 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2717 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2718 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2719 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2720 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2722 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2723 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2724 NFSACCCHK_VPISLOCKED, NULL);
2727 if (!nd->nd_repstat) {
2728 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2729 if (!nd->nd_repstat) {
2730 tverf[0] = nva.na_atime.tv_sec;
2731 tverf[1] = nva.na_atime.tv_nsec;
2734 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2735 cverf[1] != tverf[1]))
2736 nd->nd_repstat = EEXIST;
2738 * Do the open locking/delegation stuff.
2740 if (!nd->nd_repstat)
2741 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2742 &delegstateid, &rflags, exp, p, nva.na_filerev);
2745 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2746 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2747 * (ie: Leave the NFSVOPUNLOCK() about here.)
2750 NFSVOPUNLOCK(vp, 0, p);
2752 FREE((caddr_t)stp, M_NFSDSTATE);
2753 if (!nd->nd_repstat && dirp)
2754 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2756 if (!nd->nd_repstat) {
2757 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2758 *tl++ = txdr_unsigned(stateid.seqid);
2759 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2760 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2761 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2762 *tl++ = newnfs_true;
2768 *tl++ = newnfs_false; /* Since dirp is not locked */
2769 txdr_hyper(dirfor.na_filerev, tl);
2771 txdr_hyper(diraft.na_filerev, tl);
2774 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2775 (void) nfsrv_putattrbit(nd, &attrbits);
2776 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2777 if (rflags & NFSV4OPEN_READDELEGATE)
2778 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2779 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2780 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2782 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2783 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2784 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2785 *tl++ = txdr_unsigned(delegstateid.seqid);
2786 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2788 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2789 if (rflags & NFSV4OPEN_RECALL)
2793 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2794 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2795 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2796 txdr_hyper(nva.na_size, tl);
2798 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2799 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2800 *tl++ = txdr_unsigned(0x0);
2801 acemask = NFSV4ACE_ALLFILESMASK;
2802 if (nva.na_mode & S_IRUSR)
2803 acemask |= NFSV4ACE_READMASK;
2804 if (nva.na_mode & S_IWUSR)
2805 acemask |= NFSV4ACE_WRITEMASK;
2806 if (nva.na_mode & S_IXUSR)
2807 acemask |= NFSV4ACE_EXECUTEMASK;
2808 *tl = txdr_unsigned(acemask);
2809 (void) nfsm_strtom(nd, "OWNER@", 6);
2817 #ifdef NFS4_ACL_EXTATTR_NAME
2823 #ifdef NFS4_ACL_EXTATTR_NAME
2827 FREE((caddr_t)stp, M_NFSDSTATE);
2832 * nfsv4 close service
2835 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2836 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2839 struct nfsstate st, *stp = &st;
2841 nfsv4stateid_t stateid;
2844 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2845 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2846 stp->ls_ownerlen = 0;
2847 stp->ls_op = nd->nd_rp;
2848 stp->ls_uid = nd->nd_cred->cr_uid;
2849 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2850 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2852 stp->ls_flags = NFSLCK_CLOSE;
2853 clientid.lval[0] = stp->ls_stateid.other[0];
2854 clientid.lval[1] = stp->ls_stateid.other[1];
2855 if (nd->nd_flag & ND_IMPLIEDCLID) {
2856 if (nd->nd_clientid.qval != clientid.qval)
2857 printf("EEK! multiple clids\n");
2859 nd->nd_flag |= ND_IMPLIEDCLID;
2860 nd->nd_clientid.qval = clientid.qval;
2862 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2864 if (!nd->nd_repstat) {
2865 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2866 *tl++ = txdr_unsigned(stateid.seqid);
2867 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2876 * nfsv4 delegpurge service
2879 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2880 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2886 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2887 nd->nd_repstat = NFSERR_WRONGSEC;
2890 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2891 clientid.lval[0] = *tl++;
2892 clientid.lval[1] = *tl;
2893 if (nd->nd_flag & ND_IMPLIEDCLID) {
2894 if (nd->nd_clientid.qval != clientid.qval)
2895 printf("EEK! multiple clids\n");
2897 nd->nd_flag |= ND_IMPLIEDCLID;
2898 nd->nd_clientid.qval = clientid.qval;
2900 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2901 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2907 * nfsv4 delegreturn service
2910 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2911 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2915 nfsv4stateid_t stateid;
2918 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2919 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2920 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2921 clientid.lval[0] = stateid.other[0];
2922 clientid.lval[1] = stateid.other[1];
2923 if (nd->nd_flag & ND_IMPLIEDCLID) {
2924 if (nd->nd_clientid.qval != clientid.qval)
2925 printf("EEK! multiple clids\n");
2927 nd->nd_flag |= ND_IMPLIEDCLID;
2928 nd->nd_clientid.qval = clientid.qval;
2930 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2931 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2938 * nfsv4 get file handle service
2941 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2942 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2946 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2948 if (!nd->nd_repstat)
2949 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2954 * nfsv4 open confirm service
2957 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2958 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2961 struct nfsstate st, *stp = &st;
2963 nfsv4stateid_t stateid;
2966 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2967 stp->ls_ownerlen = 0;
2968 stp->ls_op = nd->nd_rp;
2969 stp->ls_uid = nd->nd_cred->cr_uid;
2970 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2971 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2973 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2974 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2975 stp->ls_flags = NFSLCK_CONFIRM;
2976 clientid.lval[0] = stp->ls_stateid.other[0];
2977 clientid.lval[1] = stp->ls_stateid.other[1];
2978 if (nd->nd_flag & ND_IMPLIEDCLID) {
2979 if (nd->nd_clientid.qval != clientid.qval)
2980 printf("EEK! multiple clids\n");
2982 nd->nd_flag |= ND_IMPLIEDCLID;
2983 nd->nd_clientid.qval = clientid.qval;
2985 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2986 if (!nd->nd_repstat) {
2987 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2988 *tl++ = txdr_unsigned(stateid.seqid);
2989 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2997 * nfsv4 open downgrade service
3000 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3001 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3005 struct nfsstate st, *stp = &st;
3007 nfsv4stateid_t stateid;
3010 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3011 stp->ls_ownerlen = 0;
3012 stp->ls_op = nd->nd_rp;
3013 stp->ls_uid = nd->nd_cred->cr_uid;
3014 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3015 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3017 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3018 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3019 i = fxdr_unsigned(int, *tl++);
3021 case NFSV4OPEN_ACCESSREAD:
3022 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3024 case NFSV4OPEN_ACCESSWRITE:
3025 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3027 case NFSV4OPEN_ACCESSBOTH:
3028 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3032 nd->nd_repstat = NFSERR_BADXDR;
3034 i = fxdr_unsigned(int, *tl);
3036 case NFSV4OPEN_DENYNONE:
3038 case NFSV4OPEN_DENYREAD:
3039 stp->ls_flags |= NFSLCK_READDENY;
3041 case NFSV4OPEN_DENYWRITE:
3042 stp->ls_flags |= NFSLCK_WRITEDENY;
3044 case NFSV4OPEN_DENYBOTH:
3045 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3048 nd->nd_repstat = NFSERR_BADXDR;
3051 clientid.lval[0] = stp->ls_stateid.other[0];
3052 clientid.lval[1] = stp->ls_stateid.other[1];
3053 if (nd->nd_flag & ND_IMPLIEDCLID) {
3054 if (nd->nd_clientid.qval != clientid.qval)
3055 printf("EEK! multiple clids\n");
3057 nd->nd_flag |= ND_IMPLIEDCLID;
3058 nd->nd_clientid.qval = clientid.qval;
3060 if (!nd->nd_repstat)
3061 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3063 if (!nd->nd_repstat) {
3064 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3065 *tl++ = txdr_unsigned(stateid.seqid);
3066 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3074 * nfsv4 renew lease service
3077 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3078 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3084 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3085 nd->nd_repstat = NFSERR_WRONGSEC;
3088 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3089 clientid.lval[0] = *tl++;
3090 clientid.lval[1] = *tl;
3091 if (nd->nd_flag & ND_IMPLIEDCLID) {
3092 if (nd->nd_clientid.qval != clientid.qval)
3093 printf("EEK! multiple clids\n");
3095 nd->nd_flag |= ND_IMPLIEDCLID;
3096 nd->nd_clientid.qval = clientid.qval;
3098 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3099 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3105 * nfsv4 security info service
3108 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3109 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3113 struct nameidata named;
3114 vnode_t dirp = NULL, vp;
3116 struct nfsexstuff retnes;
3118 int error, savflag, i;
3123 * All this just to get the export flags for the name.
3125 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3126 LOCKLEAF | SAVESTART);
3127 nfsvno_setpathbuf(&named, &bufp, &hashp);
3128 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3131 nfsvno_relpathbuf(&named);
3134 if (!nd->nd_repstat) {
3135 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3138 nfsvno_relpathbuf(&named);
3144 vrele(named.ni_startdir);
3145 nfsvno_relpathbuf(&named);
3146 fh.nfsrvfh_len = NFSX_MYFH;
3148 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3150 savflag = nd->nd_flag;
3151 if (!nd->nd_repstat) {
3152 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3156 nd->nd_flag = savflag;
3161 * Finally have the export flags for name, so we can create
3162 * the security info.
3165 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3166 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3167 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3169 *tl = txdr_unsigned(RPCAUTH_UNIX);
3171 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3172 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3173 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3174 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3175 nfsgss_mechlist[KERBV_MECH].len);
3176 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3177 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3178 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3180 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3181 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3182 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3183 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3184 nfsgss_mechlist[KERBV_MECH].len);
3185 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3186 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3187 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3189 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3191 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3192 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3193 nfsgss_mechlist[KERBV_MECH].len);
3194 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3195 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3196 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3200 *sizp = txdr_unsigned(len);
3205 * nfsv4 set client id service
3208 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3209 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3213 int error = 0, idlen;
3214 struct nfsclient *clp = NULL;
3215 struct sockaddr_in *rad;
3216 u_char *verf, *ucp, *ucp2, addrbuf[24];
3217 nfsquad_t clientid, confirm;
3219 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3220 nd->nd_repstat = NFSERR_WRONGSEC;
3223 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3224 verf = (u_char *)tl;
3225 tl += (NFSX_VERF / NFSX_UNSIGNED);
3226 i = fxdr_unsigned(int, *tl);
3227 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3228 nd->nd_repstat = NFSERR_BADXDR;
3232 if (nd->nd_flag & ND_GSS)
3233 i += nd->nd_princlen;
3234 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3235 M_NFSDCLIENT, M_WAITOK);
3236 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3237 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3238 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3239 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3240 clp->lc_req.nr_cred = NULL;
3241 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3242 clp->lc_idlen = idlen;
3243 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3246 if (nd->nd_flag & ND_GSS) {
3247 clp->lc_flags = LCL_GSS;
3248 if (nd->nd_flag & ND_GSSINTEGRITY)
3249 clp->lc_flags |= LCL_GSSINTEGRITY;
3250 else if (nd->nd_flag & ND_GSSPRIVACY)
3251 clp->lc_flags |= LCL_GSSPRIVACY;
3255 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3256 clp->lc_flags |= LCL_NAME;
3257 clp->lc_namelen = nd->nd_princlen;
3258 clp->lc_name = &clp->lc_id[idlen];
3259 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3261 clp->lc_uid = nd->nd_cred->cr_uid;
3262 clp->lc_gid = nd->nd_cred->cr_gid;
3264 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3265 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3266 error = nfsrv_getclientipaddr(nd, clp);
3269 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3270 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3273 * nfsrv_setclient() does the actual work of adding it to the
3274 * client list. If there is no error, the structure has been
3275 * linked into the client list and clp should no longer be used
3276 * here. When an error is returned, it has not been linked in,
3277 * so it should be free'd.
3279 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3280 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3281 if (clp->lc_flags & LCL_TCPCALLBACK)
3282 (void) nfsm_strtom(nd, "tcp", 3);
3284 (void) nfsm_strtom(nd, "udp", 3);
3285 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3286 ucp = (u_char *)&rad->sin_addr.s_addr;
3287 ucp2 = (u_char *)&rad->sin_port;
3288 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3289 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3290 ucp2[0] & 0xff, ucp2[1] & 0xff);
3291 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3294 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3295 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3296 free((caddr_t)clp, M_NFSDCLIENT);
3298 if (!nd->nd_repstat) {
3299 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3300 *tl++ = clientid.lval[0];
3301 *tl++ = clientid.lval[1];
3302 *tl++ = confirm.lval[0];
3303 *tl = confirm.lval[1];
3308 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3309 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3310 free((caddr_t)clp, M_NFSDCLIENT);
3316 * nfsv4 set client id confirm service
3319 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3320 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3321 __unused struct nfsexstuff *exp)
3325 nfsquad_t clientid, confirm;
3327 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3328 nd->nd_repstat = NFSERR_WRONGSEC;
3331 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3332 clientid.lval[0] = *tl++;
3333 clientid.lval[1] = *tl++;
3334 confirm.lval[0] = *tl++;
3335 confirm.lval[1] = *tl;
3338 * nfsrv_getclient() searches the client list for a match and
3339 * returns the appropriate NFSERR status.
3341 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3342 NULL, confirm, nd, p);
3348 * nfsv4 verify service
3351 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3352 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3354 int error = 0, ret, fhsize = NFSX_MYFH;
3355 struct nfsvattr nva;
3357 struct nfsfsinfo fs;
3360 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3361 if (!nd->nd_repstat)
3362 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3363 if (!nd->nd_repstat)
3364 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3365 if (!nd->nd_repstat) {
3366 nfsvno_getfs(&fs, isdgram);
3367 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3368 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3370 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3372 nd->nd_repstat = NFSERR_SAME;
3373 else if (ret != NFSERR_NOTSAME)
3374 nd->nd_repstat = ret;
3376 nd->nd_repstat = ret;
3387 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3388 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3389 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3392 int error = 0, createdir;
3394 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3395 createdir = fxdr_unsigned(int, *tl);
3396 nd->nd_repstat = NFSERR_NOTSUPP;
3403 * nfsv4 release lock owner service
3406 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3407 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3410 struct nfsstate *stp = NULL;
3414 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3415 nd->nd_repstat = NFSERR_WRONGSEC;
3418 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3419 len = fxdr_unsigned(int, *(tl + 2));
3420 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3421 nd->nd_repstat = NFSERR_BADXDR;
3424 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3425 M_NFSDSTATE, M_WAITOK);
3426 stp->ls_ownerlen = len;
3428 stp->ls_flags = NFSLCK_RELEASE;
3429 stp->ls_uid = nd->nd_cred->cr_uid;
3430 clientid.lval[0] = *tl++;
3431 clientid.lval[1] = *tl;
3432 if (nd->nd_flag & ND_IMPLIEDCLID) {
3433 if (nd->nd_clientid.qval != clientid.qval)
3434 printf("EEK! multiple clids\n");
3436 nd->nd_flag |= ND_IMPLIEDCLID;
3437 nd->nd_clientid.qval = clientid.qval;
3439 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3442 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3443 FREE((caddr_t)stp, M_NFSDSTATE);
3447 free((caddr_t)stp, M_NFSDSTATE);