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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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, &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);
1468 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p);
1469 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1470 !(nd->nd_flag & ND_NFSV4))
1471 nfsvno_unlockvfs(mp);
1476 if (nd->nd_flag & ND_NFSV3) {
1477 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1478 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1479 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1480 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1481 *tl++ = newnfs_false;
1482 txdr_hyper(fdirfor.na_filerev, tl);
1484 txdr_hyper(fdiraft.na_filerev, tl);
1486 *tl++ = newnfs_false;
1487 txdr_hyper(tdirfor.na_filerev, tl);
1489 txdr_hyper(tdiraft.na_filerev, tl);
1498 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1499 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1500 struct nfsexstuff *toexp)
1502 struct nameidata named;
1504 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1505 vnode_t dirp = NULL, dp = NULL;
1506 struct nfsvattr dirfor, diraft, at;
1507 struct nfsexstuff tnes;
1513 if (nd->nd_repstat) {
1514 nfsrv_postopattr(nd, getret, &at);
1515 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1518 NFSVOPUNLOCK(vp, 0, p);
1519 if (vnode_vtype(vp) == VDIR) {
1520 if (nd->nd_flag & ND_NFSV4)
1521 nd->nd_repstat = NFSERR_ISDIR;
1523 nd->nd_repstat = NFSERR_INVAL;
1526 } else if (vnode_vtype(vp) == VLNK) {
1527 if (nd->nd_flag & ND_NFSV2)
1528 nd->nd_repstat = NFSERR_INVAL;
1530 nd->nd_repstat = NFSERR_NOTSUPP;
1534 if (!nd->nd_repstat) {
1535 if (nd->nd_flag & ND_NFSV4) {
1539 error = nfsrv_mtofh(nd, &dfh);
1542 /* tovp is always NULL unless NFSv4 */
1545 /* Won't lock vfs if already locked, mp == NULL */
1546 tnes.nes_vfslocked = exp->nes_vfslocked;
1547 nfsd_fhtovp(nd, &dfh, &dp, &tnes, &mp, 0, p);
1549 NFSVOPUNLOCK(dp, 0, p);
1552 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1553 LOCKPARENT | SAVENAME);
1554 if (!nd->nd_repstat) {
1555 nfsvno_setpathbuf(&named, &bufp, &hashp);
1556 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1560 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1561 !(nd->nd_flag & ND_NFSV4))
1562 nfsvno_unlockvfs(mp);
1565 nfsvno_relpathbuf(&named);
1568 if (!nd->nd_repstat) {
1569 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1574 nfsvno_relpathbuf(&named);
1578 if (nd->nd_flag & ND_NFSV2) {
1582 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1586 if (!nd->nd_repstat)
1587 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1588 if (nd->nd_flag & ND_NFSV3)
1589 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1591 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
1594 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1595 !(nd->nd_flag & ND_NFSV4))
1596 nfsvno_unlockvfs(mp);
1598 if (nd->nd_flag & ND_NFSV3) {
1599 nfsrv_postopattr(nd, getret, &at);
1600 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1601 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1602 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1603 *tl++ = newnfs_false;
1604 txdr_hyper(dirfor.na_filerev, tl);
1606 txdr_hyper(diraft.na_filerev, tl);
1612 * nfs symbolic link service
1615 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1616 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1617 struct nfsexstuff *exp)
1619 struct nfsvattr nva, dirfor, diraft;
1620 struct nameidata named;
1621 int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1622 vnode_t dirp = NULL;
1623 char *bufp, *pathcp = NULL;
1626 if (nd->nd_repstat) {
1627 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1632 NFSVNO_ATTRINIT(&nva);
1633 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1634 LOCKPARENT | SAVESTART);
1635 nfsvno_setpathbuf(&named, &bufp, &hashp);
1636 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1637 if (!error && !nd->nd_repstat)
1638 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1641 nfsvno_relpathbuf(&named);
1644 if (!nd->nd_repstat) {
1645 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1648 nfsvno_relpathbuf(&named);
1650 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1656 * And call nfsrvd_symlinksub() to do the common code. It will
1657 * return EBADRPC upon a parsing error, 0 otherwise.
1659 if (!nd->nd_repstat) {
1661 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1663 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1664 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1666 } else if (dirp != NULL) {
1667 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1671 FREE(pathcp, M_TEMP);
1673 if (nd->nd_flag & ND_NFSV3) {
1674 if (!nd->nd_repstat) {
1675 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1676 nfsrv_postopattr(nd, 0, &nva);
1678 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1684 * Common code for creating a symbolic link.
1687 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1688 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1689 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1690 int *diraft_retp, nfsattrbit_t *attrbitp,
1691 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1696 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1697 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1698 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1699 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1700 if (nd->nd_flag & ND_NFSV3) {
1701 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1702 if (!nd->nd_repstat)
1703 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1704 nvap, nd->nd_cred, p);
1707 NFSVOPUNLOCK(ndp->ni_vp, 0, p);
1714 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p);
1717 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1718 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1719 *tl++ = newnfs_false;
1720 txdr_hyper(dirforp->na_filerev, tl);
1722 txdr_hyper(diraftp->na_filerev, tl);
1723 (void) nfsrv_putattrbit(nd, attrbitp);
1731 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1732 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1733 struct nfsexstuff *exp)
1735 struct nfsvattr nva, dirfor, diraft;
1736 struct nameidata named;
1738 int error, dirfor_ret = 1, diraft_ret = 1;
1739 vnode_t dirp = NULL;
1743 if (nd->nd_repstat) {
1744 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1747 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1748 LOCKPARENT | SAVENAME);
1749 nfsvno_setpathbuf(&named, &bufp, &hashp);
1750 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1753 nfsvno_relpathbuf(&named);
1756 if (!nd->nd_repstat) {
1757 NFSVNO_ATTRINIT(&nva);
1758 if (nd->nd_flag & ND_NFSV3) {
1759 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1762 nfsvno_relpathbuf(&named);
1766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1767 nva.na_mode = nfstov_mode(*tl++);
1770 if (!nd->nd_repstat) {
1771 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1774 nfsvno_relpathbuf(&named);
1776 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1780 if (nd->nd_repstat) {
1782 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1786 if (nd->nd_flag & ND_NFSV3)
1787 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1792 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p);
1795 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1797 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1798 &diraft_ret, NULL, NULL, p, exp);
1800 if (nd->nd_flag & ND_NFSV3) {
1801 if (!nd->nd_repstat) {
1802 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1803 nfsrv_postopattr(nd, 0, &nva);
1805 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1806 } else if (!nd->nd_repstat) {
1807 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1808 nfsrv_fillattr(nd, &nva);
1813 nfsvno_relpathbuf(&named);
1818 * Code common to mkdir for V2,3 and 4.
1821 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1822 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1823 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1824 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1825 NFSPROC_T *p, struct nfsexstuff *exp)
1830 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1831 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1832 nd->nd_cred, p, exp);
1833 if (!nd->nd_repstat) {
1835 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1836 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1837 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1838 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1840 if (vpp && !nd->nd_repstat) {
1841 NFSVOPUNLOCK(vp, 0, p);
1848 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p);
1851 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1852 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1853 *tl++ = newnfs_false;
1854 txdr_hyper(dirforp->na_filerev, tl);
1856 txdr_hyper(diraftp->na_filerev, tl);
1857 (void) nfsrv_putattrbit(nd, attrbitp);
1862 * nfs commit service
1865 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1866 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1868 struct nfsvattr bfor, aft;
1870 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1873 if (nd->nd_repstat) {
1874 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1877 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1879 * XXX At this time VOP_FSYNC() does not accept offset and byte
1880 * count parameters, so these arguments are useless (someday maybe).
1882 off = fxdr_hyper(tl);
1884 cnt = fxdr_unsigned(int, *tl);
1885 if (nd->nd_flag & ND_NFSV3)
1886 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p);
1887 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1888 if (nd->nd_flag & ND_NFSV3) {
1889 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p);
1890 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1893 if (!nd->nd_repstat) {
1894 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1895 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1896 *tl = txdr_unsigned(nfsboottime.tv_usec);
1905 * nfs statfs service
1908 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1909 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1918 if (nd->nd_repstat) {
1919 nfsrv_postopattr(nd, getret, &at);
1923 nd->nd_repstat = nfsvno_statfs(vp, sf);
1924 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1926 if (nd->nd_flag & ND_NFSV3)
1927 nfsrv_postopattr(nd, getret, &at);
1930 if (nd->nd_flag & ND_NFSV2) {
1931 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1932 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1933 *tl++ = txdr_unsigned(sf->f_bsize);
1934 *tl++ = txdr_unsigned(sf->f_blocks);
1935 *tl++ = txdr_unsigned(sf->f_bfree);
1936 *tl = txdr_unsigned(sf->f_bavail);
1938 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1939 tval = (u_quad_t)sf->f_blocks;
1940 tval *= (u_quad_t)sf->f_bsize;
1941 txdr_hyper(tval, tl); tl += 2;
1942 tval = (u_quad_t)sf->f_bfree;
1943 tval *= (u_quad_t)sf->f_bsize;
1944 txdr_hyper(tval, tl); tl += 2;
1945 tval = (u_quad_t)sf->f_bavail;
1946 tval *= (u_quad_t)sf->f_bsize;
1947 txdr_hyper(tval, tl); tl += 2;
1948 tval = (u_quad_t)sf->f_files;
1949 txdr_hyper(tval, tl); tl += 2;
1950 tval = (u_quad_t)sf->f_ffree;
1951 txdr_hyper(tval, tl); tl += 2;
1952 tval = (u_quad_t)sf->f_ffree;
1953 txdr_hyper(tval, tl); tl += 2;
1960 * nfs fsinfo service
1963 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1964 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1967 struct nfsfsinfo fs;
1971 if (nd->nd_repstat) {
1972 nfsrv_postopattr(nd, getret, &at);
1975 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
1976 nfsvno_getfs(&fs, isdgram);
1978 nfsrv_postopattr(nd, getret, &at);
1979 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1980 *tl++ = txdr_unsigned(fs.fs_rtmax);
1981 *tl++ = txdr_unsigned(fs.fs_rtpref);
1982 *tl++ = txdr_unsigned(fs.fs_rtmult);
1983 *tl++ = txdr_unsigned(fs.fs_wtmax);
1984 *tl++ = txdr_unsigned(fs.fs_wtpref);
1985 *tl++ = txdr_unsigned(fs.fs_wtmult);
1986 *tl++ = txdr_unsigned(fs.fs_dtpref);
1987 txdr_hyper(fs.fs_maxfilesize, tl);
1989 txdr_nfsv3time(&fs.fs_timedelta, tl);
1991 *tl = txdr_unsigned(fs.fs_properties);
1996 * nfs pathconf service
1999 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2000 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2002 struct nfsv3_pathconf *pc;
2004 register_t linkmax, namemax, chownres, notrunc;
2007 if (nd->nd_repstat) {
2008 nfsrv_postopattr(nd, getret, &at);
2011 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2013 if (!nd->nd_repstat)
2014 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2016 if (!nd->nd_repstat)
2017 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2018 &chownres, nd->nd_cred, p);
2019 if (!nd->nd_repstat)
2020 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2022 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p);
2024 nfsrv_postopattr(nd, getret, &at);
2025 if (!nd->nd_repstat) {
2026 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2027 pc->pc_linkmax = txdr_unsigned(linkmax);
2028 pc->pc_namemax = txdr_unsigned(namemax);
2029 pc->pc_notrunc = txdr_unsigned(notrunc);
2030 pc->pc_chownrestricted = txdr_unsigned(chownres);
2033 * These should probably be supported by VOP_PATHCONF(), but
2034 * until msdosfs is exportable (why would you want to?), the
2035 * Unix defaults should be ok.
2037 pc->pc_caseinsensitive = newnfs_false;
2038 pc->pc_casepreserving = newnfs_true;
2044 * nfsv4 lock service
2047 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2048 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2052 struct nfsstate *stp = NULL;
2053 struct nfslock *lop;
2054 struct nfslockconflict cf;
2056 u_short flags = NFSLCK_LOCK, lflags;
2057 u_int64_t offset, len;
2058 nfsv4stateid_t stateid;
2061 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2062 i = fxdr_unsigned(int, *tl++);
2064 case NFSV4LOCKT_READW:
2065 flags |= NFSLCK_BLOCKING;
2066 case NFSV4LOCKT_READ:
2067 lflags = NFSLCK_READ;
2069 case NFSV4LOCKT_WRITEW:
2070 flags |= NFSLCK_BLOCKING;
2071 case NFSV4LOCKT_WRITE:
2072 lflags = NFSLCK_WRITE;
2075 nd->nd_repstat = NFSERR_BADXDR;
2078 if (*tl++ == newnfs_true)
2079 flags |= NFSLCK_RECLAIM;
2080 offset = fxdr_hyper(tl);
2082 len = fxdr_hyper(tl);
2084 if (*tl == newnfs_true)
2085 flags |= NFSLCK_OPENTOLOCK;
2086 if (flags & NFSLCK_OPENTOLOCK) {
2087 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2088 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2089 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2090 nd->nd_repstat = NFSERR_BADXDR;
2093 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2094 M_NFSDSTATE, M_WAITOK);
2095 stp->ls_ownerlen = i;
2096 stp->ls_op = nd->nd_rp;
2097 stp->ls_seq = fxdr_unsigned(int, *tl++);
2098 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2099 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2101 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2102 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2103 clientid.lval[0] = *tl++;
2104 clientid.lval[1] = *tl++;
2105 if (nd->nd_flag & ND_IMPLIEDCLID) {
2106 if (nd->nd_clientid.qval != clientid.qval)
2107 printf("EEK! multiple clids\n");
2109 nd->nd_flag |= ND_IMPLIEDCLID;
2110 nd->nd_clientid.qval = clientid.qval;
2112 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2116 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2117 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2118 M_NFSDSTATE, M_WAITOK);
2119 stp->ls_ownerlen = 0;
2120 stp->ls_op = nd->nd_rp;
2121 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2122 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2124 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2125 stp->ls_seq = fxdr_unsigned(int, *tl);
2126 clientid.lval[0] = stp->ls_stateid.other[0];
2127 clientid.lval[1] = stp->ls_stateid.other[1];
2128 if (nd->nd_flag & ND_IMPLIEDCLID) {
2129 if (nd->nd_clientid.qval != clientid.qval)
2130 printf("EEK! multiple clids\n");
2132 nd->nd_flag |= ND_IMPLIEDCLID;
2133 nd->nd_clientid.qval = clientid.qval;
2136 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2137 M_NFSDLOCK, M_WAITOK);
2138 lop->lo_first = offset;
2139 if (len == NFS64BITSSET) {
2140 lop->lo_end = NFS64BITSSET;
2142 lop->lo_end = offset + len;
2143 if (lop->lo_end <= lop->lo_first)
2144 nd->nd_repstat = NFSERR_INVAL;
2146 lop->lo_flags = lflags;
2147 stp->ls_flags = flags;
2148 stp->ls_uid = nd->nd_cred->cr_uid;
2151 * Do basic access checking.
2153 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2154 if (vnode_vtype(vp) == VDIR)
2155 nd->nd_repstat = NFSERR_ISDIR;
2157 nd->nd_repstat = NFSERR_INVAL;
2159 if (!nd->nd_repstat) {
2160 if (lflags & NFSLCK_WRITE) {
2161 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2162 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2163 NFSACCCHK_VPISLOCKED, NULL);
2165 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2166 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2167 NFSACCCHK_VPISLOCKED, NULL);
2169 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2170 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2171 NFSACCCHK_VPISLOCKED, NULL);
2176 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2177 * seqid# gets updated. nfsrv_lockctrl() will return the value
2178 * of nd_repstat, if it gets that far.
2180 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2181 &stateid, exp, nd, p);
2183 FREE((caddr_t)lop, M_NFSDLOCK);
2185 FREE((caddr_t)stp, M_NFSDSTATE);
2186 if (!nd->nd_repstat) {
2187 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2188 *tl++ = txdr_unsigned(stateid.seqid);
2189 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2190 } else if (nd->nd_repstat == NFSERR_DENIED) {
2191 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2192 txdr_hyper(cf.cl_first, tl);
2194 if (cf.cl_end == NFS64BITSSET)
2197 len = cf.cl_end - cf.cl_first;
2198 txdr_hyper(len, tl);
2200 if (cf.cl_flags == NFSLCK_WRITE)
2201 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2203 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2204 *tl++ = stateid.other[0];
2205 *tl = stateid.other[1];
2206 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2213 free((caddr_t)stp, M_NFSDSTATE);
2218 * nfsv4 lock test service
2221 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2222 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2226 struct nfsstate *stp = NULL;
2227 struct nfslock lo, *lop = &lo;
2228 struct nfslockconflict cf;
2230 nfsv4stateid_t stateid;
2234 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2235 i = fxdr_unsigned(int, *(tl + 7));
2236 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2237 nd->nd_repstat = NFSERR_BADXDR;
2240 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2241 M_NFSDSTATE, M_WAITOK);
2242 stp->ls_ownerlen = i;
2244 stp->ls_flags = NFSLCK_TEST;
2245 stp->ls_uid = nd->nd_cred->cr_uid;
2246 i = fxdr_unsigned(int, *tl++);
2248 case NFSV4LOCKT_READW:
2249 stp->ls_flags |= NFSLCK_BLOCKING;
2250 case NFSV4LOCKT_READ:
2251 lo.lo_flags = NFSLCK_READ;
2253 case NFSV4LOCKT_WRITEW:
2254 stp->ls_flags |= NFSLCK_BLOCKING;
2255 case NFSV4LOCKT_WRITE:
2256 lo.lo_flags = NFSLCK_WRITE;
2259 nd->nd_repstat = NFSERR_BADXDR;
2262 lo.lo_first = fxdr_hyper(tl);
2264 len = fxdr_hyper(tl);
2265 if (len == NFS64BITSSET) {
2266 lo.lo_end = NFS64BITSSET;
2268 lo.lo_end = lo.lo_first + len;
2269 if (lo.lo_end <= lo.lo_first)
2270 nd->nd_repstat = NFSERR_INVAL;
2273 clientid.lval[0] = *tl++;
2274 clientid.lval[1] = *tl;
2275 if (nd->nd_flag & ND_IMPLIEDCLID) {
2276 if (nd->nd_clientid.qval != clientid.qval)
2277 printf("EEK! multiple clids\n");
2279 nd->nd_flag |= ND_IMPLIEDCLID;
2280 nd->nd_clientid.qval = clientid.qval;
2282 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2285 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2286 if (vnode_vtype(vp) == VDIR)
2287 nd->nd_repstat = NFSERR_ISDIR;
2289 nd->nd_repstat = NFSERR_INVAL;
2291 if (!nd->nd_repstat)
2292 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2293 &stateid, exp, nd, p);
2295 FREE((caddr_t)stp, M_NFSDSTATE);
2296 if (nd->nd_repstat) {
2297 if (nd->nd_repstat == NFSERR_DENIED) {
2298 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2299 txdr_hyper(cf.cl_first, tl);
2301 if (cf.cl_end == NFS64BITSSET)
2304 len = cf.cl_end - cf.cl_first;
2305 txdr_hyper(len, tl);
2307 if (cf.cl_flags == NFSLCK_WRITE)
2308 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2310 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2311 *tl++ = stp->ls_stateid.other[0];
2312 *tl = stp->ls_stateid.other[1];
2313 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2321 free((caddr_t)stp, M_NFSDSTATE);
2326 * nfsv4 unlock service
2329 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2330 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2334 struct nfsstate *stp;
2335 struct nfslock *lop;
2337 nfsv4stateid_t stateid;
2341 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2342 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2343 M_NFSDSTATE, M_WAITOK);
2344 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2345 M_NFSDLOCK, M_WAITOK);
2346 stp->ls_flags = NFSLCK_UNLOCK;
2347 lop->lo_flags = NFSLCK_UNLOCK;
2348 stp->ls_op = nd->nd_rp;
2349 i = fxdr_unsigned(int, *tl++);
2351 case NFSV4LOCKT_READW:
2352 stp->ls_flags |= NFSLCK_BLOCKING;
2353 case NFSV4LOCKT_READ:
2355 case NFSV4LOCKT_WRITEW:
2356 stp->ls_flags |= NFSLCK_BLOCKING;
2357 case NFSV4LOCKT_WRITE:
2360 nd->nd_repstat = NFSERR_BADXDR;
2361 free(stp, M_NFSDSTATE);
2362 free(lop, M_NFSDLOCK);
2365 stp->ls_ownerlen = 0;
2366 stp->ls_uid = nd->nd_cred->cr_uid;
2367 stp->ls_seq = fxdr_unsigned(int, *tl++);
2368 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2369 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2371 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2372 lop->lo_first = fxdr_hyper(tl);
2374 len = fxdr_hyper(tl);
2375 if (len == NFS64BITSSET) {
2376 lop->lo_end = NFS64BITSSET;
2378 lop->lo_end = lop->lo_first + len;
2379 if (lop->lo_end <= lop->lo_first)
2380 nd->nd_repstat = NFSERR_INVAL;
2382 clientid.lval[0] = stp->ls_stateid.other[0];
2383 clientid.lval[1] = stp->ls_stateid.other[1];
2384 if (nd->nd_flag & ND_IMPLIEDCLID) {
2385 if (nd->nd_clientid.qval != clientid.qval)
2386 printf("EEK! multiple clids\n");
2388 nd->nd_flag |= ND_IMPLIEDCLID;
2389 nd->nd_clientid.qval = clientid.qval;
2391 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2392 if (vnode_vtype(vp) == VDIR)
2393 nd->nd_repstat = NFSERR_ISDIR;
2395 nd->nd_repstat = NFSERR_INVAL;
2398 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2399 * seqid# gets incremented. nfsrv_lockctrl() will return the
2400 * value of nd_repstat, if it gets that far.
2402 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2403 &stateid, exp, nd, p);
2405 FREE((caddr_t)stp, M_NFSDSTATE);
2407 free((caddr_t)lop, M_NFSDLOCK);
2408 if (!nd->nd_repstat) {
2409 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2410 *tl++ = txdr_unsigned(stateid.seqid);
2411 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2419 * nfsv4 open service
2422 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2423 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2424 struct nfsexstuff *exp)
2428 struct nfsstate *stp = NULL;
2429 int error = 0, create, claim, exclusive_flag = 0;
2430 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2431 int how = NFSCREATE_UNCHECKED;
2432 int32_t cverf[2], tverf[2] = { 0, 0 };
2433 vnode_t vp = NULL, dirp = NULL;
2434 struct nfsvattr nva, dirfor, diraft;
2435 struct nameidata named;
2436 nfsv4stateid_t stateid, delegstateid;
2437 nfsattrbit_t attrbits;
2441 NFSACL_T *aclp = NULL;
2443 #ifdef NFS4_ACL_EXTATTR_NAME
2444 aclp = acl_alloc(M_WAITOK);
2447 NFSZERO_ATTRBIT(&attrbits);
2448 named.ni_startdir = NULL;
2449 named.ni_cnd.cn_nameiop = 0;
2450 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2451 i = fxdr_unsigned(int, *(tl + 5));
2452 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2453 nd->nd_repstat = NFSERR_BADXDR;
2455 #ifdef NFS4_ACL_EXTATTR_NAME
2460 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2461 M_NFSDSTATE, M_WAITOK);
2462 stp->ls_ownerlen = i;
2463 stp->ls_op = nd->nd_rp;
2464 stp->ls_flags = NFSLCK_OPEN;
2465 stp->ls_uid = nd->nd_cred->cr_uid;
2466 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2467 i = fxdr_unsigned(int, *tl++);
2469 case NFSV4OPEN_ACCESSREAD:
2470 stp->ls_flags |= NFSLCK_READACCESS;
2472 case NFSV4OPEN_ACCESSWRITE:
2473 stp->ls_flags |= NFSLCK_WRITEACCESS;
2475 case NFSV4OPEN_ACCESSBOTH:
2476 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2479 nd->nd_repstat = NFSERR_INVAL;
2481 i = fxdr_unsigned(int, *tl++);
2483 case NFSV4OPEN_DENYNONE:
2485 case NFSV4OPEN_DENYREAD:
2486 stp->ls_flags |= NFSLCK_READDENY;
2488 case NFSV4OPEN_DENYWRITE:
2489 stp->ls_flags |= NFSLCK_WRITEDENY;
2491 case NFSV4OPEN_DENYBOTH:
2492 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2495 nd->nd_repstat = NFSERR_INVAL;
2497 clientid.lval[0] = *tl++;
2498 clientid.lval[1] = *tl;
2499 if (nd->nd_flag & ND_IMPLIEDCLID) {
2500 if (nd->nd_clientid.qval != clientid.qval)
2501 printf("EEK! multiple clids\n");
2503 nd->nd_flag |= ND_IMPLIEDCLID;
2504 nd->nd_clientid.qval = clientid.qval;
2506 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2509 #ifdef NFS4_ACL_EXTATTR_NAME
2512 FREE((caddr_t)stp, M_NFSDSTATE);
2515 NFSVNO_ATTRINIT(&nva);
2516 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2517 create = fxdr_unsigned(int, *tl);
2518 if (!nd->nd_repstat)
2519 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p);
2520 if (create == NFSV4OPEN_CREATE) {
2523 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2524 how = fxdr_unsigned(int, *tl);
2526 case NFSCREATE_UNCHECKED:
2527 case NFSCREATE_GUARDED:
2528 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2531 #ifdef NFS4_ACL_EXTATTR_NAME
2534 FREE((caddr_t)stp, M_NFSDSTATE);
2538 * If the na_gid being set is the same as that of
2539 * the directory it is going in, clear it, since
2540 * that is what will be set by default. This allows
2541 * a user that isn't in that group to do the create.
2543 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2544 nva.na_gid == dirfor.na_gid)
2545 NFSVNO_UNSET(&nva, gid);
2546 if (!nd->nd_repstat)
2547 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2549 case NFSCREATE_EXCLUSIVE:
2550 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2555 nd->nd_repstat = NFSERR_BADXDR;
2557 #ifdef NFS4_ACL_EXTATTR_NAME
2560 FREE((caddr_t)stp, M_NFSDSTATE);
2563 } else if (create != NFSV4OPEN_NOCREATE) {
2564 nd->nd_repstat = NFSERR_BADXDR;
2566 #ifdef NFS4_ACL_EXTATTR_NAME
2569 FREE((caddr_t)stp, M_NFSDSTATE);
2574 * Now, handle the claim, which usually includes looking up a
2575 * name in the directory referenced by dp. The exception is
2576 * NFSV4OPEN_CLAIMPREVIOUS.
2578 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2579 claim = fxdr_unsigned(int, *tl);
2580 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2581 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2582 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2583 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2584 stp->ls_flags |= NFSLCK_DELEGCUR;
2585 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2586 stp->ls_flags |= NFSLCK_DELEGPREV;
2588 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2589 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2590 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2591 claim != NFSV4OPEN_CLAIMNULL)
2592 nd->nd_repstat = NFSERR_INVAL;
2593 if (nd->nd_repstat) {
2594 nd->nd_repstat = nfsrv_opencheck(clientid,
2595 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2597 #ifdef NFS4_ACL_EXTATTR_NAME
2600 FREE((caddr_t)stp, M_NFSDSTATE);
2603 if (create == NFSV4OPEN_CREATE)
2604 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2605 LOCKPARENT | LOCKLEAF | SAVESTART);
2607 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2608 LOCKLEAF | SAVESTART);
2609 nfsvno_setpathbuf(&named, &bufp, &hashp);
2610 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2613 #ifdef NFS4_ACL_EXTATTR_NAME
2616 FREE((caddr_t)stp, M_NFSDSTATE);
2617 nfsvno_relpathbuf(&named);
2620 if (!nd->nd_repstat) {
2621 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2625 nfsvno_relpathbuf(&named);
2627 if (create == NFSV4OPEN_CREATE) {
2629 case NFSCREATE_UNCHECKED:
2632 * Clear the setable attribute bits, except
2633 * for Size, if it is being truncated.
2635 NFSZERO_ATTRBIT(&attrbits);
2636 if (NFSVNO_ISSETSIZE(&nva))
2637 NFSSETBIT_ATTRBIT(&attrbits,
2641 case NFSCREATE_GUARDED:
2642 if (named.ni_vp && !nd->nd_repstat)
2643 nd->nd_repstat = EEXIST;
2645 case NFSCREATE_EXCLUSIVE:
2651 nfsvno_open(nd, &named, clientid, &stateid, stp,
2652 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2653 nd->nd_cred, p, exp, &vp);
2654 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2655 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2656 i = fxdr_unsigned(int, *tl);
2658 case NFSV4OPEN_DELEGATEREAD:
2659 stp->ls_flags |= NFSLCK_DELEGREAD;
2661 case NFSV4OPEN_DELEGATEWRITE:
2662 stp->ls_flags |= NFSLCK_DELEGWRITE;
2663 case NFSV4OPEN_DELEGATENONE:
2666 nd->nd_repstat = NFSERR_BADXDR;
2668 #ifdef NFS4_ACL_EXTATTR_NAME
2671 FREE((caddr_t)stp, M_NFSDSTATE);
2674 stp->ls_flags |= NFSLCK_RECLAIM;
2676 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
2677 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp,
2678 nd, p, nd->nd_repstat);
2680 nd->nd_repstat = NFSERR_BADXDR;
2682 #ifdef NFS4_ACL_EXTATTR_NAME
2685 FREE((caddr_t)stp, M_NFSDSTATE);
2690 * Do basic access checking.
2692 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2693 if (vnode_vtype(vp) == VDIR)
2694 nd->nd_repstat = NFSERR_ISDIR;
2695 else if (vnode_vtype(vp) == VLNK)
2696 nd->nd_repstat = NFSERR_SYMLINK;
2698 nd->nd_repstat = NFSERR_INVAL;
2700 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2701 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2702 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2703 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2704 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2705 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2707 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2708 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2709 NFSACCCHK_VPISLOCKED, NULL);
2712 if (!nd->nd_repstat) {
2713 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p);
2714 if (!nd->nd_repstat) {
2715 tverf[0] = nva.na_atime.tv_sec;
2716 tverf[1] = nva.na_atime.tv_nsec;
2719 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2720 cverf[1] != tverf[1]))
2721 nd->nd_repstat = EEXIST;
2723 * Do the open locking/delegation stuff.
2725 if (!nd->nd_repstat)
2726 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2727 &delegstateid, &rflags, exp, p, nva.na_filerev);
2730 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2731 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2732 * (ie: Leave the NFSVOPUNLOCK() about here.)
2735 NFSVOPUNLOCK(vp, 0, p);
2737 FREE((caddr_t)stp, M_NFSDSTATE);
2738 if (!nd->nd_repstat && dirp)
2739 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p);
2740 if (!nd->nd_repstat) {
2741 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2742 *tl++ = txdr_unsigned(stateid.seqid);
2743 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2744 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2745 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2746 *tl++ = newnfs_true;
2752 *tl++ = newnfs_false; /* Since dirp is not locked */
2753 txdr_hyper(dirfor.na_filerev, tl);
2755 txdr_hyper(diraft.na_filerev, tl);
2758 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2759 (void) nfsrv_putattrbit(nd, &attrbits);
2760 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2761 if (rflags & NFSV4OPEN_READDELEGATE)
2762 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2763 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2764 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2766 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2767 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2768 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2769 *tl++ = txdr_unsigned(delegstateid.seqid);
2770 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2772 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2773 if (rflags & NFSV4OPEN_RECALL)
2777 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2778 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2779 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2780 txdr_hyper(nva.na_size, tl);
2782 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2783 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2784 *tl++ = txdr_unsigned(0x0);
2785 acemask = NFSV4ACE_ALLFILESMASK;
2786 if (nva.na_mode & S_IRUSR)
2787 acemask |= NFSV4ACE_READMASK;
2788 if (nva.na_mode & S_IWUSR)
2789 acemask |= NFSV4ACE_WRITEMASK;
2790 if (nva.na_mode & S_IXUSR)
2791 acemask |= NFSV4ACE_EXECUTEMASK;
2792 *tl = txdr_unsigned(acemask);
2793 (void) nfsm_strtom(nd, "OWNER@", 6);
2801 #ifdef NFS4_ACL_EXTATTR_NAME
2807 #ifdef NFS4_ACL_EXTATTR_NAME
2811 FREE((caddr_t)stp, M_NFSDSTATE);
2816 * nfsv4 close service
2819 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2820 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2823 struct nfsstate st, *stp = &st;
2825 nfsv4stateid_t stateid;
2828 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2829 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2830 stp->ls_ownerlen = 0;
2831 stp->ls_op = nd->nd_rp;
2832 stp->ls_uid = nd->nd_cred->cr_uid;
2833 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2834 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2836 stp->ls_flags = NFSLCK_CLOSE;
2837 clientid.lval[0] = stp->ls_stateid.other[0];
2838 clientid.lval[1] = stp->ls_stateid.other[1];
2839 if (nd->nd_flag & ND_IMPLIEDCLID) {
2840 if (nd->nd_clientid.qval != clientid.qval)
2841 printf("EEK! multiple clids\n");
2843 nd->nd_flag |= ND_IMPLIEDCLID;
2844 nd->nd_clientid.qval = clientid.qval;
2846 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2848 if (!nd->nd_repstat) {
2849 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2850 *tl++ = txdr_unsigned(stateid.seqid);
2851 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2860 * nfsv4 delegpurge service
2863 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2864 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2870 if ((!nfs_rootfhset && !nfsv4root_set) ||
2871 nfsd_checkrootexp(nd)) {
2872 nd->nd_repstat = NFSERR_WRONGSEC;
2875 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2876 clientid.lval[0] = *tl++;
2877 clientid.lval[1] = *tl;
2878 if (nd->nd_flag & ND_IMPLIEDCLID) {
2879 if (nd->nd_clientid.qval != clientid.qval)
2880 printf("EEK! multiple clids\n");
2882 nd->nd_flag |= ND_IMPLIEDCLID;
2883 nd->nd_clientid.qval = clientid.qval;
2885 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2886 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2892 * nfsv4 delegreturn service
2895 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2896 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2900 nfsv4stateid_t stateid;
2903 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2904 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2905 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2906 clientid.lval[0] = stateid.other[0];
2907 clientid.lval[1] = stateid.other[1];
2908 if (nd->nd_flag & ND_IMPLIEDCLID) {
2909 if (nd->nd_clientid.qval != clientid.qval)
2910 printf("EEK! multiple clids\n");
2912 nd->nd_flag |= ND_IMPLIEDCLID;
2913 nd->nd_clientid.qval = clientid.qval;
2915 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2916 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2923 * nfsv4 get file handle service
2926 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2927 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2931 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2933 if (!nd->nd_repstat)
2934 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2939 * nfsv4 open confirm service
2942 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2943 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2946 struct nfsstate st, *stp = &st;
2948 nfsv4stateid_t stateid;
2951 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2952 stp->ls_ownerlen = 0;
2953 stp->ls_op = nd->nd_rp;
2954 stp->ls_uid = nd->nd_cred->cr_uid;
2955 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2956 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2958 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2959 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2960 stp->ls_flags = NFSLCK_CONFIRM;
2961 clientid.lval[0] = stp->ls_stateid.other[0];
2962 clientid.lval[1] = stp->ls_stateid.other[1];
2963 if (nd->nd_flag & ND_IMPLIEDCLID) {
2964 if (nd->nd_clientid.qval != clientid.qval)
2965 printf("EEK! multiple clids\n");
2967 nd->nd_flag |= ND_IMPLIEDCLID;
2968 nd->nd_clientid.qval = clientid.qval;
2970 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2971 if (!nd->nd_repstat) {
2972 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2973 *tl++ = txdr_unsigned(stateid.seqid);
2974 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2982 * nfsv4 open downgrade service
2985 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
2986 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2990 struct nfsstate st, *stp = &st;
2992 nfsv4stateid_t stateid;
2995 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
2996 stp->ls_ownerlen = 0;
2997 stp->ls_op = nd->nd_rp;
2998 stp->ls_uid = nd->nd_cred->cr_uid;
2999 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3000 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3002 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3003 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3004 i = fxdr_unsigned(int, *tl++);
3006 case NFSV4OPEN_ACCESSREAD:
3007 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3009 case NFSV4OPEN_ACCESSWRITE:
3010 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3012 case NFSV4OPEN_ACCESSBOTH:
3013 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3017 nd->nd_repstat = NFSERR_BADXDR;
3019 i = fxdr_unsigned(int, *tl);
3021 case NFSV4OPEN_DENYNONE:
3023 case NFSV4OPEN_DENYREAD:
3024 stp->ls_flags |= NFSLCK_READDENY;
3026 case NFSV4OPEN_DENYWRITE:
3027 stp->ls_flags |= NFSLCK_WRITEDENY;
3029 case NFSV4OPEN_DENYBOTH:
3030 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3033 nd->nd_repstat = NFSERR_BADXDR;
3036 clientid.lval[0] = stp->ls_stateid.other[0];
3037 clientid.lval[1] = stp->ls_stateid.other[1];
3038 if (nd->nd_flag & ND_IMPLIEDCLID) {
3039 if (nd->nd_clientid.qval != clientid.qval)
3040 printf("EEK! multiple clids\n");
3042 nd->nd_flag |= ND_IMPLIEDCLID;
3043 nd->nd_clientid.qval = clientid.qval;
3045 if (!nd->nd_repstat)
3046 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3048 if (!nd->nd_repstat) {
3049 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3050 *tl++ = txdr_unsigned(stateid.seqid);
3051 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3059 * nfsv4 renew lease service
3062 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3063 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3069 if ((!nfs_rootfhset && !nfsv4root_set) ||
3070 nfsd_checkrootexp(nd)) {
3071 nd->nd_repstat = NFSERR_WRONGSEC;
3074 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3075 clientid.lval[0] = *tl++;
3076 clientid.lval[1] = *tl;
3077 if (nd->nd_flag & ND_IMPLIEDCLID) {
3078 if (nd->nd_clientid.qval != clientid.qval)
3079 printf("EEK! multiple clids\n");
3081 nd->nd_flag |= ND_IMPLIEDCLID;
3082 nd->nd_clientid.qval = clientid.qval;
3084 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3085 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3091 * nfsv4 security info service
3094 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3095 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3099 struct nameidata named;
3100 vnode_t dirp = NULL, vp;
3102 struct nfsexstuff retnes;
3105 int error, savflag, i;
3110 * All this just to get the export flags for the name.
3112 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3113 LOCKLEAF | SAVESTART);
3114 nfsvno_setpathbuf(&named, &bufp, &hashp);
3115 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3118 nfsvno_relpathbuf(&named);
3121 if (!nd->nd_repstat) {
3122 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3125 nfsvno_relpathbuf(&named);
3131 vrele(named.ni_startdir);
3132 nfsvno_relpathbuf(&named);
3133 fh.nfsrvfh_len = NFSX_MYFH;
3135 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3136 mp = vnode_mount(vp); /* so it won't try to re-lock filesys */
3137 retnes.nes_vfslocked = exp->nes_vfslocked;
3139 savflag = nd->nd_flag;
3140 if (!nd->nd_repstat) {
3141 nfsd_fhtovp(nd, &fh, &vp, &retnes, &mp, 0, p);
3145 nd->nd_flag = savflag;
3150 * Finally have the export flags for name, so we can create
3151 * the security info.
3154 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3155 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3156 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3158 *tl = txdr_unsigned(RPCAUTH_UNIX);
3160 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3162 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3163 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3164 nfsgss_mechlist[KERBV_MECH].len);
3165 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3166 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3167 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3169 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3170 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3171 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3172 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3173 nfsgss_mechlist[KERBV_MECH].len);
3174 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3175 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3176 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3178 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3179 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3180 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3181 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3182 nfsgss_mechlist[KERBV_MECH].len);
3183 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3184 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3185 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3189 *sizp = txdr_unsigned(len);
3194 * nfsv4 set client id service
3197 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3198 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3202 int error = 0, idlen;
3203 struct nfsclient *clp = NULL;
3204 struct sockaddr_in *rad;
3205 u_char *verf, *ucp, *ucp2, addrbuf[24];
3206 nfsquad_t clientid, confirm;
3208 if ((!nfs_rootfhset && !nfsv4root_set) ||
3209 nfsd_checkrootexp(nd)) {
3210 nd->nd_repstat = NFSERR_WRONGSEC;
3213 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3214 verf = (u_char *)tl;
3215 tl += (NFSX_VERF / NFSX_UNSIGNED);
3216 i = fxdr_unsigned(int, *tl);
3217 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3218 nd->nd_repstat = NFSERR_BADXDR;
3222 if (nd->nd_flag & ND_GSS)
3223 i += nd->nd_princlen;
3224 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3225 M_NFSDCLIENT, M_WAITOK);
3226 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3227 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3228 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3229 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3230 clp->lc_req.nr_cred = NULL;
3231 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3232 clp->lc_idlen = idlen;
3233 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3236 if (nd->nd_flag & ND_GSS) {
3237 clp->lc_flags = LCL_GSS;
3238 if (nd->nd_flag & ND_GSSINTEGRITY)
3239 clp->lc_flags |= LCL_GSSINTEGRITY;
3240 else if (nd->nd_flag & ND_GSSPRIVACY)
3241 clp->lc_flags |= LCL_GSSPRIVACY;
3245 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3246 clp->lc_flags |= LCL_NAME;
3247 clp->lc_namelen = nd->nd_princlen;
3248 clp->lc_name = &clp->lc_id[idlen];
3249 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3251 clp->lc_uid = nd->nd_cred->cr_uid;
3252 clp->lc_gid = nd->nd_cred->cr_gid;
3254 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3255 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3256 error = nfsrv_getclientipaddr(nd, clp);
3259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3260 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3263 * nfsrv_setclient() does the actual work of adding it to the
3264 * client list. If there is no error, the structure has been
3265 * linked into the client list and clp should no longer be used
3266 * here. When an error is returned, it has not been linked in,
3267 * so it should be free'd.
3269 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3270 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3271 if (clp->lc_flags & LCL_TCPCALLBACK)
3272 (void) nfsm_strtom(nd, "tcp", 3);
3274 (void) nfsm_strtom(nd, "udp", 3);
3275 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3276 ucp = (u_char *)&rad->sin_addr.s_addr;
3277 ucp2 = (u_char *)&rad->sin_port;
3278 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3279 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3280 ucp2[0] & 0xff, ucp2[1] & 0xff);
3281 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3284 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3285 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3286 free((caddr_t)clp, M_NFSDCLIENT);
3288 if (!nd->nd_repstat) {
3289 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3290 *tl++ = clientid.lval[0];
3291 *tl++ = clientid.lval[1];
3292 *tl++ = confirm.lval[0];
3293 *tl = confirm.lval[1];
3298 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3299 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3300 free((caddr_t)clp, M_NFSDCLIENT);
3306 * nfsv4 set client id confirm service
3309 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3310 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3311 __unused struct nfsexstuff *exp)
3315 nfsquad_t clientid, confirm;
3317 if ((!nfs_rootfhset && !nfsv4root_set) ||
3318 nfsd_checkrootexp(nd)) {
3319 nd->nd_repstat = NFSERR_WRONGSEC;
3322 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3323 clientid.lval[0] = *tl++;
3324 clientid.lval[1] = *tl++;
3325 confirm.lval[0] = *tl++;
3326 confirm.lval[1] = *tl;
3329 * nfsrv_getclient() searches the client list for a match and
3330 * returns the appropriate NFSERR status.
3332 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3333 NULL, confirm, nd, p);
3339 * nfsv4 verify service
3342 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3343 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3345 int error = 0, ret, fhsize = NFSX_MYFH;
3346 struct nfsvattr nva;
3348 struct nfsfsinfo fs;
3351 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p);
3352 if (!nd->nd_repstat)
3353 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3354 if (!nd->nd_repstat)
3355 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3356 if (!nd->nd_repstat) {
3357 nfsvno_getfs(&fs, isdgram);
3358 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3359 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3361 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3363 nd->nd_repstat = NFSERR_SAME;
3364 else if (ret != NFSERR_NOTSAME)
3365 nd->nd_repstat = ret;
3367 nd->nd_repstat = ret;
3378 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3379 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3380 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3383 int error = 0, createdir;
3385 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3386 createdir = fxdr_unsigned(int, *tl);
3387 nd->nd_repstat = NFSERR_NOTSUPP;
3394 * nfsv4 release lock owner service
3397 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3398 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3401 struct nfsstate *stp = NULL;
3405 if ((!nfs_rootfhset && !nfsv4root_set) ||
3406 nfsd_checkrootexp(nd)) {
3407 nd->nd_repstat = NFSERR_WRONGSEC;
3410 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3411 len = fxdr_unsigned(int, *(tl + 2));
3412 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3413 nd->nd_repstat = NFSERR_BADXDR;
3416 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3417 M_NFSDSTATE, M_WAITOK);
3418 stp->ls_ownerlen = len;
3420 stp->ls_flags = NFSLCK_RELEASE;
3421 stp->ls_uid = nd->nd_cred->cr_uid;
3422 clientid.lval[0] = *tl++;
3423 clientid.lval[1] = *tl;
3424 if (nd->nd_flag & ND_IMPLIEDCLID) {
3425 if (nd->nd_clientid.qval != clientid.qval)
3426 printf("EEK! multiple clids\n");
3428 nd->nd_flag |= ND_IMPLIEDCLID;
3429 nd->nd_clientid.qval = clientid.qval;
3431 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3434 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3435 FREE((caddr_t)stp, M_NFSDSTATE);
3439 free((caddr_t)stp, M_NFSDSTATE);