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, nfsv4root_set;
55 #endif /* !APPLEKEXT */
58 * This list defines the GSS mechanisms supported.
59 * (Don't ask me how you get these strings from the RFC stuff like
60 * iso(1), org(3)... but someone did it, so I don't need to know.)
62 static struct nfsgss_mechlist nfsgss_mechlist[] = {
63 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
68 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
69 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
70 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
71 int *diraft_retp, nfsattrbit_t *attrbitp,
72 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
74 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
75 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
76 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
77 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
78 NFSPROC_T *p, struct nfsexstuff *exp);
81 * nfs access service (not a part of NFS V2)
84 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
85 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
88 int getret, error = 0;
90 u_int32_t testmode, nfsmode, supported = 0;
94 nfsrv_postopattr(nd, 1, &nva);
97 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
98 nfsmode = fxdr_unsigned(u_int32_t, *tl);
99 if ((nd->nd_flag & ND_NFSV4) &&
100 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
101 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
102 NFSACCESS_EXECUTE))) {
103 nd->nd_repstat = NFSERR_INVAL;
107 if (nfsmode & NFSACCESS_READ) {
108 supported |= NFSACCESS_READ;
109 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
110 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
111 nfsmode &= ~NFSACCESS_READ;
113 if (nfsmode & NFSACCESS_MODIFY) {
114 supported |= NFSACCESS_MODIFY;
115 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
116 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
117 nfsmode &= ~NFSACCESS_MODIFY;
119 if (nfsmode & NFSACCESS_EXTEND) {
120 supported |= NFSACCESS_EXTEND;
121 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
122 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
123 nfsmode &= ~NFSACCESS_EXTEND;
125 if (nfsmode & NFSACCESS_DELETE) {
126 supported |= NFSACCESS_DELETE;
127 if (vp->v_type == VDIR)
128 deletebit = VDELETE_CHILD;
131 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
132 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
133 nfsmode &= ~NFSACCESS_DELETE;
135 if (vnode_vtype(vp) == VDIR)
136 testmode = NFSACCESS_LOOKUP;
138 testmode = NFSACCESS_EXECUTE;
139 if (nfsmode & testmode) {
140 supported |= (nfsmode & testmode);
141 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
142 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
143 nfsmode &= ~testmode;
145 nfsmode &= supported;
146 if (nd->nd_flag & ND_NFSV3) {
147 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
148 nfsrv_postopattr(nd, getret, &nva);
151 if (nd->nd_flag & ND_NFSV4) {
152 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
153 *tl++ = txdr_unsigned(supported);
155 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
156 *tl = txdr_unsigned(nfsmode);
164 * nfs getattr service
167 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
168 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
173 struct nfsreferral *refp;
174 nfsattrbit_t attrbits;
178 if (nd->nd_flag & ND_NFSV4) {
179 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
186 * Check for a referral.
188 refp = nfsv4root_getreferral(vp, NULL, 0);
190 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
196 nd->nd_repstat = nfsvno_accchk(vp,
198 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
199 NFSACCCHK_VPISLOCKED, NULL);
202 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
203 if (!nd->nd_repstat) {
204 if (nd->nd_flag & ND_NFSV4) {
205 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
206 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
208 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
209 &nva, &attrbits, nd->nd_cred, p);
210 NFSVOPUNLOCK(vp, 0, p);
212 (void) nfsvno_fillattr(nd, vp, &nva, &fh,
213 0, &attrbits, nd->nd_cred, p, isdgram, 1);
216 nfsrv_fillattr(nd, &nva);
226 * nfs setattr service
229 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
230 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
232 struct nfsvattr nva, nva2;
234 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
235 struct timespec guard = { 0, 0 };
236 nfsattrbit_t attrbits, retbits;
237 nfsv4stateid_t stateid;
238 NFSACL_T *aclp = NULL;
240 if (nd->nd_repstat) {
241 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
244 #ifdef NFS4_ACL_EXTATTR_NAME
245 aclp = acl_alloc(M_WAITOK);
248 NFSVNO_ATTRINIT(&nva);
249 NFSZERO_ATTRBIT(&retbits);
250 if (nd->nd_flag & ND_NFSV4) {
251 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
252 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
253 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
255 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
258 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
260 nd->nd_repstat = preat_ret;
261 if (nd->nd_flag & ND_NFSV3) {
262 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
263 gcheck = fxdr_unsigned(int, *tl);
265 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
266 fxdr_nfsv3time(tl, &guard);
268 if (!nd->nd_repstat && gcheck &&
269 (nva2.na_ctime.tv_sec != guard.tv_sec ||
270 nva2.na_ctime.tv_nsec != guard.tv_nsec))
271 nd->nd_repstat = NFSERR_NOT_SYNC;
272 if (nd->nd_repstat) {
274 #ifdef NFS4_ACL_EXTATTR_NAME
277 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
280 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
281 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
284 * Now that we have all the fields, lets do it.
285 * If the size is being changed write access is required, otherwise
286 * just check for a read only file system.
288 if (!nd->nd_repstat) {
289 if (NFSVNO_NOTSETSIZE(&nva)) {
290 if (NFSVNO_EXRDONLY(exp) ||
291 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
292 nd->nd_repstat = EROFS;
294 if (vnode_vtype(vp) != VREG)
295 nd->nd_repstat = EINVAL;
296 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
297 NFSVNO_EXSTRICTACCESS(exp))
298 nd->nd_repstat = nfsvno_accchk(vp,
299 VWRITE, nd->nd_cred, exp, p,
300 NFSACCCHK_NOOVERRIDE,
301 NFSACCCHK_VPISLOCKED, NULL);
304 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
305 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
306 &nva, &attrbits, exp, p);
308 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
310 * For V4, try setting the attrbutes in sets, so that the
311 * reply bitmap will be correct for an error case.
313 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
314 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
315 NFSVNO_ATTRINIT(&nva2);
316 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
317 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
318 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
320 if (!nd->nd_repstat) {
321 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
322 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
323 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
324 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
327 if (!nd->nd_repstat &&
328 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
329 NFSVNO_ATTRINIT(&nva2);
330 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
331 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
334 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
336 if (!nd->nd_repstat &&
337 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
338 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
339 NFSVNO_ATTRINIT(&nva2);
340 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
341 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
342 if (nva.na_vaflags & VA_UTIMES_NULL) {
343 nva2.na_vaflags |= VA_UTIMES_NULL;
344 NFSVNO_SETACTIVE(&nva2, vaflags);
346 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
348 if (!nd->nd_repstat) {
349 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
350 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
351 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
352 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
355 if (!nd->nd_repstat &&
356 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
357 NFSVNO_ATTRINIT(&nva2);
358 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
359 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
362 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
365 #ifdef NFS4_ACL_EXTATTR_NAME
366 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
367 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
368 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
370 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
373 } else if (!nd->nd_repstat) {
374 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
377 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
378 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
380 nd->nd_repstat = postat_ret;
383 #ifdef NFS4_ACL_EXTATTR_NAME
386 if (nd->nd_flag & ND_NFSV3)
387 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
388 else if (nd->nd_flag & ND_NFSV4)
389 (void) nfsrv_putattrbit(nd, &retbits);
390 else if (!nd->nd_repstat)
391 nfsrv_fillattr(nd, &nva);
395 #ifdef NFS4_ACL_EXTATTR_NAME
398 if (nd->nd_flag & ND_NFSV4) {
400 * For all nd_repstat, the V4 reply includes a bitmap,
401 * even NFSERR_BADXDR, which is what this will end up
404 (void) nfsrv_putattrbit(nd, &retbits);
411 * (Also performs lookup parent for v4)
414 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
415 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
416 __unused struct nfsexstuff *exp)
418 struct nameidata named;
419 vnode_t vp, dirp = NULL;
420 int error, dattr_ret = 1;
421 struct nfsvattr nva, dattr;
425 if (nd->nd_repstat) {
426 nfsrv_postopattr(nd, dattr_ret, &dattr);
431 * For some reason, if dp is a symlink, the error
432 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
434 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
435 nd->nd_repstat = NFSERR_SYMLINK;
440 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
441 LOCKLEAF | SAVESTART);
442 nfsvno_setpathbuf(&named, &bufp, &hashp);
443 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
446 nfsvno_relpathbuf(&named);
449 if (!nd->nd_repstat) {
450 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
453 nfsvno_relpathbuf(&named);
455 if (nd->nd_repstat) {
457 if (nd->nd_flag & ND_NFSV3)
458 dattr_ret = nfsvno_getattr(dirp, &dattr,
462 if (nd->nd_flag & ND_NFSV3)
463 nfsrv_postopattr(nd, dattr_ret, &dattr);
466 if (named.ni_startdir)
467 vrele(named.ni_startdir);
468 nfsvno_relpathbuf(&named);
470 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
471 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
472 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
474 NFSVOPUNLOCK(vp, 0, p);
480 if (nd->nd_flag & ND_NFSV3)
481 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
485 if (nd->nd_repstat) {
486 if (nd->nd_flag & ND_NFSV3)
487 nfsrv_postopattr(nd, dattr_ret, &dattr);
490 if (nd->nd_flag & ND_NFSV2) {
491 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
492 nfsrv_fillattr(nd, &nva);
493 } else if (nd->nd_flag & ND_NFSV3) {
494 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
495 nfsrv_postopattr(nd, 0, &nva);
496 nfsrv_postopattr(nd, dattr_ret, &dattr);
502 * nfs readlink service
505 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
506 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
509 mbuf_t mp = NULL, mpend = NULL;
513 if (nd->nd_repstat) {
514 nfsrv_postopattr(nd, getret, &nva);
517 if (vnode_vtype(vp) != VLNK) {
518 if (nd->nd_flag & ND_NFSV2)
519 nd->nd_repstat = ENXIO;
521 nd->nd_repstat = EINVAL;
524 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
526 if (nd->nd_flag & ND_NFSV3)
527 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
529 if (nd->nd_flag & ND_NFSV3)
530 nfsrv_postopattr(nd, getret, &nva);
533 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
534 *tl = txdr_unsigned(len);
535 mbuf_setnext(nd->nd_mb, mp);
537 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
545 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
546 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
549 int error = 0, cnt, len, getret = 1, reqlen, eof = 0;
553 struct nfsstate st, *stp = &st;
554 struct nfslock lo, *lop = &lo;
555 nfsv4stateid_t stateid;
558 if (nd->nd_repstat) {
559 nfsrv_postopattr(nd, getret, &nva);
562 if (nd->nd_flag & ND_NFSV2) {
563 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
564 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
565 reqlen = fxdr_unsigned(int, *tl);
566 } else if (nd->nd_flag & ND_NFSV3) {
567 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
568 off = fxdr_hyper(tl);
570 reqlen = fxdr_unsigned(int, *tl);
572 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
573 reqlen = fxdr_unsigned(int, *(tl + 6));
575 if (reqlen > NFS_SRVMAXDATA(nd)) {
576 reqlen = NFS_SRVMAXDATA(nd);
577 } else if (reqlen < 0) {
581 if (nd->nd_flag & ND_NFSV4) {
582 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
583 lop->lo_flags = NFSLCK_READ;
584 stp->ls_ownerlen = 0;
586 stp->ls_uid = nd->nd_cred->cr_uid;
587 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
588 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
589 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
590 if (nd->nd_flag & ND_IMPLIEDCLID) {
591 if (nd->nd_clientid.qval != clientid.qval)
592 printf("EEK! multiple clids\n");
594 nd->nd_flag |= ND_IMPLIEDCLID;
595 nd->nd_clientid.qval = clientid.qval;
597 stp->ls_stateid.other[2] = *tl++;
598 off = fxdr_hyper(tl);
601 lop->lo_end = off + reqlen;
603 * Paranoia, just in case it wraps around.
605 if (lop->lo_end < off)
606 lop->lo_end = NFS64BITSSET;
608 if (vnode_vtype(vp) != VREG) {
609 if (nd->nd_flag & ND_NFSV3)
610 nd->nd_repstat = EINVAL;
612 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
615 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
617 nd->nd_repstat = getret;
618 if (!nd->nd_repstat &&
619 (nva.na_uid != nd->nd_cred->cr_uid ||
620 NFSVNO_EXSTRICTACCESS(exp))) {
621 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
623 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
625 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
626 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
627 NFSACCCHK_VPISLOCKED, NULL);
629 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
630 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
631 &stateid, exp, nd, p);
632 if (nd->nd_repstat) {
634 if (nd->nd_flag & ND_NFSV3)
635 nfsrv_postopattr(nd, getret, &nva);
638 if (off >= nva.na_size) {
641 } else if (reqlen == 0)
643 else if ((off + reqlen) > nva.na_size)
644 cnt = nva.na_size - off;
647 len = NFSM_RNDUP(cnt);
650 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
652 if (!(nd->nd_flag & ND_NFSV4)) {
653 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
655 nd->nd_repstat = getret;
657 if (nd->nd_repstat) {
661 if (nd->nd_flag & ND_NFSV3)
662 nfsrv_postopattr(nd, getret, &nva);
667 if (nd->nd_flag & ND_NFSV2) {
668 nfsrv_fillattr(nd, &nva);
669 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
671 if (nd->nd_flag & ND_NFSV3) {
672 nfsrv_postopattr(nd, getret, &nva);
673 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
674 *tl++ = txdr_unsigned(cnt);
676 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
677 if (len < reqlen || eof)
680 *tl++ = newnfs_false;
682 *tl = txdr_unsigned(cnt);
684 mbuf_setnext(nd->nd_mb, m3);
686 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
698 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
699 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
704 struct nfsvattr nva, forat;
705 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
706 int stable = NFSWRITE_FILESYNC;
708 struct nfsstate st, *stp = &st;
709 struct nfslock lo, *lop = &lo;
710 nfsv4stateid_t stateid;
713 if (nd->nd_repstat) {
714 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
717 if (nd->nd_flag & ND_NFSV2) {
718 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
719 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
721 retlen = len = fxdr_unsigned(int32_t, *tl);
722 } else if (nd->nd_flag & ND_NFSV3) {
723 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
724 off = fxdr_hyper(tl);
726 stable = fxdr_unsigned(int, *tl++);
727 retlen = len = fxdr_unsigned(int32_t, *tl);
729 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
730 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
731 lop->lo_flags = NFSLCK_WRITE;
732 stp->ls_ownerlen = 0;
734 stp->ls_uid = nd->nd_cred->cr_uid;
735 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
736 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
737 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
738 if (nd->nd_flag & ND_IMPLIEDCLID) {
739 if (nd->nd_clientid.qval != clientid.qval)
740 printf("EEK! multiple clids\n");
742 nd->nd_flag |= ND_IMPLIEDCLID;
743 nd->nd_clientid.qval = clientid.qval;
745 stp->ls_stateid.other[2] = *tl++;
746 off = fxdr_hyper(tl);
749 stable = fxdr_unsigned(int, *tl++);
750 retlen = len = fxdr_unsigned(int32_t, *tl);
751 lop->lo_end = off + len;
753 * Paranoia, just in case it wraps around, which shouldn't
754 * ever happen anyhow.
756 if (lop->lo_end < lop->lo_first)
757 lop->lo_end = NFS64BITSSET;
761 * Loop through the mbuf chain, counting how many mbufs are a
762 * part of this write operation, so the iovec size is known.
766 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
782 if (retlen > NFS_MAXDATA || retlen < 0)
783 nd->nd_repstat = EIO;
784 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
785 if (nd->nd_flag & ND_NFSV3)
786 nd->nd_repstat = EINVAL;
788 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
791 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
793 nd->nd_repstat = forat_ret;
794 if (!nd->nd_repstat &&
795 (forat.na_uid != nd->nd_cred->cr_uid ||
796 NFSVNO_EXSTRICTACCESS(exp)))
797 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
799 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
800 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
801 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
802 &stateid, exp, nd, p);
804 if (nd->nd_repstat) {
806 if (nd->nd_flag & ND_NFSV3)
807 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
812 * For NFS Version 2, it is not obvious what a write of zero length
813 * should do, but I might as well be consistent with Version 3,
814 * which is to return ok so long as there are no permission problems.
817 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
818 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
819 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
821 panic("nfsrv_write mbuf");
823 if (nd->nd_flag & ND_NFSV4)
826 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
829 nd->nd_repstat = aftat_ret;
830 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
831 if (nd->nd_flag & ND_NFSV3)
832 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
835 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
836 *tl++ = txdr_unsigned(retlen);
837 if (stable == NFSWRITE_UNSTABLE)
838 *tl++ = txdr_unsigned(stable);
840 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
842 * Actually, there is no need to txdr these fields,
843 * but it may make the values more human readable,
844 * for debugging purposes.
846 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
847 *tl = txdr_unsigned(nfsboottime.tv_usec);
848 } else if (!nd->nd_repstat)
849 nfsrv_fillattr(nd, &nva);
857 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
858 * now does a truncate to 0 length via. setattr if it already exists
859 * The core creation routine has been extracted out into nfsrv_creatsub(),
860 * so it can also be used by nfsrv_open() for V4.
863 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
864 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
866 struct nfsvattr nva, dirfor, diraft;
867 struct nfsv2_sattr *sp;
868 struct nameidata named;
870 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
871 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
873 vnode_t vp = NULL, dirp = NULL;
878 int32_t cverf[2], tverf[2] = { 0, 0 };
880 if (nd->nd_repstat) {
881 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
884 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
885 LOCKPARENT | LOCKLEAF | SAVESTART);
886 nfsvno_setpathbuf(&named, &bufp, &hashp);
887 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
890 nfsvno_relpathbuf(&named);
893 if (!nd->nd_repstat) {
894 NFSVNO_ATTRINIT(&nva);
895 if (nd->nd_flag & ND_NFSV2) {
896 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
897 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
900 NFSVNO_SETATTRVAL(&nva, type, vtyp);
901 NFSVNO_SETATTRVAL(&nva, mode,
902 nfstov_mode(sp->sa_mode));
903 switch (nva.na_type) {
905 tsize = fxdr_unsigned(int32_t, sp->sa_size);
907 NFSVNO_SETATTRVAL(&nva, size,
913 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
919 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
920 how = fxdr_unsigned(int, *tl);
922 case NFSCREATE_GUARDED:
923 case NFSCREATE_UNCHECKED:
924 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
928 case NFSCREATE_EXCLUSIVE:
929 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
935 NFSVNO_SETATTRVAL(&nva, type, VREG);
938 if (nd->nd_repstat) {
939 nfsvno_relpathbuf(&named);
940 if (nd->nd_flag & ND_NFSV3) {
941 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
943 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
950 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
952 if (nd->nd_flag & ND_NFSV2) {
956 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
960 if (nd->nd_repstat) {
961 if (nd->nd_flag & ND_NFSV3)
962 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
969 if (!(nd->nd_flag & ND_NFSV2)) {
971 case NFSCREATE_GUARDED:
973 nd->nd_repstat = EEXIST;
975 case NFSCREATE_UNCHECKED:
977 case NFSCREATE_EXCLUSIVE:
978 if (named.ni_vp == NULL)
979 NFSVNO_SETATTRVAL(&nva, mode, 0);
985 * Iff doesn't exist, create it
986 * otherwise just truncate to 0 length
987 * should I set the mode too ?
989 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
990 &exclusive_flag, cverf, rdev, p, exp);
992 if (!nd->nd_repstat) {
993 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
995 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
998 if (!nd->nd_repstat) {
999 tverf[0] = nva.na_atime.tv_sec;
1000 tverf[1] = nva.na_atime.tv_nsec;
1003 if (nd->nd_flag & ND_NFSV2) {
1004 if (!nd->nd_repstat) {
1005 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1006 nfsrv_fillattr(nd, &nva);
1009 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1010 || cverf[1] != tverf[1]))
1011 nd->nd_repstat = EEXIST;
1012 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1014 if (!nd->nd_repstat) {
1015 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1016 nfsrv_postopattr(nd, 0, &nva);
1018 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1023 nfsvno_relpathbuf(&named);
1028 * nfs v3 mknod service (and v4 create)
1031 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1032 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1033 struct nfsexstuff *exp)
1035 struct nfsvattr nva, dirfor, diraft;
1037 struct nameidata named;
1038 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1039 u_int32_t major, minor;
1040 enum vtype vtyp = VNON;
1041 nfstype nfs4type = NFNON;
1042 vnode_t vp, dirp = NULL;
1043 nfsattrbit_t attrbits;
1044 char *bufp = NULL, *pathcp = NULL;
1045 u_long *hashp, cnflags;
1046 NFSACL_T *aclp = NULL;
1048 NFSVNO_ATTRINIT(&nva);
1049 cnflags = (LOCKPARENT | SAVESTART);
1050 if (nd->nd_repstat) {
1051 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1054 #ifdef NFS4_ACL_EXTATTR_NAME
1055 aclp = acl_alloc(M_WAITOK);
1060 * For V4, the creation stuff is here, Yuck!
1062 if (nd->nd_flag & ND_NFSV4) {
1063 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1064 vtyp = nfsv34tov_type(*tl);
1065 nfs4type = fxdr_unsigned(nfstype, *tl);
1068 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1072 #ifdef NFS4_ACL_EXTATTR_NAME
1080 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1081 major = fxdr_unsigned(u_int32_t, *tl++);
1082 minor = fxdr_unsigned(u_int32_t, *tl);
1083 nva.na_rdev = NFSMAKEDEV(major, minor);
1089 cnflags = (LOCKPARENT | SAVENAME);
1092 nd->nd_repstat = NFSERR_BADTYPE;
1094 #ifdef NFS4_ACL_EXTATTR_NAME
1100 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1101 nfsvno_setpathbuf(&named, &bufp, &hashp);
1102 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1105 #ifdef NFS4_ACL_EXTATTR_NAME
1108 nfsvno_relpathbuf(&named);
1110 FREE(pathcp, M_TEMP);
1113 if (!nd->nd_repstat) {
1114 if (nd->nd_flag & ND_NFSV3) {
1115 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1116 vtyp = nfsv34tov_type(*tl);
1118 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1121 #ifdef NFS4_ACL_EXTATTR_NAME
1124 nfsvno_relpathbuf(&named);
1126 FREE(pathcp, M_TEMP);
1130 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1131 (vtyp == VCHR || vtyp == VBLK)) {
1132 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1133 major = fxdr_unsigned(u_int32_t, *tl++);
1134 minor = fxdr_unsigned(u_int32_t, *tl);
1135 nva.na_rdev = NFSMAKEDEV(major, minor);
1139 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1140 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1141 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1142 dirfor.na_gid == nva.na_gid)
1143 NFSVNO_UNSET(&nva, gid);
1144 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1146 if (nd->nd_repstat) {
1148 #ifdef NFS4_ACL_EXTATTR_NAME
1151 nfsvno_relpathbuf(&named);
1153 FREE(pathcp, M_TEMP);
1154 if (nd->nd_flag & ND_NFSV3)
1155 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1161 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1162 * in va_mode, so we'll have to set a default here.
1164 if (NFSVNO_NOTSETMODE(&nva)) {
1172 named.ni_cnd.cn_flags |= WILLBEDIR;
1173 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1174 if (nd->nd_repstat) {
1176 if (nd->nd_flag & ND_NFSV3)
1177 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1181 #ifdef NFS4_ACL_EXTATTR_NAME
1184 if (nd->nd_flag & ND_NFSV3)
1185 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1190 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1192 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1194 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1195 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1197 #ifdef NFS4_ACL_EXTATTR_NAME
1201 } else if (vtyp == VLNK) {
1202 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1203 &dirfor, &diraft, &diraft_ret, &attrbits,
1204 aclp, p, exp, pathcp, pathlen);
1205 #ifdef NFS4_ACL_EXTATTR_NAME
1208 FREE(pathcp, M_TEMP);
1213 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1214 if (!nd->nd_repstat) {
1216 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1217 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1218 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1219 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1222 NFSVOPUNLOCK(vp, 0, p);
1229 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1231 if (!nd->nd_repstat) {
1232 if (nd->nd_flag & ND_NFSV3) {
1233 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1234 nfsrv_postopattr(nd, 0, &nva);
1236 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1237 *tl++ = newnfs_false;
1238 txdr_hyper(dirfor.na_filerev, tl);
1240 txdr_hyper(diraft.na_filerev, tl);
1241 (void) nfsrv_putattrbit(nd, &attrbits);
1244 if (nd->nd_flag & ND_NFSV3)
1245 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1246 #ifdef NFS4_ACL_EXTATTR_NAME
1252 #ifdef NFS4_ACL_EXTATTR_NAME
1256 nfsvno_relpathbuf(&named);
1258 FREE(pathcp, M_TEMP);
1263 * nfs remove service
1266 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1267 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1269 struct nameidata named;
1271 int error, dirfor_ret = 1, diraft_ret = 1;
1272 vnode_t dirp = NULL;
1273 struct nfsvattr dirfor, diraft;
1277 if (nd->nd_repstat) {
1278 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1281 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1282 LOCKPARENT | LOCKLEAF);
1283 nfsvno_setpathbuf(&named, &bufp, &hashp);
1284 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1287 nfsvno_relpathbuf(&named);
1290 if (!nd->nd_repstat) {
1291 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1294 nfsvno_relpathbuf(&named);
1297 if (!(nd->nd_flag & ND_NFSV2)) {
1298 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1305 if (!nd->nd_repstat) {
1306 if (nd->nd_flag & ND_NFSV4) {
1307 if (vnode_vtype(named.ni_vp) == VDIR)
1308 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1309 nd->nd_cred, p, exp);
1311 nd->nd_repstat = nfsvno_removesub(&named, 1,
1312 nd->nd_cred, p, exp);
1313 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1314 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1315 nd->nd_cred, p, exp);
1317 nd->nd_repstat = nfsvno_removesub(&named, 0,
1318 nd->nd_cred, p, exp);
1321 if (!(nd->nd_flag & ND_NFSV2)) {
1323 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1327 if (nd->nd_flag & ND_NFSV3) {
1328 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1330 } else if (!nd->nd_repstat) {
1331 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1332 *tl++ = newnfs_false;
1333 txdr_hyper(dirfor.na_filerev, tl);
1335 txdr_hyper(diraft.na_filerev, tl);
1342 * nfs rename service
1345 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1346 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1347 struct nfsexstuff *toexp)
1350 int error, fdirfor_ret = 1, fdiraft_ret = 1;
1351 int tdirfor_ret = 1, tdiraft_ret = 1;
1352 struct nameidata fromnd, tond;
1353 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1354 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1355 struct nfsexstuff tnes;
1358 char *bufp, *tbufp = NULL;
1361 if (nd->nd_repstat) {
1362 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1363 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1366 if (!(nd->nd_flag & ND_NFSV2))
1367 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1368 tond.ni_cnd.cn_nameiop = 0;
1369 tond.ni_startdir = NULL;
1370 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1371 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1372 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1377 nfsvno_relpathbuf(&fromnd);
1380 if (nd->nd_flag & ND_NFSV4) {
1383 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1385 error = nfsrv_mtofh(nd, &tfh);
1388 /* todp is always NULL except NFSv4 */
1389 nfsvno_relpathbuf(&fromnd);
1392 nd->nd_cred->cr_uid = nd->nd_saveduid;
1393 /* Won't lock vfs if already locked, mp == NULL */
1394 tnes.nes_vfslocked = exp->nes_vfslocked;
1395 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, &mp, 0, p);
1397 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1399 NFSVOPUNLOCK(tdp, 0, p);
1402 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1403 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1404 if (!nd->nd_repstat) {
1405 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1408 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1409 !(nd->nd_flag & ND_NFSV4))
1410 nfsvno_unlockvfs(mp);
1414 nfsvno_relpathbuf(&fromnd);
1415 nfsvno_relpathbuf(&tond);
1419 if (nd->nd_repstat) {
1420 if (nd->nd_flag & ND_NFSV3) {
1421 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1423 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1427 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1428 !(nd->nd_flag & ND_NFSV4))
1429 nfsvno_unlockvfs(mp);
1433 nfsvno_relpathbuf(&fromnd);
1434 nfsvno_relpathbuf(&tond);
1439 * Done parsing, now down to business.
1441 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1442 if (nd->nd_repstat) {
1443 if (nd->nd_flag & ND_NFSV3) {
1444 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1446 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1452 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1453 !(nd->nd_flag & ND_NFSV4))
1454 nfsvno_unlockvfs(mp);
1457 nfsvno_relpathbuf(&tond);
1460 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1461 tond.ni_cnd.cn_flags |= WILLBEDIR;
1462 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1463 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1464 nd->nd_flag, nd->nd_cred, p);
1466 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1469 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1471 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1472 !(nd->nd_flag & ND_NFSV4))
1473 nfsvno_unlockvfs(mp);
1478 if (nd->nd_flag & ND_NFSV3) {
1479 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1480 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1481 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1482 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1483 *tl++ = newnfs_false;
1484 txdr_hyper(fdirfor.na_filerev, tl);
1486 txdr_hyper(fdiraft.na_filerev, tl);
1488 *tl++ = newnfs_false;
1489 txdr_hyper(tdirfor.na_filerev, tl);
1491 txdr_hyper(tdiraft.na_filerev, tl);
1500 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1501 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1502 struct nfsexstuff *toexp)
1504 struct nameidata named;
1506 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1507 vnode_t dirp = NULL, dp = NULL;
1508 struct nfsvattr dirfor, diraft, at;
1509 struct nfsexstuff tnes;
1515 if (nd->nd_repstat) {
1516 nfsrv_postopattr(nd, getret, &at);
1517 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1520 NFSVOPUNLOCK(vp, 0, p);
1521 if (vnode_vtype(vp) == VDIR) {
1522 if (nd->nd_flag & ND_NFSV4)
1523 nd->nd_repstat = NFSERR_ISDIR;
1525 nd->nd_repstat = NFSERR_INVAL;
1528 } else if (vnode_vtype(vp) == VLNK) {
1529 if (nd->nd_flag & ND_NFSV2)
1530 nd->nd_repstat = NFSERR_INVAL;
1532 nd->nd_repstat = NFSERR_NOTSUPP;
1536 if (!nd->nd_repstat) {
1537 if (nd->nd_flag & ND_NFSV4) {
1541 error = nfsrv_mtofh(nd, &dfh);
1544 /* tovp is always NULL unless NFSv4 */
1547 /* Won't lock vfs if already locked, mp == NULL */
1548 tnes.nes_vfslocked = exp->nes_vfslocked;
1549 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, &mp, 0,
1552 NFSVOPUNLOCK(dp, 0, p);
1555 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1556 LOCKPARENT | SAVENAME);
1557 if (!nd->nd_repstat) {
1558 nfsvno_setpathbuf(&named, &bufp, &hashp);
1559 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1563 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1564 !(nd->nd_flag & ND_NFSV4))
1565 nfsvno_unlockvfs(mp);
1568 nfsvno_relpathbuf(&named);
1571 if (!nd->nd_repstat) {
1572 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1577 nfsvno_relpathbuf(&named);
1581 if (nd->nd_flag & ND_NFSV2) {
1585 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1589 if (!nd->nd_repstat)
1590 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1591 if (nd->nd_flag & ND_NFSV3)
1592 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1594 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1597 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1598 !(nd->nd_flag & ND_NFSV4))
1599 nfsvno_unlockvfs(mp);
1601 if (nd->nd_flag & ND_NFSV3) {
1602 nfsrv_postopattr(nd, getret, &at);
1603 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1604 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1605 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1606 *tl++ = newnfs_false;
1607 txdr_hyper(dirfor.na_filerev, tl);
1609 txdr_hyper(diraft.na_filerev, tl);
1615 * nfs symbolic link service
1618 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1619 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1620 struct nfsexstuff *exp)
1622 struct nfsvattr nva, dirfor, diraft;
1623 struct nameidata named;
1624 int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1625 vnode_t dirp = NULL;
1626 char *bufp, *pathcp = NULL;
1629 if (nd->nd_repstat) {
1630 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1635 NFSVNO_ATTRINIT(&nva);
1636 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1637 LOCKPARENT | SAVESTART);
1638 nfsvno_setpathbuf(&named, &bufp, &hashp);
1639 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1640 if (!error && !nd->nd_repstat)
1641 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1644 nfsvno_relpathbuf(&named);
1647 if (!nd->nd_repstat) {
1648 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1651 nfsvno_relpathbuf(&named);
1653 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1659 * And call nfsrvd_symlinksub() to do the common code. It will
1660 * return EBADRPC upon a parsing error, 0 otherwise.
1662 if (!nd->nd_repstat) {
1664 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1666 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1667 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1669 } else if (dirp != NULL) {
1670 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1674 FREE(pathcp, M_TEMP);
1676 if (nd->nd_flag & ND_NFSV3) {
1677 if (!nd->nd_repstat) {
1678 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1679 nfsrv_postopattr(nd, 0, &nva);
1681 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1687 * Common code for creating a symbolic link.
1690 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1691 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1692 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1693 int *diraft_retp, nfsattrbit_t *attrbitp,
1694 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1699 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1700 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1701 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1702 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1703 if (nd->nd_flag & ND_NFSV3) {
1704 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1705 if (!nd->nd_repstat)
1706 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1707 nvap, nd->nd_cred, p, 1);
1710 NFSVOPUNLOCK(ndp->ni_vp, 0, p);
1717 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1720 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1721 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1722 *tl++ = newnfs_false;
1723 txdr_hyper(dirforp->na_filerev, tl);
1725 txdr_hyper(diraftp->na_filerev, tl);
1726 (void) nfsrv_putattrbit(nd, attrbitp);
1734 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1735 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1736 struct nfsexstuff *exp)
1738 struct nfsvattr nva, dirfor, diraft;
1739 struct nameidata named;
1741 int error, dirfor_ret = 1, diraft_ret = 1;
1742 vnode_t dirp = NULL;
1746 if (nd->nd_repstat) {
1747 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1750 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1751 LOCKPARENT | SAVENAME);
1752 nfsvno_setpathbuf(&named, &bufp, &hashp);
1753 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1756 nfsvno_relpathbuf(&named);
1759 if (!nd->nd_repstat) {
1760 NFSVNO_ATTRINIT(&nva);
1761 if (nd->nd_flag & ND_NFSV3) {
1762 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1765 nfsvno_relpathbuf(&named);
1769 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1770 nva.na_mode = nfstov_mode(*tl++);
1773 if (!nd->nd_repstat) {
1774 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1777 nfsvno_relpathbuf(&named);
1779 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1783 if (nd->nd_repstat) {
1785 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1789 if (nd->nd_flag & ND_NFSV3)
1790 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1795 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1798 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1800 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1801 &diraft_ret, NULL, NULL, p, exp);
1803 if (nd->nd_flag & ND_NFSV3) {
1804 if (!nd->nd_repstat) {
1805 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1806 nfsrv_postopattr(nd, 0, &nva);
1808 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1809 } else if (!nd->nd_repstat) {
1810 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1811 nfsrv_fillattr(nd, &nva);
1816 nfsvno_relpathbuf(&named);
1821 * Code common to mkdir for V2,3 and 4.
1824 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1825 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1826 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1827 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1828 NFSPROC_T *p, struct nfsexstuff *exp)
1833 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1834 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1835 nd->nd_cred, p, exp);
1836 if (!nd->nd_repstat) {
1838 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1839 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1840 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1841 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1843 if (vpp && !nd->nd_repstat) {
1844 NFSVOPUNLOCK(vp, 0, p);
1851 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1854 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1855 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1856 *tl++ = newnfs_false;
1857 txdr_hyper(dirforp->na_filerev, tl);
1859 txdr_hyper(diraftp->na_filerev, tl);
1860 (void) nfsrv_putattrbit(nd, attrbitp);
1865 * nfs commit service
1868 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1869 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1871 struct nfsvattr bfor, aft;
1873 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1876 if (nd->nd_repstat) {
1877 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1880 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1882 * XXX At this time VOP_FSYNC() does not accept offset and byte
1883 * count parameters, so these arguments are useless (someday maybe).
1885 off = fxdr_hyper(tl);
1887 cnt = fxdr_unsigned(int, *tl);
1888 if (nd->nd_flag & ND_NFSV3)
1889 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1890 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1891 if (nd->nd_flag & ND_NFSV3) {
1892 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1893 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1896 if (!nd->nd_repstat) {
1897 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1898 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1899 *tl = txdr_unsigned(nfsboottime.tv_usec);
1908 * nfs statfs service
1911 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1912 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1921 if (nd->nd_repstat) {
1922 nfsrv_postopattr(nd, getret, &at);
1926 nd->nd_repstat = nfsvno_statfs(vp, sf);
1927 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1929 if (nd->nd_flag & ND_NFSV3)
1930 nfsrv_postopattr(nd, getret, &at);
1933 if (nd->nd_flag & ND_NFSV2) {
1934 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1935 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1936 *tl++ = txdr_unsigned(sf->f_bsize);
1937 *tl++ = txdr_unsigned(sf->f_blocks);
1938 *tl++ = txdr_unsigned(sf->f_bfree);
1939 *tl = txdr_unsigned(sf->f_bavail);
1941 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1942 tval = (u_quad_t)sf->f_blocks;
1943 tval *= (u_quad_t)sf->f_bsize;
1944 txdr_hyper(tval, tl); tl += 2;
1945 tval = (u_quad_t)sf->f_bfree;
1946 tval *= (u_quad_t)sf->f_bsize;
1947 txdr_hyper(tval, tl); tl += 2;
1948 tval = (u_quad_t)sf->f_bavail;
1949 tval *= (u_quad_t)sf->f_bsize;
1950 txdr_hyper(tval, tl); tl += 2;
1951 tval = (u_quad_t)sf->f_files;
1952 txdr_hyper(tval, tl); tl += 2;
1953 tval = (u_quad_t)sf->f_ffree;
1954 txdr_hyper(tval, tl); tl += 2;
1955 tval = (u_quad_t)sf->f_ffree;
1956 txdr_hyper(tval, tl); tl += 2;
1963 * nfs fsinfo service
1966 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1967 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1970 struct nfsfsinfo fs;
1974 if (nd->nd_repstat) {
1975 nfsrv_postopattr(nd, getret, &at);
1978 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1979 nfsvno_getfs(&fs, isdgram);
1981 nfsrv_postopattr(nd, getret, &at);
1982 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1983 *tl++ = txdr_unsigned(fs.fs_rtmax);
1984 *tl++ = txdr_unsigned(fs.fs_rtpref);
1985 *tl++ = txdr_unsigned(fs.fs_rtmult);
1986 *tl++ = txdr_unsigned(fs.fs_wtmax);
1987 *tl++ = txdr_unsigned(fs.fs_wtpref);
1988 *tl++ = txdr_unsigned(fs.fs_wtmult);
1989 *tl++ = txdr_unsigned(fs.fs_dtpref);
1990 txdr_hyper(fs.fs_maxfilesize, tl);
1992 txdr_nfsv3time(&fs.fs_timedelta, tl);
1994 *tl = txdr_unsigned(fs.fs_properties);
1999 * nfs pathconf service
2002 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2003 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2005 struct nfsv3_pathconf *pc;
2007 register_t linkmax, namemax, chownres, notrunc;
2010 if (nd->nd_repstat) {
2011 nfsrv_postopattr(nd, getret, &at);
2014 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2016 if (!nd->nd_repstat)
2017 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2019 if (!nd->nd_repstat)
2020 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2021 &chownres, nd->nd_cred, p);
2022 if (!nd->nd_repstat)
2023 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2025 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2027 nfsrv_postopattr(nd, getret, &at);
2028 if (!nd->nd_repstat) {
2029 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2030 pc->pc_linkmax = txdr_unsigned(linkmax);
2031 pc->pc_namemax = txdr_unsigned(namemax);
2032 pc->pc_notrunc = txdr_unsigned(notrunc);
2033 pc->pc_chownrestricted = txdr_unsigned(chownres);
2036 * These should probably be supported by VOP_PATHCONF(), but
2037 * until msdosfs is exportable (why would you want to?), the
2038 * Unix defaults should be ok.
2040 pc->pc_caseinsensitive = newnfs_false;
2041 pc->pc_casepreserving = newnfs_true;
2047 * nfsv4 lock service
2050 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2051 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2055 struct nfsstate *stp = NULL;
2056 struct nfslock *lop;
2057 struct nfslockconflict cf;
2059 u_short flags = NFSLCK_LOCK, lflags;
2060 u_int64_t offset, len;
2061 nfsv4stateid_t stateid;
2064 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2065 i = fxdr_unsigned(int, *tl++);
2067 case NFSV4LOCKT_READW:
2068 flags |= NFSLCK_BLOCKING;
2069 case NFSV4LOCKT_READ:
2070 lflags = NFSLCK_READ;
2072 case NFSV4LOCKT_WRITEW:
2073 flags |= NFSLCK_BLOCKING;
2074 case NFSV4LOCKT_WRITE:
2075 lflags = NFSLCK_WRITE;
2078 nd->nd_repstat = NFSERR_BADXDR;
2081 if (*tl++ == newnfs_true)
2082 flags |= NFSLCK_RECLAIM;
2083 offset = fxdr_hyper(tl);
2085 len = fxdr_hyper(tl);
2087 if (*tl == newnfs_true)
2088 flags |= NFSLCK_OPENTOLOCK;
2089 if (flags & NFSLCK_OPENTOLOCK) {
2090 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2091 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2092 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2093 nd->nd_repstat = NFSERR_BADXDR;
2096 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2097 M_NFSDSTATE, M_WAITOK);
2098 stp->ls_ownerlen = i;
2099 stp->ls_op = nd->nd_rp;
2100 stp->ls_seq = fxdr_unsigned(int, *tl++);
2101 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2102 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2104 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2105 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2106 clientid.lval[0] = *tl++;
2107 clientid.lval[1] = *tl++;
2108 if (nd->nd_flag & ND_IMPLIEDCLID) {
2109 if (nd->nd_clientid.qval != clientid.qval)
2110 printf("EEK! multiple clids\n");
2112 nd->nd_flag |= ND_IMPLIEDCLID;
2113 nd->nd_clientid.qval = clientid.qval;
2115 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2119 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2120 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2121 M_NFSDSTATE, M_WAITOK);
2122 stp->ls_ownerlen = 0;
2123 stp->ls_op = nd->nd_rp;
2124 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2125 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2127 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2128 stp->ls_seq = fxdr_unsigned(int, *tl);
2129 clientid.lval[0] = stp->ls_stateid.other[0];
2130 clientid.lval[1] = stp->ls_stateid.other[1];
2131 if (nd->nd_flag & ND_IMPLIEDCLID) {
2132 if (nd->nd_clientid.qval != clientid.qval)
2133 printf("EEK! multiple clids\n");
2135 nd->nd_flag |= ND_IMPLIEDCLID;
2136 nd->nd_clientid.qval = clientid.qval;
2139 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2140 M_NFSDLOCK, M_WAITOK);
2141 lop->lo_first = offset;
2142 if (len == NFS64BITSSET) {
2143 lop->lo_end = NFS64BITSSET;
2145 lop->lo_end = offset + len;
2146 if (lop->lo_end <= lop->lo_first)
2147 nd->nd_repstat = NFSERR_INVAL;
2149 lop->lo_flags = lflags;
2150 stp->ls_flags = flags;
2151 stp->ls_uid = nd->nd_cred->cr_uid;
2154 * Do basic access checking.
2156 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2157 if (vnode_vtype(vp) == VDIR)
2158 nd->nd_repstat = NFSERR_ISDIR;
2160 nd->nd_repstat = NFSERR_INVAL;
2162 if (!nd->nd_repstat) {
2163 if (lflags & NFSLCK_WRITE) {
2164 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2165 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2166 NFSACCCHK_VPISLOCKED, NULL);
2168 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2169 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2170 NFSACCCHK_VPISLOCKED, NULL);
2172 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2173 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2174 NFSACCCHK_VPISLOCKED, NULL);
2179 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2180 * seqid# gets updated. nfsrv_lockctrl() will return the value
2181 * of nd_repstat, if it gets that far.
2183 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2184 &stateid, exp, nd, p);
2186 FREE((caddr_t)lop, M_NFSDLOCK);
2188 FREE((caddr_t)stp, M_NFSDSTATE);
2189 if (!nd->nd_repstat) {
2190 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2191 *tl++ = txdr_unsigned(stateid.seqid);
2192 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2193 } else if (nd->nd_repstat == NFSERR_DENIED) {
2194 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2195 txdr_hyper(cf.cl_first, tl);
2197 if (cf.cl_end == NFS64BITSSET)
2200 len = cf.cl_end - cf.cl_first;
2201 txdr_hyper(len, tl);
2203 if (cf.cl_flags == NFSLCK_WRITE)
2204 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2206 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2207 *tl++ = stateid.other[0];
2208 *tl = stateid.other[1];
2209 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2216 free((caddr_t)stp, M_NFSDSTATE);
2221 * nfsv4 lock test service
2224 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2225 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2229 struct nfsstate *stp = NULL;
2230 struct nfslock lo, *lop = &lo;
2231 struct nfslockconflict cf;
2233 nfsv4stateid_t stateid;
2237 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2238 i = fxdr_unsigned(int, *(tl + 7));
2239 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2240 nd->nd_repstat = NFSERR_BADXDR;
2243 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2244 M_NFSDSTATE, M_WAITOK);
2245 stp->ls_ownerlen = i;
2247 stp->ls_flags = NFSLCK_TEST;
2248 stp->ls_uid = nd->nd_cred->cr_uid;
2249 i = fxdr_unsigned(int, *tl++);
2251 case NFSV4LOCKT_READW:
2252 stp->ls_flags |= NFSLCK_BLOCKING;
2253 case NFSV4LOCKT_READ:
2254 lo.lo_flags = NFSLCK_READ;
2256 case NFSV4LOCKT_WRITEW:
2257 stp->ls_flags |= NFSLCK_BLOCKING;
2258 case NFSV4LOCKT_WRITE:
2259 lo.lo_flags = NFSLCK_WRITE;
2262 nd->nd_repstat = NFSERR_BADXDR;
2265 lo.lo_first = fxdr_hyper(tl);
2267 len = fxdr_hyper(tl);
2268 if (len == NFS64BITSSET) {
2269 lo.lo_end = NFS64BITSSET;
2271 lo.lo_end = lo.lo_first + len;
2272 if (lo.lo_end <= lo.lo_first)
2273 nd->nd_repstat = NFSERR_INVAL;
2276 clientid.lval[0] = *tl++;
2277 clientid.lval[1] = *tl;
2278 if (nd->nd_flag & ND_IMPLIEDCLID) {
2279 if (nd->nd_clientid.qval != clientid.qval)
2280 printf("EEK! multiple clids\n");
2282 nd->nd_flag |= ND_IMPLIEDCLID;
2283 nd->nd_clientid.qval = clientid.qval;
2285 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2288 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2289 if (vnode_vtype(vp) == VDIR)
2290 nd->nd_repstat = NFSERR_ISDIR;
2292 nd->nd_repstat = NFSERR_INVAL;
2294 if (!nd->nd_repstat)
2295 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2296 &stateid, exp, nd, p);
2298 FREE((caddr_t)stp, M_NFSDSTATE);
2299 if (nd->nd_repstat) {
2300 if (nd->nd_repstat == NFSERR_DENIED) {
2301 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2302 txdr_hyper(cf.cl_first, tl);
2304 if (cf.cl_end == NFS64BITSSET)
2307 len = cf.cl_end - cf.cl_first;
2308 txdr_hyper(len, tl);
2310 if (cf.cl_flags == NFSLCK_WRITE)
2311 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2313 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2314 *tl++ = stp->ls_stateid.other[0];
2315 *tl = stp->ls_stateid.other[1];
2316 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2324 free((caddr_t)stp, M_NFSDSTATE);
2329 * nfsv4 unlock service
2332 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2333 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2337 struct nfsstate *stp;
2338 struct nfslock *lop;
2340 nfsv4stateid_t stateid;
2344 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2345 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2346 M_NFSDSTATE, M_WAITOK);
2347 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2348 M_NFSDLOCK, M_WAITOK);
2349 stp->ls_flags = NFSLCK_UNLOCK;
2350 lop->lo_flags = NFSLCK_UNLOCK;
2351 stp->ls_op = nd->nd_rp;
2352 i = fxdr_unsigned(int, *tl++);
2354 case NFSV4LOCKT_READW:
2355 stp->ls_flags |= NFSLCK_BLOCKING;
2356 case NFSV4LOCKT_READ:
2358 case NFSV4LOCKT_WRITEW:
2359 stp->ls_flags |= NFSLCK_BLOCKING;
2360 case NFSV4LOCKT_WRITE:
2363 nd->nd_repstat = NFSERR_BADXDR;
2364 free(stp, M_NFSDSTATE);
2365 free(lop, M_NFSDLOCK);
2368 stp->ls_ownerlen = 0;
2369 stp->ls_uid = nd->nd_cred->cr_uid;
2370 stp->ls_seq = fxdr_unsigned(int, *tl++);
2371 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2372 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2374 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2375 lop->lo_first = fxdr_hyper(tl);
2377 len = fxdr_hyper(tl);
2378 if (len == NFS64BITSSET) {
2379 lop->lo_end = NFS64BITSSET;
2381 lop->lo_end = lop->lo_first + len;
2382 if (lop->lo_end <= lop->lo_first)
2383 nd->nd_repstat = NFSERR_INVAL;
2385 clientid.lval[0] = stp->ls_stateid.other[0];
2386 clientid.lval[1] = stp->ls_stateid.other[1];
2387 if (nd->nd_flag & ND_IMPLIEDCLID) {
2388 if (nd->nd_clientid.qval != clientid.qval)
2389 printf("EEK! multiple clids\n");
2391 nd->nd_flag |= ND_IMPLIEDCLID;
2392 nd->nd_clientid.qval = clientid.qval;
2394 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2395 if (vnode_vtype(vp) == VDIR)
2396 nd->nd_repstat = NFSERR_ISDIR;
2398 nd->nd_repstat = NFSERR_INVAL;
2401 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2402 * seqid# gets incremented. nfsrv_lockctrl() will return the
2403 * value of nd_repstat, if it gets that far.
2405 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2406 &stateid, exp, nd, p);
2408 FREE((caddr_t)stp, M_NFSDSTATE);
2410 free((caddr_t)lop, M_NFSDLOCK);
2411 if (!nd->nd_repstat) {
2412 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2413 *tl++ = txdr_unsigned(stateid.seqid);
2414 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2422 * nfsv4 open service
2425 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2426 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2427 struct nfsexstuff *exp)
2431 struct nfsstate *stp = NULL;
2432 int error = 0, create, claim, exclusive_flag = 0;
2433 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2434 int how = NFSCREATE_UNCHECKED;
2435 int32_t cverf[2], tverf[2] = { 0, 0 };
2436 vnode_t vp = NULL, dirp = NULL;
2437 struct nfsvattr nva, dirfor, diraft;
2438 struct nameidata named;
2439 nfsv4stateid_t stateid, delegstateid;
2440 nfsattrbit_t attrbits;
2444 NFSACL_T *aclp = NULL;
2446 #ifdef NFS4_ACL_EXTATTR_NAME
2447 aclp = acl_alloc(M_WAITOK);
2450 NFSZERO_ATTRBIT(&attrbits);
2451 named.ni_startdir = NULL;
2452 named.ni_cnd.cn_nameiop = 0;
2453 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2454 i = fxdr_unsigned(int, *(tl + 5));
2455 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2456 nd->nd_repstat = NFSERR_BADXDR;
2458 #ifdef NFS4_ACL_EXTATTR_NAME
2463 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2464 M_NFSDSTATE, M_WAITOK);
2465 stp->ls_ownerlen = i;
2466 stp->ls_op = nd->nd_rp;
2467 stp->ls_flags = NFSLCK_OPEN;
2468 stp->ls_uid = nd->nd_cred->cr_uid;
2469 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2470 i = fxdr_unsigned(int, *tl++);
2472 case NFSV4OPEN_ACCESSREAD:
2473 stp->ls_flags |= NFSLCK_READACCESS;
2475 case NFSV4OPEN_ACCESSWRITE:
2476 stp->ls_flags |= NFSLCK_WRITEACCESS;
2478 case NFSV4OPEN_ACCESSBOTH:
2479 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2482 nd->nd_repstat = NFSERR_INVAL;
2484 i = fxdr_unsigned(int, *tl++);
2486 case NFSV4OPEN_DENYNONE:
2488 case NFSV4OPEN_DENYREAD:
2489 stp->ls_flags |= NFSLCK_READDENY;
2491 case NFSV4OPEN_DENYWRITE:
2492 stp->ls_flags |= NFSLCK_WRITEDENY;
2494 case NFSV4OPEN_DENYBOTH:
2495 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2498 nd->nd_repstat = NFSERR_INVAL;
2500 clientid.lval[0] = *tl++;
2501 clientid.lval[1] = *tl;
2502 if (nd->nd_flag & ND_IMPLIEDCLID) {
2503 if (nd->nd_clientid.qval != clientid.qval)
2504 printf("EEK! multiple clids\n");
2506 nd->nd_flag |= ND_IMPLIEDCLID;
2507 nd->nd_clientid.qval = clientid.qval;
2509 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2512 #ifdef NFS4_ACL_EXTATTR_NAME
2515 FREE((caddr_t)stp, M_NFSDSTATE);
2518 NFSVNO_ATTRINIT(&nva);
2519 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2520 create = fxdr_unsigned(int, *tl);
2521 if (!nd->nd_repstat)
2522 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2523 if (create == NFSV4OPEN_CREATE) {
2526 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2527 how = fxdr_unsigned(int, *tl);
2529 case NFSCREATE_UNCHECKED:
2530 case NFSCREATE_GUARDED:
2531 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2534 #ifdef NFS4_ACL_EXTATTR_NAME
2537 FREE((caddr_t)stp, M_NFSDSTATE);
2541 * If the na_gid being set is the same as that of
2542 * the directory it is going in, clear it, since
2543 * that is what will be set by default. This allows
2544 * a user that isn't in that group to do the create.
2546 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2547 nva.na_gid == dirfor.na_gid)
2548 NFSVNO_UNSET(&nva, gid);
2549 if (!nd->nd_repstat)
2550 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2552 case NFSCREATE_EXCLUSIVE:
2553 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2558 nd->nd_repstat = NFSERR_BADXDR;
2560 #ifdef NFS4_ACL_EXTATTR_NAME
2563 FREE((caddr_t)stp, M_NFSDSTATE);
2566 } else if (create != NFSV4OPEN_NOCREATE) {
2567 nd->nd_repstat = NFSERR_BADXDR;
2569 #ifdef NFS4_ACL_EXTATTR_NAME
2572 FREE((caddr_t)stp, M_NFSDSTATE);
2577 * Now, handle the claim, which usually includes looking up a
2578 * name in the directory referenced by dp. The exception is
2579 * NFSV4OPEN_CLAIMPREVIOUS.
2581 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2582 claim = fxdr_unsigned(int, *tl);
2583 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2584 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2585 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2586 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2587 stp->ls_flags |= NFSLCK_DELEGCUR;
2588 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2589 stp->ls_flags |= NFSLCK_DELEGPREV;
2591 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2592 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2593 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2594 claim != NFSV4OPEN_CLAIMNULL)
2595 nd->nd_repstat = NFSERR_INVAL;
2596 if (nd->nd_repstat) {
2597 nd->nd_repstat = nfsrv_opencheck(clientid,
2598 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2600 #ifdef NFS4_ACL_EXTATTR_NAME
2603 FREE((caddr_t)stp, M_NFSDSTATE);
2606 if (create == NFSV4OPEN_CREATE)
2607 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2608 LOCKPARENT | LOCKLEAF | SAVESTART);
2610 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2611 LOCKLEAF | SAVESTART);
2612 nfsvno_setpathbuf(&named, &bufp, &hashp);
2613 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2616 #ifdef NFS4_ACL_EXTATTR_NAME
2619 FREE((caddr_t)stp, M_NFSDSTATE);
2620 nfsvno_relpathbuf(&named);
2623 if (!nd->nd_repstat) {
2624 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2628 nfsvno_relpathbuf(&named);
2630 if (create == NFSV4OPEN_CREATE) {
2632 case NFSCREATE_UNCHECKED:
2635 * Clear the setable attribute bits, except
2636 * for Size, if it is being truncated.
2638 NFSZERO_ATTRBIT(&attrbits);
2639 if (NFSVNO_ISSETSIZE(&nva))
2640 NFSSETBIT_ATTRBIT(&attrbits,
2644 case NFSCREATE_GUARDED:
2645 if (named.ni_vp && !nd->nd_repstat)
2646 nd->nd_repstat = EEXIST;
2648 case NFSCREATE_EXCLUSIVE:
2654 nfsvno_open(nd, &named, clientid, &stateid, stp,
2655 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2656 nd->nd_cred, p, exp, &vp);
2657 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2658 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2659 i = fxdr_unsigned(int, *tl);
2661 case NFSV4OPEN_DELEGATEREAD:
2662 stp->ls_flags |= NFSLCK_DELEGREAD;
2664 case NFSV4OPEN_DELEGATEWRITE:
2665 stp->ls_flags |= NFSLCK_DELEGWRITE;
2666 case NFSV4OPEN_DELEGATENONE:
2669 nd->nd_repstat = NFSERR_BADXDR;
2671 #ifdef NFS4_ACL_EXTATTR_NAME
2674 FREE((caddr_t)stp, M_NFSDSTATE);
2677 stp->ls_flags |= NFSLCK_RECLAIM;
2679 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
2680 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp,
2681 nd, p, nd->nd_repstat);
2683 nd->nd_repstat = NFSERR_BADXDR;
2685 #ifdef NFS4_ACL_EXTATTR_NAME
2688 FREE((caddr_t)stp, M_NFSDSTATE);
2693 * Do basic access checking.
2695 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2696 if (vnode_vtype(vp) == VDIR)
2697 nd->nd_repstat = NFSERR_ISDIR;
2698 else if (vnode_vtype(vp) == VLNK)
2699 nd->nd_repstat = NFSERR_SYMLINK;
2701 nd->nd_repstat = NFSERR_INVAL;
2703 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2704 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2705 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2706 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2707 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2708 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2710 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2711 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2712 NFSACCCHK_VPISLOCKED, NULL);
2715 if (!nd->nd_repstat) {
2716 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2717 if (!nd->nd_repstat) {
2718 tverf[0] = nva.na_atime.tv_sec;
2719 tverf[1] = nva.na_atime.tv_nsec;
2722 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2723 cverf[1] != tverf[1]))
2724 nd->nd_repstat = EEXIST;
2726 * Do the open locking/delegation stuff.
2728 if (!nd->nd_repstat)
2729 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2730 &delegstateid, &rflags, exp, p, nva.na_filerev);
2733 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2734 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2735 * (ie: Leave the NFSVOPUNLOCK() about here.)
2738 NFSVOPUNLOCK(vp, 0, p);
2740 FREE((caddr_t)stp, M_NFSDSTATE);
2741 if (!nd->nd_repstat && dirp)
2742 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2744 if (!nd->nd_repstat) {
2745 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2746 *tl++ = txdr_unsigned(stateid.seqid);
2747 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2748 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2749 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2750 *tl++ = newnfs_true;
2756 *tl++ = newnfs_false; /* Since dirp is not locked */
2757 txdr_hyper(dirfor.na_filerev, tl);
2759 txdr_hyper(diraft.na_filerev, tl);
2762 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2763 (void) nfsrv_putattrbit(nd, &attrbits);
2764 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2765 if (rflags & NFSV4OPEN_READDELEGATE)
2766 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2767 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2768 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2770 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2771 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2772 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2773 *tl++ = txdr_unsigned(delegstateid.seqid);
2774 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2776 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2777 if (rflags & NFSV4OPEN_RECALL)
2781 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2782 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2783 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2784 txdr_hyper(nva.na_size, tl);
2786 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2787 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2788 *tl++ = txdr_unsigned(0x0);
2789 acemask = NFSV4ACE_ALLFILESMASK;
2790 if (nva.na_mode & S_IRUSR)
2791 acemask |= NFSV4ACE_READMASK;
2792 if (nva.na_mode & S_IWUSR)
2793 acemask |= NFSV4ACE_WRITEMASK;
2794 if (nva.na_mode & S_IXUSR)
2795 acemask |= NFSV4ACE_EXECUTEMASK;
2796 *tl = txdr_unsigned(acemask);
2797 (void) nfsm_strtom(nd, "OWNER@", 6);
2805 #ifdef NFS4_ACL_EXTATTR_NAME
2811 #ifdef NFS4_ACL_EXTATTR_NAME
2815 FREE((caddr_t)stp, M_NFSDSTATE);
2820 * nfsv4 close service
2823 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2824 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2827 struct nfsstate st, *stp = &st;
2829 nfsv4stateid_t stateid;
2832 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2833 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2834 stp->ls_ownerlen = 0;
2835 stp->ls_op = nd->nd_rp;
2836 stp->ls_uid = nd->nd_cred->cr_uid;
2837 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2838 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2840 stp->ls_flags = NFSLCK_CLOSE;
2841 clientid.lval[0] = stp->ls_stateid.other[0];
2842 clientid.lval[1] = stp->ls_stateid.other[1];
2843 if (nd->nd_flag & ND_IMPLIEDCLID) {
2844 if (nd->nd_clientid.qval != clientid.qval)
2845 printf("EEK! multiple clids\n");
2847 nd->nd_flag |= ND_IMPLIEDCLID;
2848 nd->nd_clientid.qval = clientid.qval;
2850 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2852 if (!nd->nd_repstat) {
2853 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2854 *tl++ = txdr_unsigned(stateid.seqid);
2855 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2864 * nfsv4 delegpurge service
2867 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2868 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2874 if ((!nfs_rootfhset && !nfsv4root_set) ||
2875 nfsd_checkrootexp(nd)) {
2876 nd->nd_repstat = NFSERR_WRONGSEC;
2879 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2880 clientid.lval[0] = *tl++;
2881 clientid.lval[1] = *tl;
2882 if (nd->nd_flag & ND_IMPLIEDCLID) {
2883 if (nd->nd_clientid.qval != clientid.qval)
2884 printf("EEK! multiple clids\n");
2886 nd->nd_flag |= ND_IMPLIEDCLID;
2887 nd->nd_clientid.qval = clientid.qval;
2889 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2890 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2896 * nfsv4 delegreturn service
2899 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2900 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2904 nfsv4stateid_t stateid;
2907 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2908 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2909 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2910 clientid.lval[0] = stateid.other[0];
2911 clientid.lval[1] = stateid.other[1];
2912 if (nd->nd_flag & ND_IMPLIEDCLID) {
2913 if (nd->nd_clientid.qval != clientid.qval)
2914 printf("EEK! multiple clids\n");
2916 nd->nd_flag |= ND_IMPLIEDCLID;
2917 nd->nd_clientid.qval = clientid.qval;
2919 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2920 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2927 * nfsv4 get file handle service
2930 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2931 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2935 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2937 if (!nd->nd_repstat)
2938 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2943 * nfsv4 open confirm service
2946 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2947 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2950 struct nfsstate st, *stp = &st;
2952 nfsv4stateid_t stateid;
2955 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2956 stp->ls_ownerlen = 0;
2957 stp->ls_op = nd->nd_rp;
2958 stp->ls_uid = nd->nd_cred->cr_uid;
2959 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2960 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2962 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2963 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2964 stp->ls_flags = NFSLCK_CONFIRM;
2965 clientid.lval[0] = stp->ls_stateid.other[0];
2966 clientid.lval[1] = stp->ls_stateid.other[1];
2967 if (nd->nd_flag & ND_IMPLIEDCLID) {
2968 if (nd->nd_clientid.qval != clientid.qval)
2969 printf("EEK! multiple clids\n");
2971 nd->nd_flag |= ND_IMPLIEDCLID;
2972 nd->nd_clientid.qval = clientid.qval;
2974 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2975 if (!nd->nd_repstat) {
2976 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2977 *tl++ = txdr_unsigned(stateid.seqid);
2978 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2986 * nfsv4 open downgrade service
2989 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
2990 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2994 struct nfsstate st, *stp = &st;
2996 nfsv4stateid_t stateid;
2999 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3000 stp->ls_ownerlen = 0;
3001 stp->ls_op = nd->nd_rp;
3002 stp->ls_uid = nd->nd_cred->cr_uid;
3003 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3004 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3006 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3007 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3008 i = fxdr_unsigned(int, *tl++);
3010 case NFSV4OPEN_ACCESSREAD:
3011 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3013 case NFSV4OPEN_ACCESSWRITE:
3014 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3016 case NFSV4OPEN_ACCESSBOTH:
3017 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3021 nd->nd_repstat = NFSERR_BADXDR;
3023 i = fxdr_unsigned(int, *tl);
3025 case NFSV4OPEN_DENYNONE:
3027 case NFSV4OPEN_DENYREAD:
3028 stp->ls_flags |= NFSLCK_READDENY;
3030 case NFSV4OPEN_DENYWRITE:
3031 stp->ls_flags |= NFSLCK_WRITEDENY;
3033 case NFSV4OPEN_DENYBOTH:
3034 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3037 nd->nd_repstat = NFSERR_BADXDR;
3040 clientid.lval[0] = stp->ls_stateid.other[0];
3041 clientid.lval[1] = stp->ls_stateid.other[1];
3042 if (nd->nd_flag & ND_IMPLIEDCLID) {
3043 if (nd->nd_clientid.qval != clientid.qval)
3044 printf("EEK! multiple clids\n");
3046 nd->nd_flag |= ND_IMPLIEDCLID;
3047 nd->nd_clientid.qval = clientid.qval;
3049 if (!nd->nd_repstat)
3050 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3052 if (!nd->nd_repstat) {
3053 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3054 *tl++ = txdr_unsigned(stateid.seqid);
3055 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3063 * nfsv4 renew lease service
3066 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3067 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3073 if ((!nfs_rootfhset && !nfsv4root_set) ||
3074 nfsd_checkrootexp(nd)) {
3075 nd->nd_repstat = NFSERR_WRONGSEC;
3078 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3079 clientid.lval[0] = *tl++;
3080 clientid.lval[1] = *tl;
3081 if (nd->nd_flag & ND_IMPLIEDCLID) {
3082 if (nd->nd_clientid.qval != clientid.qval)
3083 printf("EEK! multiple clids\n");
3085 nd->nd_flag |= ND_IMPLIEDCLID;
3086 nd->nd_clientid.qval = clientid.qval;
3088 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3089 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3095 * nfsv4 security info service
3098 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3099 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3103 struct nameidata named;
3104 vnode_t dirp = NULL, vp;
3106 struct nfsexstuff retnes;
3109 int error, savflag, i;
3114 * All this just to get the export flags for the name.
3116 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3117 LOCKLEAF | SAVESTART);
3118 nfsvno_setpathbuf(&named, &bufp, &hashp);
3119 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3122 nfsvno_relpathbuf(&named);
3125 if (!nd->nd_repstat) {
3126 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3129 nfsvno_relpathbuf(&named);
3135 vrele(named.ni_startdir);
3136 nfsvno_relpathbuf(&named);
3137 fh.nfsrvfh_len = NFSX_MYFH;
3139 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3140 mp = vnode_mount(vp); /* so it won't try to re-lock filesys */
3141 retnes.nes_vfslocked = exp->nes_vfslocked;
3143 savflag = nd->nd_flag;
3144 if (!nd->nd_repstat) {
3145 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, &mp, 0, p);
3149 nd->nd_flag = savflag;
3154 * Finally have the export flags for name, so we can create
3155 * the security info.
3158 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3159 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3160 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3162 *tl = txdr_unsigned(RPCAUTH_UNIX);
3164 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3166 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3167 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3168 nfsgss_mechlist[KERBV_MECH].len);
3169 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3170 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3171 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3173 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3175 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3176 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3177 nfsgss_mechlist[KERBV_MECH].len);
3178 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3179 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3180 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3182 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3184 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3185 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3186 nfsgss_mechlist[KERBV_MECH].len);
3187 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3188 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3189 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3193 *sizp = txdr_unsigned(len);
3198 * nfsv4 set client id service
3201 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3202 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3206 int error = 0, idlen;
3207 struct nfsclient *clp = NULL;
3208 struct sockaddr_in *rad;
3209 u_char *verf, *ucp, *ucp2, addrbuf[24];
3210 nfsquad_t clientid, confirm;
3212 if ((!nfs_rootfhset && !nfsv4root_set) ||
3213 nfsd_checkrootexp(nd)) {
3214 nd->nd_repstat = NFSERR_WRONGSEC;
3217 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3218 verf = (u_char *)tl;
3219 tl += (NFSX_VERF / NFSX_UNSIGNED);
3220 i = fxdr_unsigned(int, *tl);
3221 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3222 nd->nd_repstat = NFSERR_BADXDR;
3226 if (nd->nd_flag & ND_GSS)
3227 i += nd->nd_princlen;
3228 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3229 M_NFSDCLIENT, M_WAITOK);
3230 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3231 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3232 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3233 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3234 clp->lc_req.nr_cred = NULL;
3235 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3236 clp->lc_idlen = idlen;
3237 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3240 if (nd->nd_flag & ND_GSS) {
3241 clp->lc_flags = LCL_GSS;
3242 if (nd->nd_flag & ND_GSSINTEGRITY)
3243 clp->lc_flags |= LCL_GSSINTEGRITY;
3244 else if (nd->nd_flag & ND_GSSPRIVACY)
3245 clp->lc_flags |= LCL_GSSPRIVACY;
3249 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3250 clp->lc_flags |= LCL_NAME;
3251 clp->lc_namelen = nd->nd_princlen;
3252 clp->lc_name = &clp->lc_id[idlen];
3253 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3255 clp->lc_uid = nd->nd_cred->cr_uid;
3256 clp->lc_gid = nd->nd_cred->cr_gid;
3258 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3259 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3260 error = nfsrv_getclientipaddr(nd, clp);
3263 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3264 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3267 * nfsrv_setclient() does the actual work of adding it to the
3268 * client list. If there is no error, the structure has been
3269 * linked into the client list and clp should no longer be used
3270 * here. When an error is returned, it has not been linked in,
3271 * so it should be free'd.
3273 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3274 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3275 if (clp->lc_flags & LCL_TCPCALLBACK)
3276 (void) nfsm_strtom(nd, "tcp", 3);
3278 (void) nfsm_strtom(nd, "udp", 3);
3279 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3280 ucp = (u_char *)&rad->sin_addr.s_addr;
3281 ucp2 = (u_char *)&rad->sin_port;
3282 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3283 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3284 ucp2[0] & 0xff, ucp2[1] & 0xff);
3285 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3288 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3289 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3290 free((caddr_t)clp, M_NFSDCLIENT);
3292 if (!nd->nd_repstat) {
3293 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3294 *tl++ = clientid.lval[0];
3295 *tl++ = clientid.lval[1];
3296 *tl++ = confirm.lval[0];
3297 *tl = confirm.lval[1];
3302 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3303 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3304 free((caddr_t)clp, M_NFSDCLIENT);
3310 * nfsv4 set client id confirm service
3313 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3314 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3315 __unused struct nfsexstuff *exp)
3319 nfsquad_t clientid, confirm;
3321 if ((!nfs_rootfhset && !nfsv4root_set) ||
3322 nfsd_checkrootexp(nd)) {
3323 nd->nd_repstat = NFSERR_WRONGSEC;
3326 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3327 clientid.lval[0] = *tl++;
3328 clientid.lval[1] = *tl++;
3329 confirm.lval[0] = *tl++;
3330 confirm.lval[1] = *tl;
3333 * nfsrv_getclient() searches the client list for a match and
3334 * returns the appropriate NFSERR status.
3336 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3337 NULL, confirm, nd, p);
3343 * nfsv4 verify service
3346 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3347 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3349 int error = 0, ret, fhsize = NFSX_MYFH;
3350 struct nfsvattr nva;
3352 struct nfsfsinfo fs;
3355 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3356 if (!nd->nd_repstat)
3357 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3358 if (!nd->nd_repstat)
3359 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3360 if (!nd->nd_repstat) {
3361 nfsvno_getfs(&fs, isdgram);
3362 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3363 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3365 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3367 nd->nd_repstat = NFSERR_SAME;
3368 else if (ret != NFSERR_NOTSAME)
3369 nd->nd_repstat = ret;
3371 nd->nd_repstat = ret;
3382 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3383 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3384 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3387 int error = 0, createdir;
3389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3390 createdir = fxdr_unsigned(int, *tl);
3391 nd->nd_repstat = NFSERR_NOTSUPP;
3398 * nfsv4 release lock owner service
3401 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3402 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3405 struct nfsstate *stp = NULL;
3409 if ((!nfs_rootfhset && !nfsv4root_set) ||
3410 nfsd_checkrootexp(nd)) {
3411 nd->nd_repstat = NFSERR_WRONGSEC;
3414 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3415 len = fxdr_unsigned(int, *(tl + 2));
3416 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3417 nd->nd_repstat = NFSERR_BADXDR;
3420 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3421 M_NFSDSTATE, M_WAITOK);
3422 stp->ls_ownerlen = len;
3424 stp->ls_flags = NFSLCK_RELEASE;
3425 stp->ls_uid = nd->nd_cred->cr_uid;
3426 clientid.lval[0] = *tl++;
3427 clientid.lval[1] = *tl;
3428 if (nd->nd_flag & ND_IMPLIEDCLID) {
3429 if (nd->nd_clientid.qval != clientid.qval)
3430 printf("EEK! multiple clids\n");
3432 nd->nd_flag |= ND_IMPLIEDCLID;
3433 nd->nd_clientid.qval = clientid.qval;
3435 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3438 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3439 FREE((caddr_t)stp, M_NFSDSTATE);
3443 free((caddr_t)stp, M_NFSDSTATE);