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;
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) {
217 if (nfsrv_enable_crossmntpt != 0 &&
218 vp->v_type == VDIR &&
219 (vp->v_vflag & VV_ROOT) != 0 &&
221 tvp = mp->mnt_vnodecovered;
229 if ((nd->nd_repstat =
230 vn_lock(tvp, LK_SHARED)) == 0) {
231 nd->nd_repstat = VOP_GETATTR(
232 tvp, &va, nd->nd_cred);
236 if (nd->nd_repstat == 0)
237 mounted_on_fileno = (uint64_t)
242 if (nd->nd_repstat == 0)
243 nd->nd_repstat = vfs_busy(mp, 0);
245 if (nd->nd_repstat == 0) {
246 (void)nfsvno_fillattr(nd, mp, vp, &nva,
247 &fh, 0, &attrbits, nd->nd_cred, p,
256 nfsrv_fillattr(nd, &nva);
266 * nfs setattr service
269 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
270 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
272 struct nfsvattr nva, nva2;
274 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
275 struct timespec guard = { 0, 0 };
276 nfsattrbit_t attrbits, retbits;
277 nfsv4stateid_t stateid;
278 NFSACL_T *aclp = NULL;
280 if (nd->nd_repstat) {
281 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
284 #ifdef NFS4_ACL_EXTATTR_NAME
285 aclp = acl_alloc(M_WAITOK);
288 NFSVNO_ATTRINIT(&nva);
289 NFSZERO_ATTRBIT(&retbits);
290 if (nd->nd_flag & ND_NFSV4) {
291 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
292 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
293 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
295 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
298 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
300 nd->nd_repstat = preat_ret;
301 if (nd->nd_flag & ND_NFSV3) {
302 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
303 gcheck = fxdr_unsigned(int, *tl);
305 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
306 fxdr_nfsv3time(tl, &guard);
308 if (!nd->nd_repstat && gcheck &&
309 (nva2.na_ctime.tv_sec != guard.tv_sec ||
310 nva2.na_ctime.tv_nsec != guard.tv_nsec))
311 nd->nd_repstat = NFSERR_NOT_SYNC;
312 if (nd->nd_repstat) {
314 #ifdef NFS4_ACL_EXTATTR_NAME
317 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
320 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
321 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
324 * Now that we have all the fields, lets do it.
325 * If the size is being changed write access is required, otherwise
326 * just check for a read only file system.
328 if (!nd->nd_repstat) {
329 if (NFSVNO_NOTSETSIZE(&nva)) {
330 if (NFSVNO_EXRDONLY(exp) ||
331 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
332 nd->nd_repstat = EROFS;
334 if (vnode_vtype(vp) != VREG)
335 nd->nd_repstat = EINVAL;
336 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
337 NFSVNO_EXSTRICTACCESS(exp))
338 nd->nd_repstat = nfsvno_accchk(vp,
339 VWRITE, nd->nd_cred, exp, p,
340 NFSACCCHK_NOOVERRIDE,
341 NFSACCCHK_VPISLOCKED, NULL);
344 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
345 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
346 &nva, &attrbits, exp, p);
348 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
350 * For V4, try setting the attrbutes in sets, so that the
351 * reply bitmap will be correct for an error case.
353 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
354 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
355 NFSVNO_ATTRINIT(&nva2);
356 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
357 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
358 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
360 if (!nd->nd_repstat) {
361 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
362 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
363 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
364 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
367 if (!nd->nd_repstat &&
368 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
369 NFSVNO_ATTRINIT(&nva2);
370 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
371 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
374 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
376 if (!nd->nd_repstat &&
377 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
378 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
379 NFSVNO_ATTRINIT(&nva2);
380 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
381 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
382 if (nva.na_vaflags & VA_UTIMES_NULL) {
383 nva2.na_vaflags |= VA_UTIMES_NULL;
384 NFSVNO_SETACTIVE(&nva2, vaflags);
386 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
388 if (!nd->nd_repstat) {
389 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
390 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
391 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
392 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
395 if (!nd->nd_repstat &&
396 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
397 NFSVNO_ATTRINIT(&nva2);
398 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
399 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
402 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
405 #ifdef NFS4_ACL_EXTATTR_NAME
406 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
407 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
408 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
410 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
413 } else if (!nd->nd_repstat) {
414 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
417 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
418 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
420 nd->nd_repstat = postat_ret;
423 #ifdef NFS4_ACL_EXTATTR_NAME
426 if (nd->nd_flag & ND_NFSV3)
427 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
428 else if (nd->nd_flag & ND_NFSV4)
429 (void) nfsrv_putattrbit(nd, &retbits);
430 else if (!nd->nd_repstat)
431 nfsrv_fillattr(nd, &nva);
435 #ifdef NFS4_ACL_EXTATTR_NAME
438 if (nd->nd_flag & ND_NFSV4) {
440 * For all nd_repstat, the V4 reply includes a bitmap,
441 * even NFSERR_BADXDR, which is what this will end up
444 (void) nfsrv_putattrbit(nd, &retbits);
451 * (Also performs lookup parent for v4)
454 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
455 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
456 __unused struct nfsexstuff *exp)
458 struct nameidata named;
459 vnode_t vp, dirp = NULL;
460 int error, dattr_ret = 1;
461 struct nfsvattr nva, dattr;
465 if (nd->nd_repstat) {
466 nfsrv_postopattr(nd, dattr_ret, &dattr);
471 * For some reason, if dp is a symlink, the error
472 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
474 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
475 nd->nd_repstat = NFSERR_SYMLINK;
480 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
481 LOCKLEAF | SAVESTART);
482 nfsvno_setpathbuf(&named, &bufp, &hashp);
483 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
486 nfsvno_relpathbuf(&named);
489 if (!nd->nd_repstat) {
490 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
493 nfsvno_relpathbuf(&named);
495 if (nd->nd_repstat) {
497 if (nd->nd_flag & ND_NFSV3)
498 dattr_ret = nfsvno_getattr(dirp, &dattr,
502 if (nd->nd_flag & ND_NFSV3)
503 nfsrv_postopattr(nd, dattr_ret, &dattr);
506 if (named.ni_startdir)
507 vrele(named.ni_startdir);
508 nfsvno_relpathbuf(&named);
510 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
511 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
512 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
513 if (vpp != NULL && nd->nd_repstat == 0)
518 if (nd->nd_flag & ND_NFSV3)
519 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
523 if (nd->nd_repstat) {
524 if (nd->nd_flag & ND_NFSV3)
525 nfsrv_postopattr(nd, dattr_ret, &dattr);
528 if (nd->nd_flag & ND_NFSV2) {
529 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
530 nfsrv_fillattr(nd, &nva);
531 } else if (nd->nd_flag & ND_NFSV3) {
532 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
533 nfsrv_postopattr(nd, 0, &nva);
534 nfsrv_postopattr(nd, dattr_ret, &dattr);
540 * nfs readlink service
543 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
544 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
547 mbuf_t mp = NULL, mpend = NULL;
551 if (nd->nd_repstat) {
552 nfsrv_postopattr(nd, getret, &nva);
555 if (vnode_vtype(vp) != VLNK) {
556 if (nd->nd_flag & ND_NFSV2)
557 nd->nd_repstat = ENXIO;
559 nd->nd_repstat = EINVAL;
562 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
564 if (nd->nd_flag & ND_NFSV3)
565 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
567 if (nd->nd_flag & ND_NFSV3)
568 nfsrv_postopattr(nd, getret, &nva);
571 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
572 *tl = txdr_unsigned(len);
573 mbuf_setnext(nd->nd_mb, mp);
575 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
583 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
584 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
587 int error = 0, cnt, len, getret = 1, reqlen, eof = 0;
591 struct nfsstate st, *stp = &st;
592 struct nfslock lo, *lop = &lo;
593 nfsv4stateid_t stateid;
596 if (nd->nd_repstat) {
597 nfsrv_postopattr(nd, getret, &nva);
600 if (nd->nd_flag & ND_NFSV2) {
601 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
602 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
603 reqlen = fxdr_unsigned(int, *tl);
604 } else if (nd->nd_flag & ND_NFSV3) {
605 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
606 off = fxdr_hyper(tl);
608 reqlen = fxdr_unsigned(int, *tl);
610 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
611 reqlen = fxdr_unsigned(int, *(tl + 6));
613 if (reqlen > NFS_SRVMAXDATA(nd)) {
614 reqlen = NFS_SRVMAXDATA(nd);
615 } else if (reqlen < 0) {
619 if (nd->nd_flag & ND_NFSV4) {
620 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
621 lop->lo_flags = NFSLCK_READ;
622 stp->ls_ownerlen = 0;
624 stp->ls_uid = nd->nd_cred->cr_uid;
625 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
626 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
627 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
628 if (nd->nd_flag & ND_IMPLIEDCLID) {
629 if (nd->nd_clientid.qval != clientid.qval)
630 printf("EEK! multiple clids\n");
632 nd->nd_flag |= ND_IMPLIEDCLID;
633 nd->nd_clientid.qval = clientid.qval;
635 stp->ls_stateid.other[2] = *tl++;
636 off = fxdr_hyper(tl);
639 lop->lo_end = off + reqlen;
641 * Paranoia, just in case it wraps around.
643 if (lop->lo_end < off)
644 lop->lo_end = NFS64BITSSET;
646 if (vnode_vtype(vp) != VREG) {
647 if (nd->nd_flag & ND_NFSV3)
648 nd->nd_repstat = EINVAL;
650 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
653 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
655 nd->nd_repstat = getret;
656 if (!nd->nd_repstat &&
657 (nva.na_uid != nd->nd_cred->cr_uid ||
658 NFSVNO_EXSTRICTACCESS(exp))) {
659 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
661 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
663 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
664 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
665 NFSACCCHK_VPISLOCKED, NULL);
667 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
668 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
669 &stateid, exp, nd, p);
670 if (nd->nd_repstat) {
672 if (nd->nd_flag & ND_NFSV3)
673 nfsrv_postopattr(nd, getret, &nva);
676 if (off >= nva.na_size) {
679 } else if (reqlen == 0)
681 else if ((off + reqlen) > nva.na_size)
682 cnt = nva.na_size - off;
685 len = NFSM_RNDUP(cnt);
688 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
690 if (!(nd->nd_flag & ND_NFSV4)) {
691 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
693 nd->nd_repstat = getret;
695 if (nd->nd_repstat) {
699 if (nd->nd_flag & ND_NFSV3)
700 nfsrv_postopattr(nd, getret, &nva);
705 if (nd->nd_flag & ND_NFSV2) {
706 nfsrv_fillattr(nd, &nva);
707 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
709 if (nd->nd_flag & ND_NFSV3) {
710 nfsrv_postopattr(nd, getret, &nva);
711 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
712 *tl++ = txdr_unsigned(cnt);
714 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
715 if (len < reqlen || eof)
718 *tl++ = newnfs_false;
720 *tl = txdr_unsigned(cnt);
722 mbuf_setnext(nd->nd_mb, m3);
724 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
736 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
737 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
742 struct nfsvattr nva, forat;
743 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
744 int stable = NFSWRITE_FILESYNC;
746 struct nfsstate st, *stp = &st;
747 struct nfslock lo, *lop = &lo;
748 nfsv4stateid_t stateid;
751 if (nd->nd_repstat) {
752 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
755 if (nd->nd_flag & ND_NFSV2) {
756 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
757 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
759 retlen = len = fxdr_unsigned(int32_t, *tl);
760 } else if (nd->nd_flag & ND_NFSV3) {
761 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
762 off = fxdr_hyper(tl);
764 stable = fxdr_unsigned(int, *tl++);
765 retlen = len = fxdr_unsigned(int32_t, *tl);
767 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
768 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
769 lop->lo_flags = NFSLCK_WRITE;
770 stp->ls_ownerlen = 0;
772 stp->ls_uid = nd->nd_cred->cr_uid;
773 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
774 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
775 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
776 if (nd->nd_flag & ND_IMPLIEDCLID) {
777 if (nd->nd_clientid.qval != clientid.qval)
778 printf("EEK! multiple clids\n");
780 nd->nd_flag |= ND_IMPLIEDCLID;
781 nd->nd_clientid.qval = clientid.qval;
783 stp->ls_stateid.other[2] = *tl++;
784 off = fxdr_hyper(tl);
787 stable = fxdr_unsigned(int, *tl++);
788 retlen = len = fxdr_unsigned(int32_t, *tl);
789 lop->lo_end = off + len;
791 * Paranoia, just in case it wraps around, which shouldn't
792 * ever happen anyhow.
794 if (lop->lo_end < lop->lo_first)
795 lop->lo_end = NFS64BITSSET;
799 * Loop through the mbuf chain, counting how many mbufs are a
800 * part of this write operation, so the iovec size is known.
804 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
820 if (retlen > NFS_MAXDATA || retlen < 0)
821 nd->nd_repstat = EIO;
822 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
823 if (nd->nd_flag & ND_NFSV3)
824 nd->nd_repstat = EINVAL;
826 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
829 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
831 nd->nd_repstat = forat_ret;
832 if (!nd->nd_repstat &&
833 (forat.na_uid != nd->nd_cred->cr_uid ||
834 NFSVNO_EXSTRICTACCESS(exp)))
835 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
837 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
838 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
839 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
840 &stateid, exp, nd, p);
842 if (nd->nd_repstat) {
844 if (nd->nd_flag & ND_NFSV3)
845 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
850 * For NFS Version 2, it is not obvious what a write of zero length
851 * should do, but I might as well be consistent with Version 3,
852 * which is to return ok so long as there are no permission problems.
855 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
856 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
857 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
859 panic("nfsrv_write mbuf");
861 if (nd->nd_flag & ND_NFSV4)
864 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
867 nd->nd_repstat = aftat_ret;
868 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
869 if (nd->nd_flag & ND_NFSV3)
870 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
873 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
874 *tl++ = txdr_unsigned(retlen);
875 if (stable == NFSWRITE_UNSTABLE)
876 *tl++ = txdr_unsigned(stable);
878 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
880 * Actually, there is no need to txdr these fields,
881 * but it may make the values more human readable,
882 * for debugging purposes.
884 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
885 *tl = txdr_unsigned(nfsboottime.tv_usec);
886 } else if (!nd->nd_repstat)
887 nfsrv_fillattr(nd, &nva);
895 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
896 * now does a truncate to 0 length via. setattr if it already exists
897 * The core creation routine has been extracted out into nfsrv_creatsub(),
898 * so it can also be used by nfsrv_open() for V4.
901 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
902 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
904 struct nfsvattr nva, dirfor, diraft;
905 struct nfsv2_sattr *sp;
906 struct nameidata named;
908 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
909 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
911 vnode_t vp = NULL, dirp = NULL;
916 int32_t cverf[2], tverf[2] = { 0, 0 };
918 if (nd->nd_repstat) {
919 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
922 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
923 LOCKPARENT | LOCKLEAF | SAVESTART);
924 nfsvno_setpathbuf(&named, &bufp, &hashp);
925 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
928 nfsvno_relpathbuf(&named);
931 if (!nd->nd_repstat) {
932 NFSVNO_ATTRINIT(&nva);
933 if (nd->nd_flag & ND_NFSV2) {
934 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
935 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
938 NFSVNO_SETATTRVAL(&nva, type, vtyp);
939 NFSVNO_SETATTRVAL(&nva, mode,
940 nfstov_mode(sp->sa_mode));
941 switch (nva.na_type) {
943 tsize = fxdr_unsigned(int32_t, sp->sa_size);
945 NFSVNO_SETATTRVAL(&nva, size,
951 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
957 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
958 how = fxdr_unsigned(int, *tl);
960 case NFSCREATE_GUARDED:
961 case NFSCREATE_UNCHECKED:
962 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
966 case NFSCREATE_EXCLUSIVE:
967 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
973 NFSVNO_SETATTRVAL(&nva, type, VREG);
976 if (nd->nd_repstat) {
977 nfsvno_relpathbuf(&named);
978 if (nd->nd_flag & ND_NFSV3) {
979 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
981 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
988 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
990 if (nd->nd_flag & ND_NFSV2) {
994 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
998 if (nd->nd_repstat) {
999 if (nd->nd_flag & ND_NFSV3)
1000 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1007 if (!(nd->nd_flag & ND_NFSV2)) {
1009 case NFSCREATE_GUARDED:
1011 nd->nd_repstat = EEXIST;
1013 case NFSCREATE_UNCHECKED:
1015 case NFSCREATE_EXCLUSIVE:
1016 if (named.ni_vp == NULL)
1017 NFSVNO_SETATTRVAL(&nva, mode, 0);
1023 * Iff doesn't exist, create it
1024 * otherwise just truncate to 0 length
1025 * should I set the mode too ?
1027 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1028 &exclusive_flag, cverf, rdev, p, exp);
1030 if (!nd->nd_repstat) {
1031 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1032 if (!nd->nd_repstat)
1033 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1036 if (!nd->nd_repstat) {
1037 tverf[0] = nva.na_atime.tv_sec;
1038 tverf[1] = nva.na_atime.tv_nsec;
1041 if (nd->nd_flag & ND_NFSV2) {
1042 if (!nd->nd_repstat) {
1043 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1044 nfsrv_fillattr(nd, &nva);
1047 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1048 || cverf[1] != tverf[1]))
1049 nd->nd_repstat = EEXIST;
1050 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1052 if (!nd->nd_repstat) {
1053 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1054 nfsrv_postopattr(nd, 0, &nva);
1056 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1061 nfsvno_relpathbuf(&named);
1066 * nfs v3 mknod service (and v4 create)
1069 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1070 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1071 struct nfsexstuff *exp)
1073 struct nfsvattr nva, dirfor, diraft;
1075 struct nameidata named;
1076 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1077 u_int32_t major, minor;
1078 enum vtype vtyp = VNON;
1079 nfstype nfs4type = NFNON;
1080 vnode_t vp, dirp = NULL;
1081 nfsattrbit_t attrbits;
1082 char *bufp = NULL, *pathcp = NULL;
1083 u_long *hashp, cnflags;
1084 NFSACL_T *aclp = NULL;
1086 NFSVNO_ATTRINIT(&nva);
1087 cnflags = (LOCKPARENT | SAVESTART);
1088 if (nd->nd_repstat) {
1089 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1092 #ifdef NFS4_ACL_EXTATTR_NAME
1093 aclp = acl_alloc(M_WAITOK);
1098 * For V4, the creation stuff is here, Yuck!
1100 if (nd->nd_flag & ND_NFSV4) {
1101 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1102 vtyp = nfsv34tov_type(*tl);
1103 nfs4type = fxdr_unsigned(nfstype, *tl);
1106 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1110 #ifdef NFS4_ACL_EXTATTR_NAME
1118 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1119 major = fxdr_unsigned(u_int32_t, *tl++);
1120 minor = fxdr_unsigned(u_int32_t, *tl);
1121 nva.na_rdev = NFSMAKEDEV(major, minor);
1127 cnflags = (LOCKPARENT | SAVENAME);
1130 nd->nd_repstat = NFSERR_BADTYPE;
1132 #ifdef NFS4_ACL_EXTATTR_NAME
1138 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1139 nfsvno_setpathbuf(&named, &bufp, &hashp);
1140 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1143 #ifdef NFS4_ACL_EXTATTR_NAME
1146 nfsvno_relpathbuf(&named);
1148 FREE(pathcp, M_TEMP);
1151 if (!nd->nd_repstat) {
1152 if (nd->nd_flag & ND_NFSV3) {
1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1154 vtyp = nfsv34tov_type(*tl);
1156 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1159 #ifdef NFS4_ACL_EXTATTR_NAME
1162 nfsvno_relpathbuf(&named);
1164 FREE(pathcp, M_TEMP);
1168 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1169 (vtyp == VCHR || vtyp == VBLK)) {
1170 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1171 major = fxdr_unsigned(u_int32_t, *tl++);
1172 minor = fxdr_unsigned(u_int32_t, *tl);
1173 nva.na_rdev = NFSMAKEDEV(major, minor);
1177 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1178 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1179 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1180 dirfor.na_gid == nva.na_gid)
1181 NFSVNO_UNSET(&nva, gid);
1182 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1184 if (nd->nd_repstat) {
1186 #ifdef NFS4_ACL_EXTATTR_NAME
1189 nfsvno_relpathbuf(&named);
1191 FREE(pathcp, M_TEMP);
1192 if (nd->nd_flag & ND_NFSV3)
1193 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1199 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1200 * in va_mode, so we'll have to set a default here.
1202 if (NFSVNO_NOTSETMODE(&nva)) {
1210 named.ni_cnd.cn_flags |= WILLBEDIR;
1211 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1212 if (nd->nd_repstat) {
1214 if (nd->nd_flag & ND_NFSV3)
1215 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1219 #ifdef NFS4_ACL_EXTATTR_NAME
1222 if (nd->nd_flag & ND_NFSV3)
1223 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1228 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1230 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1232 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1233 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1235 #ifdef NFS4_ACL_EXTATTR_NAME
1239 } else if (vtyp == VLNK) {
1240 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1241 &dirfor, &diraft, &diraft_ret, &attrbits,
1242 aclp, p, exp, pathcp, pathlen);
1243 #ifdef NFS4_ACL_EXTATTR_NAME
1246 FREE(pathcp, M_TEMP);
1251 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1252 if (!nd->nd_repstat) {
1254 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1255 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1256 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1257 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1259 if (vpp != NULL && nd->nd_repstat == 0) {
1266 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1268 if (!nd->nd_repstat) {
1269 if (nd->nd_flag & ND_NFSV3) {
1270 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1271 nfsrv_postopattr(nd, 0, &nva);
1273 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1274 *tl++ = newnfs_false;
1275 txdr_hyper(dirfor.na_filerev, tl);
1277 txdr_hyper(diraft.na_filerev, tl);
1278 (void) nfsrv_putattrbit(nd, &attrbits);
1281 if (nd->nd_flag & ND_NFSV3)
1282 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1283 #ifdef NFS4_ACL_EXTATTR_NAME
1289 #ifdef NFS4_ACL_EXTATTR_NAME
1293 nfsvno_relpathbuf(&named);
1295 FREE(pathcp, M_TEMP);
1300 * nfs remove service
1303 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1304 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1306 struct nameidata named;
1308 int error, dirfor_ret = 1, diraft_ret = 1;
1309 vnode_t dirp = NULL;
1310 struct nfsvattr dirfor, diraft;
1314 if (nd->nd_repstat) {
1315 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1318 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1319 LOCKPARENT | LOCKLEAF);
1320 nfsvno_setpathbuf(&named, &bufp, &hashp);
1321 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1324 nfsvno_relpathbuf(&named);
1327 if (!nd->nd_repstat) {
1328 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1331 nfsvno_relpathbuf(&named);
1334 if (!(nd->nd_flag & ND_NFSV2)) {
1335 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1342 if (!nd->nd_repstat) {
1343 if (nd->nd_flag & ND_NFSV4) {
1344 if (vnode_vtype(named.ni_vp) == VDIR)
1345 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1346 nd->nd_cred, p, exp);
1348 nd->nd_repstat = nfsvno_removesub(&named, 1,
1349 nd->nd_cred, p, exp);
1350 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1351 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1352 nd->nd_cred, p, exp);
1354 nd->nd_repstat = nfsvno_removesub(&named, 0,
1355 nd->nd_cred, p, exp);
1358 if (!(nd->nd_flag & ND_NFSV2)) {
1360 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1364 if (nd->nd_flag & ND_NFSV3) {
1365 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1367 } else if (!nd->nd_repstat) {
1368 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1369 *tl++ = newnfs_false;
1370 txdr_hyper(dirfor.na_filerev, tl);
1372 txdr_hyper(diraft.na_filerev, tl);
1379 * nfs rename service
1382 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1383 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1384 struct nfsexstuff *toexp)
1387 int error, fdirfor_ret = 1, fdiraft_ret = 1;
1388 int tdirfor_ret = 1, tdiraft_ret = 1;
1389 struct nameidata fromnd, tond;
1390 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1391 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1392 struct nfsexstuff tnes;
1394 char *bufp, *tbufp = NULL;
1397 if (nd->nd_repstat) {
1398 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1399 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1402 if (!(nd->nd_flag & ND_NFSV2))
1403 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1404 tond.ni_cnd.cn_nameiop = 0;
1405 tond.ni_startdir = NULL;
1406 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1407 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1408 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1413 nfsvno_relpathbuf(&fromnd);
1416 if (nd->nd_flag & ND_NFSV4) {
1419 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1421 error = nfsrv_mtofh(nd, &tfh);
1424 /* todp is always NULL except NFSv4 */
1425 nfsvno_relpathbuf(&fromnd);
1428 nd->nd_cred->cr_uid = nd->nd_saveduid;
1429 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p);
1431 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1433 NFSVOPUNLOCK(tdp, 0, p);
1436 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1437 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1438 if (!nd->nd_repstat) {
1439 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1444 nfsvno_relpathbuf(&fromnd);
1445 nfsvno_relpathbuf(&tond);
1449 if (nd->nd_repstat) {
1450 if (nd->nd_flag & ND_NFSV3) {
1451 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1453 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1459 nfsvno_relpathbuf(&fromnd);
1460 nfsvno_relpathbuf(&tond);
1465 * Done parsing, now down to business.
1467 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1468 if (nd->nd_repstat) {
1469 if (nd->nd_flag & ND_NFSV3) {
1470 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1472 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1479 nfsvno_relpathbuf(&tond);
1482 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1483 tond.ni_cnd.cn_flags |= WILLBEDIR;
1484 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1485 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1486 nd->nd_flag, nd->nd_cred, p);
1488 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1491 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1497 if (nd->nd_flag & ND_NFSV3) {
1498 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1499 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1500 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1501 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1502 *tl++ = newnfs_false;
1503 txdr_hyper(fdirfor.na_filerev, tl);
1505 txdr_hyper(fdiraft.na_filerev, tl);
1507 *tl++ = newnfs_false;
1508 txdr_hyper(tdirfor.na_filerev, tl);
1510 txdr_hyper(tdiraft.na_filerev, tl);
1519 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1520 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1521 struct nfsexstuff *toexp)
1523 struct nameidata named;
1525 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1526 vnode_t dirp = NULL, dp = NULL;
1527 struct nfsvattr dirfor, diraft, at;
1528 struct nfsexstuff tnes;
1533 if (nd->nd_repstat) {
1534 nfsrv_postopattr(nd, getret, &at);
1535 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1538 NFSVOPUNLOCK(vp, 0, p);
1539 if (vnode_vtype(vp) == VDIR) {
1540 if (nd->nd_flag & ND_NFSV4)
1541 nd->nd_repstat = NFSERR_ISDIR;
1543 nd->nd_repstat = NFSERR_INVAL;
1546 } else if (vnode_vtype(vp) == VLNK) {
1547 if (nd->nd_flag & ND_NFSV2)
1548 nd->nd_repstat = NFSERR_INVAL;
1550 nd->nd_repstat = NFSERR_NOTSUPP;
1554 if (!nd->nd_repstat) {
1555 if (nd->nd_flag & ND_NFSV4) {
1559 error = nfsrv_mtofh(nd, &dfh);
1562 /* tovp is always NULL unless NFSv4 */
1565 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1568 NFSVOPUNLOCK(dp, 0, p);
1571 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1572 LOCKPARENT | SAVENAME);
1573 if (!nd->nd_repstat) {
1574 nfsvno_setpathbuf(&named, &bufp, &hashp);
1575 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1580 nfsvno_relpathbuf(&named);
1583 if (!nd->nd_repstat) {
1584 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1589 nfsvno_relpathbuf(&named);
1593 if (nd->nd_flag & ND_NFSV2) {
1597 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1601 if (!nd->nd_repstat)
1602 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1603 if (nd->nd_flag & ND_NFSV3)
1604 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1606 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1610 if (nd->nd_flag & ND_NFSV3) {
1611 nfsrv_postopattr(nd, getret, &at);
1612 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1613 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1614 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1615 *tl++ = newnfs_false;
1616 txdr_hyper(dirfor.na_filerev, tl);
1618 txdr_hyper(diraft.na_filerev, tl);
1624 * nfs symbolic link service
1627 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1628 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1629 struct nfsexstuff *exp)
1631 struct nfsvattr nva, dirfor, diraft;
1632 struct nameidata named;
1633 int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1634 vnode_t dirp = NULL;
1635 char *bufp, *pathcp = NULL;
1638 if (nd->nd_repstat) {
1639 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1644 NFSVNO_ATTRINIT(&nva);
1645 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1646 LOCKPARENT | SAVESTART);
1647 nfsvno_setpathbuf(&named, &bufp, &hashp);
1648 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1649 if (!error && !nd->nd_repstat)
1650 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1653 nfsvno_relpathbuf(&named);
1656 if (!nd->nd_repstat) {
1657 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1660 nfsvno_relpathbuf(&named);
1662 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1668 * And call nfsrvd_symlinksub() to do the common code. It will
1669 * return EBADRPC upon a parsing error, 0 otherwise.
1671 if (!nd->nd_repstat) {
1673 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1675 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1676 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1678 } else if (dirp != NULL) {
1679 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1683 FREE(pathcp, M_TEMP);
1685 if (nd->nd_flag & ND_NFSV3) {
1686 if (!nd->nd_repstat) {
1687 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1688 nfsrv_postopattr(nd, 0, &nva);
1690 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1696 * Common code for creating a symbolic link.
1699 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1700 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1701 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1702 int *diraft_retp, nfsattrbit_t *attrbitp,
1703 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1708 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1709 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1710 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1711 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1712 if (nd->nd_flag & ND_NFSV3) {
1713 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1714 if (!nd->nd_repstat)
1715 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1716 nvap, nd->nd_cred, p, 1);
1718 if (vpp != NULL && nd->nd_repstat == 0) {
1719 VOP_UNLOCK(ndp->ni_vp, 0);
1725 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1728 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1729 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1730 *tl++ = newnfs_false;
1731 txdr_hyper(dirforp->na_filerev, tl);
1733 txdr_hyper(diraftp->na_filerev, tl);
1734 (void) nfsrv_putattrbit(nd, attrbitp);
1742 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1743 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1744 struct nfsexstuff *exp)
1746 struct nfsvattr nva, dirfor, diraft;
1747 struct nameidata named;
1749 int error, dirfor_ret = 1, diraft_ret = 1;
1750 vnode_t dirp = NULL;
1754 if (nd->nd_repstat) {
1755 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1758 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1759 LOCKPARENT | SAVENAME);
1760 nfsvno_setpathbuf(&named, &bufp, &hashp);
1761 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1764 nfsvno_relpathbuf(&named);
1767 if (!nd->nd_repstat) {
1768 NFSVNO_ATTRINIT(&nva);
1769 if (nd->nd_flag & ND_NFSV3) {
1770 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1773 nfsvno_relpathbuf(&named);
1777 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1778 nva.na_mode = nfstov_mode(*tl++);
1781 if (!nd->nd_repstat) {
1782 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1785 nfsvno_relpathbuf(&named);
1787 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1791 if (nd->nd_repstat) {
1793 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1797 if (nd->nd_flag & ND_NFSV3)
1798 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1803 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1806 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1808 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1809 &diraft_ret, NULL, NULL, p, exp);
1811 if (nd->nd_flag & ND_NFSV3) {
1812 if (!nd->nd_repstat) {
1813 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1814 nfsrv_postopattr(nd, 0, &nva);
1816 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1817 } else if (!nd->nd_repstat) {
1818 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1819 nfsrv_fillattr(nd, &nva);
1824 nfsvno_relpathbuf(&named);
1829 * Code common to mkdir for V2,3 and 4.
1832 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1833 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1834 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1835 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1836 NFSPROC_T *p, struct nfsexstuff *exp)
1841 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1842 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1843 nd->nd_cred, p, exp);
1844 if (!nd->nd_repstat) {
1846 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1847 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1848 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1849 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1851 if (vpp && !nd->nd_repstat) {
1852 NFSVOPUNLOCK(vp, 0, p);
1859 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1862 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1863 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1864 *tl++ = newnfs_false;
1865 txdr_hyper(dirforp->na_filerev, tl);
1867 txdr_hyper(diraftp->na_filerev, tl);
1868 (void) nfsrv_putattrbit(nd, attrbitp);
1873 * nfs commit service
1876 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1877 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1879 struct nfsvattr bfor, aft;
1881 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1884 if (nd->nd_repstat) {
1885 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1888 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1890 * XXX At this time VOP_FSYNC() does not accept offset and byte
1891 * count parameters, so these arguments are useless (someday maybe).
1893 off = fxdr_hyper(tl);
1895 cnt = fxdr_unsigned(int, *tl);
1896 if (nd->nd_flag & ND_NFSV3)
1897 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1898 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1899 if (nd->nd_flag & ND_NFSV3) {
1900 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1901 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1904 if (!nd->nd_repstat) {
1905 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1906 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1907 *tl = txdr_unsigned(nfsboottime.tv_usec);
1916 * nfs statfs service
1919 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1920 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1929 if (nd->nd_repstat) {
1930 nfsrv_postopattr(nd, getret, &at);
1934 nd->nd_repstat = nfsvno_statfs(vp, sf);
1935 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1937 if (nd->nd_flag & ND_NFSV3)
1938 nfsrv_postopattr(nd, getret, &at);
1941 if (nd->nd_flag & ND_NFSV2) {
1942 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1943 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1944 *tl++ = txdr_unsigned(sf->f_bsize);
1945 *tl++ = txdr_unsigned(sf->f_blocks);
1946 *tl++ = txdr_unsigned(sf->f_bfree);
1947 *tl = txdr_unsigned(sf->f_bavail);
1949 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1950 tval = (u_quad_t)sf->f_blocks;
1951 tval *= (u_quad_t)sf->f_bsize;
1952 txdr_hyper(tval, tl); tl += 2;
1953 tval = (u_quad_t)sf->f_bfree;
1954 tval *= (u_quad_t)sf->f_bsize;
1955 txdr_hyper(tval, tl); tl += 2;
1956 tval = (u_quad_t)sf->f_bavail;
1957 tval *= (u_quad_t)sf->f_bsize;
1958 txdr_hyper(tval, tl); tl += 2;
1959 tval = (u_quad_t)sf->f_files;
1960 txdr_hyper(tval, tl); tl += 2;
1961 tval = (u_quad_t)sf->f_ffree;
1962 txdr_hyper(tval, tl); tl += 2;
1963 tval = (u_quad_t)sf->f_ffree;
1964 txdr_hyper(tval, tl); tl += 2;
1971 * nfs fsinfo service
1974 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1975 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1978 struct nfsfsinfo fs;
1982 if (nd->nd_repstat) {
1983 nfsrv_postopattr(nd, getret, &at);
1986 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1987 nfsvno_getfs(&fs, isdgram);
1989 nfsrv_postopattr(nd, getret, &at);
1990 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1991 *tl++ = txdr_unsigned(fs.fs_rtmax);
1992 *tl++ = txdr_unsigned(fs.fs_rtpref);
1993 *tl++ = txdr_unsigned(fs.fs_rtmult);
1994 *tl++ = txdr_unsigned(fs.fs_wtmax);
1995 *tl++ = txdr_unsigned(fs.fs_wtpref);
1996 *tl++ = txdr_unsigned(fs.fs_wtmult);
1997 *tl++ = txdr_unsigned(fs.fs_dtpref);
1998 txdr_hyper(fs.fs_maxfilesize, tl);
2000 txdr_nfsv3time(&fs.fs_timedelta, tl);
2002 *tl = txdr_unsigned(fs.fs_properties);
2007 * nfs pathconf service
2010 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2011 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2013 struct nfsv3_pathconf *pc;
2015 register_t linkmax, namemax, chownres, notrunc;
2018 if (nd->nd_repstat) {
2019 nfsrv_postopattr(nd, getret, &at);
2022 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2024 if (!nd->nd_repstat)
2025 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2027 if (!nd->nd_repstat)
2028 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2029 &chownres, nd->nd_cred, p);
2030 if (!nd->nd_repstat)
2031 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2033 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2035 nfsrv_postopattr(nd, getret, &at);
2036 if (!nd->nd_repstat) {
2037 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2038 pc->pc_linkmax = txdr_unsigned(linkmax);
2039 pc->pc_namemax = txdr_unsigned(namemax);
2040 pc->pc_notrunc = txdr_unsigned(notrunc);
2041 pc->pc_chownrestricted = txdr_unsigned(chownres);
2044 * These should probably be supported by VOP_PATHCONF(), but
2045 * until msdosfs is exportable (why would you want to?), the
2046 * Unix defaults should be ok.
2048 pc->pc_caseinsensitive = newnfs_false;
2049 pc->pc_casepreserving = newnfs_true;
2055 * nfsv4 lock service
2058 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2059 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2063 struct nfsstate *stp = NULL;
2064 struct nfslock *lop;
2065 struct nfslockconflict cf;
2067 u_short flags = NFSLCK_LOCK, lflags;
2068 u_int64_t offset, len;
2069 nfsv4stateid_t stateid;
2072 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2073 i = fxdr_unsigned(int, *tl++);
2075 case NFSV4LOCKT_READW:
2076 flags |= NFSLCK_BLOCKING;
2077 case NFSV4LOCKT_READ:
2078 lflags = NFSLCK_READ;
2080 case NFSV4LOCKT_WRITEW:
2081 flags |= NFSLCK_BLOCKING;
2082 case NFSV4LOCKT_WRITE:
2083 lflags = NFSLCK_WRITE;
2086 nd->nd_repstat = NFSERR_BADXDR;
2089 if (*tl++ == newnfs_true)
2090 flags |= NFSLCK_RECLAIM;
2091 offset = fxdr_hyper(tl);
2093 len = fxdr_hyper(tl);
2095 if (*tl == newnfs_true)
2096 flags |= NFSLCK_OPENTOLOCK;
2097 if (flags & NFSLCK_OPENTOLOCK) {
2098 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2099 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2100 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2101 nd->nd_repstat = NFSERR_BADXDR;
2104 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2105 M_NFSDSTATE, M_WAITOK);
2106 stp->ls_ownerlen = i;
2107 stp->ls_op = nd->nd_rp;
2108 stp->ls_seq = fxdr_unsigned(int, *tl++);
2109 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2110 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2112 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2113 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2114 clientid.lval[0] = *tl++;
2115 clientid.lval[1] = *tl++;
2116 if (nd->nd_flag & ND_IMPLIEDCLID) {
2117 if (nd->nd_clientid.qval != clientid.qval)
2118 printf("EEK! multiple clids\n");
2120 nd->nd_flag |= ND_IMPLIEDCLID;
2121 nd->nd_clientid.qval = clientid.qval;
2123 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2127 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2128 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2129 M_NFSDSTATE, M_WAITOK);
2130 stp->ls_ownerlen = 0;
2131 stp->ls_op = nd->nd_rp;
2132 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2133 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2135 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2136 stp->ls_seq = fxdr_unsigned(int, *tl);
2137 clientid.lval[0] = stp->ls_stateid.other[0];
2138 clientid.lval[1] = stp->ls_stateid.other[1];
2139 if (nd->nd_flag & ND_IMPLIEDCLID) {
2140 if (nd->nd_clientid.qval != clientid.qval)
2141 printf("EEK! multiple clids\n");
2143 nd->nd_flag |= ND_IMPLIEDCLID;
2144 nd->nd_clientid.qval = clientid.qval;
2147 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2148 M_NFSDLOCK, M_WAITOK);
2149 lop->lo_first = offset;
2150 if (len == NFS64BITSSET) {
2151 lop->lo_end = NFS64BITSSET;
2153 lop->lo_end = offset + len;
2154 if (lop->lo_end <= lop->lo_first)
2155 nd->nd_repstat = NFSERR_INVAL;
2157 lop->lo_flags = lflags;
2158 stp->ls_flags = flags;
2159 stp->ls_uid = nd->nd_cred->cr_uid;
2162 * Do basic access checking.
2164 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2165 if (vnode_vtype(vp) == VDIR)
2166 nd->nd_repstat = NFSERR_ISDIR;
2168 nd->nd_repstat = NFSERR_INVAL;
2170 if (!nd->nd_repstat) {
2171 if (lflags & NFSLCK_WRITE) {
2172 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2173 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2174 NFSACCCHK_VPISLOCKED, NULL);
2176 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2177 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2178 NFSACCCHK_VPISLOCKED, NULL);
2180 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2181 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2182 NFSACCCHK_VPISLOCKED, NULL);
2187 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2188 * seqid# gets updated. nfsrv_lockctrl() will return the value
2189 * of nd_repstat, if it gets that far.
2191 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2192 &stateid, exp, nd, p);
2194 FREE((caddr_t)lop, M_NFSDLOCK);
2196 FREE((caddr_t)stp, M_NFSDSTATE);
2197 if (!nd->nd_repstat) {
2198 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2199 *tl++ = txdr_unsigned(stateid.seqid);
2200 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2201 } else if (nd->nd_repstat == NFSERR_DENIED) {
2202 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2203 txdr_hyper(cf.cl_first, tl);
2205 if (cf.cl_end == NFS64BITSSET)
2208 len = cf.cl_end - cf.cl_first;
2209 txdr_hyper(len, tl);
2211 if (cf.cl_flags == NFSLCK_WRITE)
2212 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2214 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2215 *tl++ = stateid.other[0];
2216 *tl = stateid.other[1];
2217 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2224 free((caddr_t)stp, M_NFSDSTATE);
2229 * nfsv4 lock test service
2232 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2233 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2237 struct nfsstate *stp = NULL;
2238 struct nfslock lo, *lop = &lo;
2239 struct nfslockconflict cf;
2241 nfsv4stateid_t stateid;
2245 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2246 i = fxdr_unsigned(int, *(tl + 7));
2247 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2248 nd->nd_repstat = NFSERR_BADXDR;
2251 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2252 M_NFSDSTATE, M_WAITOK);
2253 stp->ls_ownerlen = i;
2255 stp->ls_flags = NFSLCK_TEST;
2256 stp->ls_uid = nd->nd_cred->cr_uid;
2257 i = fxdr_unsigned(int, *tl++);
2259 case NFSV4LOCKT_READW:
2260 stp->ls_flags |= NFSLCK_BLOCKING;
2261 case NFSV4LOCKT_READ:
2262 lo.lo_flags = NFSLCK_READ;
2264 case NFSV4LOCKT_WRITEW:
2265 stp->ls_flags |= NFSLCK_BLOCKING;
2266 case NFSV4LOCKT_WRITE:
2267 lo.lo_flags = NFSLCK_WRITE;
2270 nd->nd_repstat = NFSERR_BADXDR;
2273 lo.lo_first = fxdr_hyper(tl);
2275 len = fxdr_hyper(tl);
2276 if (len == NFS64BITSSET) {
2277 lo.lo_end = NFS64BITSSET;
2279 lo.lo_end = lo.lo_first + len;
2280 if (lo.lo_end <= lo.lo_first)
2281 nd->nd_repstat = NFSERR_INVAL;
2284 clientid.lval[0] = *tl++;
2285 clientid.lval[1] = *tl;
2286 if (nd->nd_flag & ND_IMPLIEDCLID) {
2287 if (nd->nd_clientid.qval != clientid.qval)
2288 printf("EEK! multiple clids\n");
2290 nd->nd_flag |= ND_IMPLIEDCLID;
2291 nd->nd_clientid.qval = clientid.qval;
2293 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2296 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2297 if (vnode_vtype(vp) == VDIR)
2298 nd->nd_repstat = NFSERR_ISDIR;
2300 nd->nd_repstat = NFSERR_INVAL;
2302 if (!nd->nd_repstat)
2303 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2304 &stateid, exp, nd, p);
2306 FREE((caddr_t)stp, M_NFSDSTATE);
2307 if (nd->nd_repstat) {
2308 if (nd->nd_repstat == NFSERR_DENIED) {
2309 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2310 txdr_hyper(cf.cl_first, tl);
2312 if (cf.cl_end == NFS64BITSSET)
2315 len = cf.cl_end - cf.cl_first;
2316 txdr_hyper(len, tl);
2318 if (cf.cl_flags == NFSLCK_WRITE)
2319 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2321 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2322 *tl++ = stp->ls_stateid.other[0];
2323 *tl = stp->ls_stateid.other[1];
2324 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2332 free((caddr_t)stp, M_NFSDSTATE);
2337 * nfsv4 unlock service
2340 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2341 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2345 struct nfsstate *stp;
2346 struct nfslock *lop;
2348 nfsv4stateid_t stateid;
2352 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2353 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2354 M_NFSDSTATE, M_WAITOK);
2355 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2356 M_NFSDLOCK, M_WAITOK);
2357 stp->ls_flags = NFSLCK_UNLOCK;
2358 lop->lo_flags = NFSLCK_UNLOCK;
2359 stp->ls_op = nd->nd_rp;
2360 i = fxdr_unsigned(int, *tl++);
2362 case NFSV4LOCKT_READW:
2363 stp->ls_flags |= NFSLCK_BLOCKING;
2364 case NFSV4LOCKT_READ:
2366 case NFSV4LOCKT_WRITEW:
2367 stp->ls_flags |= NFSLCK_BLOCKING;
2368 case NFSV4LOCKT_WRITE:
2371 nd->nd_repstat = NFSERR_BADXDR;
2372 free(stp, M_NFSDSTATE);
2373 free(lop, M_NFSDLOCK);
2376 stp->ls_ownerlen = 0;
2377 stp->ls_uid = nd->nd_cred->cr_uid;
2378 stp->ls_seq = fxdr_unsigned(int, *tl++);
2379 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2380 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2382 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2383 lop->lo_first = fxdr_hyper(tl);
2385 len = fxdr_hyper(tl);
2386 if (len == NFS64BITSSET) {
2387 lop->lo_end = NFS64BITSSET;
2389 lop->lo_end = lop->lo_first + len;
2390 if (lop->lo_end <= lop->lo_first)
2391 nd->nd_repstat = NFSERR_INVAL;
2393 clientid.lval[0] = stp->ls_stateid.other[0];
2394 clientid.lval[1] = stp->ls_stateid.other[1];
2395 if (nd->nd_flag & ND_IMPLIEDCLID) {
2396 if (nd->nd_clientid.qval != clientid.qval)
2397 printf("EEK! multiple clids\n");
2399 nd->nd_flag |= ND_IMPLIEDCLID;
2400 nd->nd_clientid.qval = clientid.qval;
2402 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2403 if (vnode_vtype(vp) == VDIR)
2404 nd->nd_repstat = NFSERR_ISDIR;
2406 nd->nd_repstat = NFSERR_INVAL;
2409 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2410 * seqid# gets incremented. nfsrv_lockctrl() will return the
2411 * value of nd_repstat, if it gets that far.
2413 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2414 &stateid, exp, nd, p);
2416 FREE((caddr_t)stp, M_NFSDSTATE);
2418 free((caddr_t)lop, M_NFSDLOCK);
2419 if (!nd->nd_repstat) {
2420 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2421 *tl++ = txdr_unsigned(stateid.seqid);
2422 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2430 * nfsv4 open service
2433 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2434 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2435 struct nfsexstuff *exp)
2439 struct nfsstate *stp = NULL;
2440 int error = 0, create, claim, exclusive_flag = 0;
2441 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2442 int how = NFSCREATE_UNCHECKED;
2443 int32_t cverf[2], tverf[2] = { 0, 0 };
2444 vnode_t vp = NULL, dirp = NULL;
2445 struct nfsvattr nva, dirfor, diraft;
2446 struct nameidata named;
2447 nfsv4stateid_t stateid, delegstateid;
2448 nfsattrbit_t attrbits;
2452 NFSACL_T *aclp = NULL;
2454 #ifdef NFS4_ACL_EXTATTR_NAME
2455 aclp = acl_alloc(M_WAITOK);
2458 NFSZERO_ATTRBIT(&attrbits);
2459 named.ni_startdir = NULL;
2460 named.ni_cnd.cn_nameiop = 0;
2461 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2462 i = fxdr_unsigned(int, *(tl + 5));
2463 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2464 nd->nd_repstat = NFSERR_BADXDR;
2466 #ifdef NFS4_ACL_EXTATTR_NAME
2471 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2472 M_NFSDSTATE, M_WAITOK);
2473 stp->ls_ownerlen = i;
2474 stp->ls_op = nd->nd_rp;
2475 stp->ls_flags = NFSLCK_OPEN;
2476 stp->ls_uid = nd->nd_cred->cr_uid;
2477 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2478 i = fxdr_unsigned(int, *tl++);
2480 case NFSV4OPEN_ACCESSREAD:
2481 stp->ls_flags |= NFSLCK_READACCESS;
2483 case NFSV4OPEN_ACCESSWRITE:
2484 stp->ls_flags |= NFSLCK_WRITEACCESS;
2486 case NFSV4OPEN_ACCESSBOTH:
2487 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2490 nd->nd_repstat = NFSERR_INVAL;
2492 i = fxdr_unsigned(int, *tl++);
2494 case NFSV4OPEN_DENYNONE:
2496 case NFSV4OPEN_DENYREAD:
2497 stp->ls_flags |= NFSLCK_READDENY;
2499 case NFSV4OPEN_DENYWRITE:
2500 stp->ls_flags |= NFSLCK_WRITEDENY;
2502 case NFSV4OPEN_DENYBOTH:
2503 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2506 nd->nd_repstat = NFSERR_INVAL;
2508 clientid.lval[0] = *tl++;
2509 clientid.lval[1] = *tl;
2510 if (nd->nd_flag & ND_IMPLIEDCLID) {
2511 if (nd->nd_clientid.qval != clientid.qval)
2512 printf("EEK! multiple clids\n");
2514 nd->nd_flag |= ND_IMPLIEDCLID;
2515 nd->nd_clientid.qval = clientid.qval;
2517 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2520 #ifdef NFS4_ACL_EXTATTR_NAME
2523 FREE((caddr_t)stp, M_NFSDSTATE);
2526 NFSVNO_ATTRINIT(&nva);
2527 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2528 create = fxdr_unsigned(int, *tl);
2529 if (!nd->nd_repstat)
2530 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2531 if (create == NFSV4OPEN_CREATE) {
2534 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2535 how = fxdr_unsigned(int, *tl);
2537 case NFSCREATE_UNCHECKED:
2538 case NFSCREATE_GUARDED:
2539 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2542 #ifdef NFS4_ACL_EXTATTR_NAME
2545 FREE((caddr_t)stp, M_NFSDSTATE);
2549 * If the na_gid being set is the same as that of
2550 * the directory it is going in, clear it, since
2551 * that is what will be set by default. This allows
2552 * a user that isn't in that group to do the create.
2554 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2555 nva.na_gid == dirfor.na_gid)
2556 NFSVNO_UNSET(&nva, gid);
2557 if (!nd->nd_repstat)
2558 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2560 case NFSCREATE_EXCLUSIVE:
2561 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2566 nd->nd_repstat = NFSERR_BADXDR;
2568 #ifdef NFS4_ACL_EXTATTR_NAME
2571 FREE((caddr_t)stp, M_NFSDSTATE);
2574 } else if (create != NFSV4OPEN_NOCREATE) {
2575 nd->nd_repstat = NFSERR_BADXDR;
2577 #ifdef NFS4_ACL_EXTATTR_NAME
2580 FREE((caddr_t)stp, M_NFSDSTATE);
2585 * Now, handle the claim, which usually includes looking up a
2586 * name in the directory referenced by dp. The exception is
2587 * NFSV4OPEN_CLAIMPREVIOUS.
2589 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2590 claim = fxdr_unsigned(int, *tl);
2591 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2592 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2593 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2594 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2595 stp->ls_flags |= NFSLCK_DELEGCUR;
2596 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2597 stp->ls_flags |= NFSLCK_DELEGPREV;
2599 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2600 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2601 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2602 claim != NFSV4OPEN_CLAIMNULL)
2603 nd->nd_repstat = NFSERR_INVAL;
2604 if (nd->nd_repstat) {
2605 nd->nd_repstat = nfsrv_opencheck(clientid,
2606 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2608 #ifdef NFS4_ACL_EXTATTR_NAME
2611 FREE((caddr_t)stp, M_NFSDSTATE);
2614 if (create == NFSV4OPEN_CREATE)
2615 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2616 LOCKPARENT | LOCKLEAF | SAVESTART);
2618 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2619 LOCKLEAF | SAVESTART);
2620 nfsvno_setpathbuf(&named, &bufp, &hashp);
2621 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2624 #ifdef NFS4_ACL_EXTATTR_NAME
2627 FREE((caddr_t)stp, M_NFSDSTATE);
2628 nfsvno_relpathbuf(&named);
2631 if (!nd->nd_repstat) {
2632 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2636 nfsvno_relpathbuf(&named);
2638 if (create == NFSV4OPEN_CREATE) {
2640 case NFSCREATE_UNCHECKED:
2643 * Clear the setable attribute bits, except
2644 * for Size, if it is being truncated.
2646 NFSZERO_ATTRBIT(&attrbits);
2647 if (NFSVNO_ISSETSIZE(&nva))
2648 NFSSETBIT_ATTRBIT(&attrbits,
2652 case NFSCREATE_GUARDED:
2653 if (named.ni_vp && !nd->nd_repstat)
2654 nd->nd_repstat = EEXIST;
2656 case NFSCREATE_EXCLUSIVE:
2662 nfsvno_open(nd, &named, clientid, &stateid, stp,
2663 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2664 nd->nd_cred, p, exp, &vp);
2665 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2667 i = fxdr_unsigned(int, *tl);
2669 case NFSV4OPEN_DELEGATEREAD:
2670 stp->ls_flags |= NFSLCK_DELEGREAD;
2672 case NFSV4OPEN_DELEGATEWRITE:
2673 stp->ls_flags |= NFSLCK_DELEGWRITE;
2674 case NFSV4OPEN_DELEGATENONE:
2677 nd->nd_repstat = NFSERR_BADXDR;
2679 #ifdef NFS4_ACL_EXTATTR_NAME
2682 FREE((caddr_t)stp, M_NFSDSTATE);
2685 stp->ls_flags |= NFSLCK_RECLAIM;
2687 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2688 if ((vp->v_iflag & VI_DOOMED) == 0)
2689 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2690 stp, vp, nd, p, nd->nd_repstat);
2692 nd->nd_repstat = NFSERR_PERM;
2694 nd->nd_repstat = NFSERR_BADXDR;
2696 #ifdef NFS4_ACL_EXTATTR_NAME
2699 FREE((caddr_t)stp, M_NFSDSTATE);
2704 * Do basic access checking.
2706 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2707 if (vnode_vtype(vp) == VDIR)
2708 nd->nd_repstat = NFSERR_ISDIR;
2709 else if (vnode_vtype(vp) == VLNK)
2710 nd->nd_repstat = NFSERR_SYMLINK;
2712 nd->nd_repstat = NFSERR_INVAL;
2714 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2715 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2716 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2717 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2718 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2719 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2721 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2722 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2723 NFSACCCHK_VPISLOCKED, NULL);
2726 if (!nd->nd_repstat) {
2727 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2728 if (!nd->nd_repstat) {
2729 tverf[0] = nva.na_atime.tv_sec;
2730 tverf[1] = nva.na_atime.tv_nsec;
2733 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2734 cverf[1] != tverf[1]))
2735 nd->nd_repstat = EEXIST;
2737 * Do the open locking/delegation stuff.
2739 if (!nd->nd_repstat)
2740 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2741 &delegstateid, &rflags, exp, p, nva.na_filerev);
2744 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2745 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2746 * (ie: Leave the NFSVOPUNLOCK() about here.)
2749 NFSVOPUNLOCK(vp, 0, p);
2751 FREE((caddr_t)stp, M_NFSDSTATE);
2752 if (!nd->nd_repstat && dirp)
2753 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2755 if (!nd->nd_repstat) {
2756 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2757 *tl++ = txdr_unsigned(stateid.seqid);
2758 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2759 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2760 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2761 *tl++ = newnfs_true;
2767 *tl++ = newnfs_false; /* Since dirp is not locked */
2768 txdr_hyper(dirfor.na_filerev, tl);
2770 txdr_hyper(diraft.na_filerev, tl);
2773 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2774 (void) nfsrv_putattrbit(nd, &attrbits);
2775 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2776 if (rflags & NFSV4OPEN_READDELEGATE)
2777 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2778 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2779 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2781 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2782 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2783 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2784 *tl++ = txdr_unsigned(delegstateid.seqid);
2785 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2787 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2788 if (rflags & NFSV4OPEN_RECALL)
2792 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2793 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2794 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2795 txdr_hyper(nva.na_size, tl);
2797 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2798 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2799 *tl++ = txdr_unsigned(0x0);
2800 acemask = NFSV4ACE_ALLFILESMASK;
2801 if (nva.na_mode & S_IRUSR)
2802 acemask |= NFSV4ACE_READMASK;
2803 if (nva.na_mode & S_IWUSR)
2804 acemask |= NFSV4ACE_WRITEMASK;
2805 if (nva.na_mode & S_IXUSR)
2806 acemask |= NFSV4ACE_EXECUTEMASK;
2807 *tl = txdr_unsigned(acemask);
2808 (void) nfsm_strtom(nd, "OWNER@", 6);
2816 #ifdef NFS4_ACL_EXTATTR_NAME
2822 #ifdef NFS4_ACL_EXTATTR_NAME
2826 FREE((caddr_t)stp, M_NFSDSTATE);
2831 * nfsv4 close service
2834 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2835 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2838 struct nfsstate st, *stp = &st;
2840 nfsv4stateid_t stateid;
2843 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2844 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2845 stp->ls_ownerlen = 0;
2846 stp->ls_op = nd->nd_rp;
2847 stp->ls_uid = nd->nd_cred->cr_uid;
2848 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2849 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2851 stp->ls_flags = NFSLCK_CLOSE;
2852 clientid.lval[0] = stp->ls_stateid.other[0];
2853 clientid.lval[1] = stp->ls_stateid.other[1];
2854 if (nd->nd_flag & ND_IMPLIEDCLID) {
2855 if (nd->nd_clientid.qval != clientid.qval)
2856 printf("EEK! multiple clids\n");
2858 nd->nd_flag |= ND_IMPLIEDCLID;
2859 nd->nd_clientid.qval = clientid.qval;
2861 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2863 if (!nd->nd_repstat) {
2864 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2865 *tl++ = txdr_unsigned(stateid.seqid);
2866 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2875 * nfsv4 delegpurge service
2878 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2879 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2885 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2886 nd->nd_repstat = NFSERR_WRONGSEC;
2889 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2890 clientid.lval[0] = *tl++;
2891 clientid.lval[1] = *tl;
2892 if (nd->nd_flag & ND_IMPLIEDCLID) {
2893 if (nd->nd_clientid.qval != clientid.qval)
2894 printf("EEK! multiple clids\n");
2896 nd->nd_flag |= ND_IMPLIEDCLID;
2897 nd->nd_clientid.qval = clientid.qval;
2899 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2900 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2906 * nfsv4 delegreturn service
2909 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2910 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2914 nfsv4stateid_t stateid;
2917 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2918 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2919 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2920 clientid.lval[0] = stateid.other[0];
2921 clientid.lval[1] = stateid.other[1];
2922 if (nd->nd_flag & ND_IMPLIEDCLID) {
2923 if (nd->nd_clientid.qval != clientid.qval)
2924 printf("EEK! multiple clids\n");
2926 nd->nd_flag |= ND_IMPLIEDCLID;
2927 nd->nd_clientid.qval = clientid.qval;
2929 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2930 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2937 * nfsv4 get file handle service
2940 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2941 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2945 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2947 if (!nd->nd_repstat)
2948 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2953 * nfsv4 open confirm service
2956 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2957 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2960 struct nfsstate st, *stp = &st;
2962 nfsv4stateid_t stateid;
2965 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2966 stp->ls_ownerlen = 0;
2967 stp->ls_op = nd->nd_rp;
2968 stp->ls_uid = nd->nd_cred->cr_uid;
2969 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2970 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2972 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2973 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2974 stp->ls_flags = NFSLCK_CONFIRM;
2975 clientid.lval[0] = stp->ls_stateid.other[0];
2976 clientid.lval[1] = stp->ls_stateid.other[1];
2977 if (nd->nd_flag & ND_IMPLIEDCLID) {
2978 if (nd->nd_clientid.qval != clientid.qval)
2979 printf("EEK! multiple clids\n");
2981 nd->nd_flag |= ND_IMPLIEDCLID;
2982 nd->nd_clientid.qval = clientid.qval;
2984 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2985 if (!nd->nd_repstat) {
2986 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2987 *tl++ = txdr_unsigned(stateid.seqid);
2988 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2996 * nfsv4 open downgrade service
2999 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3000 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3004 struct nfsstate st, *stp = &st;
3006 nfsv4stateid_t stateid;
3009 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3010 stp->ls_ownerlen = 0;
3011 stp->ls_op = nd->nd_rp;
3012 stp->ls_uid = nd->nd_cred->cr_uid;
3013 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3014 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3016 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3017 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3018 i = fxdr_unsigned(int, *tl++);
3020 case NFSV4OPEN_ACCESSREAD:
3021 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3023 case NFSV4OPEN_ACCESSWRITE:
3024 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3026 case NFSV4OPEN_ACCESSBOTH:
3027 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3031 nd->nd_repstat = NFSERR_BADXDR;
3033 i = fxdr_unsigned(int, *tl);
3035 case NFSV4OPEN_DENYNONE:
3037 case NFSV4OPEN_DENYREAD:
3038 stp->ls_flags |= NFSLCK_READDENY;
3040 case NFSV4OPEN_DENYWRITE:
3041 stp->ls_flags |= NFSLCK_WRITEDENY;
3043 case NFSV4OPEN_DENYBOTH:
3044 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3047 nd->nd_repstat = NFSERR_BADXDR;
3050 clientid.lval[0] = stp->ls_stateid.other[0];
3051 clientid.lval[1] = stp->ls_stateid.other[1];
3052 if (nd->nd_flag & ND_IMPLIEDCLID) {
3053 if (nd->nd_clientid.qval != clientid.qval)
3054 printf("EEK! multiple clids\n");
3056 nd->nd_flag |= ND_IMPLIEDCLID;
3057 nd->nd_clientid.qval = clientid.qval;
3059 if (!nd->nd_repstat)
3060 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3062 if (!nd->nd_repstat) {
3063 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3064 *tl++ = txdr_unsigned(stateid.seqid);
3065 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3073 * nfsv4 renew lease service
3076 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3077 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3083 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3084 nd->nd_repstat = NFSERR_WRONGSEC;
3087 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3088 clientid.lval[0] = *tl++;
3089 clientid.lval[1] = *tl;
3090 if (nd->nd_flag & ND_IMPLIEDCLID) {
3091 if (nd->nd_clientid.qval != clientid.qval)
3092 printf("EEK! multiple clids\n");
3094 nd->nd_flag |= ND_IMPLIEDCLID;
3095 nd->nd_clientid.qval = clientid.qval;
3097 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3098 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3104 * nfsv4 security info service
3107 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3108 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3112 struct nameidata named;
3113 vnode_t dirp = NULL, vp;
3115 struct nfsexstuff retnes;
3117 int error, savflag, i;
3122 * All this just to get the export flags for the name.
3124 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3125 LOCKLEAF | SAVESTART);
3126 nfsvno_setpathbuf(&named, &bufp, &hashp);
3127 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3130 nfsvno_relpathbuf(&named);
3133 if (!nd->nd_repstat) {
3134 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3137 nfsvno_relpathbuf(&named);
3143 vrele(named.ni_startdir);
3144 nfsvno_relpathbuf(&named);
3145 fh.nfsrvfh_len = NFSX_MYFH;
3147 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3149 savflag = nd->nd_flag;
3150 if (!nd->nd_repstat) {
3151 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3155 nd->nd_flag = savflag;
3160 * Finally have the export flags for name, so we can create
3161 * the security info.
3164 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3165 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3166 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3168 *tl = txdr_unsigned(RPCAUTH_UNIX);
3170 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3171 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3172 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3173 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3174 nfsgss_mechlist[KERBV_MECH].len);
3175 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3176 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3177 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3179 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3181 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3182 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3183 nfsgss_mechlist[KERBV_MECH].len);
3184 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3185 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3186 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3188 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3189 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3190 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3191 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3192 nfsgss_mechlist[KERBV_MECH].len);
3193 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3194 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3195 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3199 *sizp = txdr_unsigned(len);
3204 * nfsv4 set client id service
3207 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3208 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3212 int error = 0, idlen;
3213 struct nfsclient *clp = NULL;
3214 struct sockaddr_in *rad;
3215 u_char *verf, *ucp, *ucp2, addrbuf[24];
3216 nfsquad_t clientid, confirm;
3218 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3219 nd->nd_repstat = NFSERR_WRONGSEC;
3222 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3223 verf = (u_char *)tl;
3224 tl += (NFSX_VERF / NFSX_UNSIGNED);
3225 i = fxdr_unsigned(int, *tl);
3226 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3227 nd->nd_repstat = NFSERR_BADXDR;
3231 if (nd->nd_flag & ND_GSS)
3232 i += nd->nd_princlen;
3233 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3234 M_NFSDCLIENT, M_WAITOK);
3235 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3236 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3237 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3238 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3239 clp->lc_req.nr_cred = NULL;
3240 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3241 clp->lc_idlen = idlen;
3242 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3245 if (nd->nd_flag & ND_GSS) {
3246 clp->lc_flags = LCL_GSS;
3247 if (nd->nd_flag & ND_GSSINTEGRITY)
3248 clp->lc_flags |= LCL_GSSINTEGRITY;
3249 else if (nd->nd_flag & ND_GSSPRIVACY)
3250 clp->lc_flags |= LCL_GSSPRIVACY;
3254 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3255 clp->lc_flags |= LCL_NAME;
3256 clp->lc_namelen = nd->nd_princlen;
3257 clp->lc_name = &clp->lc_id[idlen];
3258 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3260 clp->lc_uid = nd->nd_cred->cr_uid;
3261 clp->lc_gid = nd->nd_cred->cr_gid;
3263 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3264 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3265 error = nfsrv_getclientipaddr(nd, clp);
3268 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3269 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3272 * nfsrv_setclient() does the actual work of adding it to the
3273 * client list. If there is no error, the structure has been
3274 * linked into the client list and clp should no longer be used
3275 * here. When an error is returned, it has not been linked in,
3276 * so it should be free'd.
3278 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3279 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3280 if (clp->lc_flags & LCL_TCPCALLBACK)
3281 (void) nfsm_strtom(nd, "tcp", 3);
3283 (void) nfsm_strtom(nd, "udp", 3);
3284 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3285 ucp = (u_char *)&rad->sin_addr.s_addr;
3286 ucp2 = (u_char *)&rad->sin_port;
3287 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3288 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3289 ucp2[0] & 0xff, ucp2[1] & 0xff);
3290 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3293 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3294 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3295 free((caddr_t)clp, M_NFSDCLIENT);
3297 if (!nd->nd_repstat) {
3298 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3299 *tl++ = clientid.lval[0];
3300 *tl++ = clientid.lval[1];
3301 *tl++ = confirm.lval[0];
3302 *tl = confirm.lval[1];
3307 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3308 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3309 free((caddr_t)clp, M_NFSDCLIENT);
3315 * nfsv4 set client id confirm service
3318 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3319 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3320 __unused struct nfsexstuff *exp)
3324 nfsquad_t clientid, confirm;
3326 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3327 nd->nd_repstat = NFSERR_WRONGSEC;
3330 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3331 clientid.lval[0] = *tl++;
3332 clientid.lval[1] = *tl++;
3333 confirm.lval[0] = *tl++;
3334 confirm.lval[1] = *tl;
3337 * nfsrv_getclient() searches the client list for a match and
3338 * returns the appropriate NFSERR status.
3340 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3341 NULL, confirm, nd, p);
3347 * nfsv4 verify service
3350 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3351 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3353 int error = 0, ret, fhsize = NFSX_MYFH;
3354 struct nfsvattr nva;
3356 struct nfsfsinfo fs;
3359 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3360 if (!nd->nd_repstat)
3361 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3362 if (!nd->nd_repstat)
3363 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3364 if (!nd->nd_repstat) {
3365 nfsvno_getfs(&fs, isdgram);
3366 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3367 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3369 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3371 nd->nd_repstat = NFSERR_SAME;
3372 else if (ret != NFSERR_NOTSAME)
3373 nd->nd_repstat = ret;
3375 nd->nd_repstat = ret;
3386 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3387 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3388 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3391 int error = 0, createdir;
3393 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3394 createdir = fxdr_unsigned(int, *tl);
3395 nd->nd_repstat = NFSERR_NOTSUPP;
3402 * nfsv4 release lock owner service
3405 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3406 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3409 struct nfsstate *stp = NULL;
3413 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3414 nd->nd_repstat = NFSERR_WRONGSEC;
3417 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3418 len = fxdr_unsigned(int, *(tl + 2));
3419 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3420 nd->nd_repstat = NFSERR_BADXDR;
3423 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3424 M_NFSDSTATE, M_WAITOK);
3425 stp->ls_ownerlen = len;
3427 stp->ls_flags = NFSLCK_RELEASE;
3428 stp->ls_uid = nd->nd_cred->cr_uid;
3429 clientid.lval[0] = *tl++;
3430 clientid.lval[1] = *tl;
3431 if (nd->nd_flag & ND_IMPLIEDCLID) {
3432 if (nd->nd_clientid.qval != clientid.qval)
3433 printf("EEK! multiple clids\n");
3435 nd->nd_flag |= ND_IMPLIEDCLID;
3436 nd->nd_clientid.qval = clientid.qval;
3438 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3441 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3442 FREE((caddr_t)stp, M_NFSDSTATE);
3446 free((caddr_t)stp, M_NFSDSTATE);