2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * nfs version 2, 3 and 4 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42 * function in nfsd_port.c
43 * 3 - build the rpc reply in an mbuf list
44 * For nfsv4, these functions are called for each Op within the Compound RPC.
48 #include <fs/nfs/nfsport.h>
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset;
55 #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);
473 if (vpp != NULL && nd->nd_repstat == 0)
478 if (nd->nd_flag & ND_NFSV3)
479 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
483 if (nd->nd_repstat) {
484 if (nd->nd_flag & ND_NFSV3)
485 nfsrv_postopattr(nd, dattr_ret, &dattr);
488 if (nd->nd_flag & ND_NFSV2) {
489 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
490 nfsrv_fillattr(nd, &nva);
491 } else if (nd->nd_flag & ND_NFSV3) {
492 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
493 nfsrv_postopattr(nd, 0, &nva);
494 nfsrv_postopattr(nd, dattr_ret, &dattr);
500 * nfs readlink service
503 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
504 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
507 mbuf_t mp = NULL, mpend = NULL;
511 if (nd->nd_repstat) {
512 nfsrv_postopattr(nd, getret, &nva);
515 if (vnode_vtype(vp) != VLNK) {
516 if (nd->nd_flag & ND_NFSV2)
517 nd->nd_repstat = ENXIO;
519 nd->nd_repstat = EINVAL;
522 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
524 if (nd->nd_flag & ND_NFSV3)
525 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
527 if (nd->nd_flag & ND_NFSV3)
528 nfsrv_postopattr(nd, getret, &nva);
531 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
532 *tl = txdr_unsigned(len);
533 mbuf_setnext(nd->nd_mb, mp);
535 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
543 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
544 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
547 int error = 0, cnt, len, getret = 1, reqlen, eof = 0;
551 struct nfsstate st, *stp = &st;
552 struct nfslock lo, *lop = &lo;
553 nfsv4stateid_t stateid;
556 if (nd->nd_repstat) {
557 nfsrv_postopattr(nd, getret, &nva);
560 if (nd->nd_flag & ND_NFSV2) {
561 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
562 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
563 reqlen = fxdr_unsigned(int, *tl);
564 } else if (nd->nd_flag & ND_NFSV3) {
565 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
566 off = fxdr_hyper(tl);
568 reqlen = fxdr_unsigned(int, *tl);
570 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
571 reqlen = fxdr_unsigned(int, *(tl + 6));
573 if (reqlen > NFS_SRVMAXDATA(nd)) {
574 reqlen = NFS_SRVMAXDATA(nd);
575 } else if (reqlen < 0) {
579 if (nd->nd_flag & ND_NFSV4) {
580 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
581 lop->lo_flags = NFSLCK_READ;
582 stp->ls_ownerlen = 0;
584 stp->ls_uid = nd->nd_cred->cr_uid;
585 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
586 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
587 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
588 if (nd->nd_flag & ND_IMPLIEDCLID) {
589 if (nd->nd_clientid.qval != clientid.qval)
590 printf("EEK! multiple clids\n");
592 nd->nd_flag |= ND_IMPLIEDCLID;
593 nd->nd_clientid.qval = clientid.qval;
595 stp->ls_stateid.other[2] = *tl++;
596 off = fxdr_hyper(tl);
599 lop->lo_end = off + reqlen;
601 * Paranoia, just in case it wraps around.
603 if (lop->lo_end < off)
604 lop->lo_end = NFS64BITSSET;
606 if (vnode_vtype(vp) != VREG) {
607 if (nd->nd_flag & ND_NFSV3)
608 nd->nd_repstat = EINVAL;
610 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
613 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
615 nd->nd_repstat = getret;
616 if (!nd->nd_repstat &&
617 (nva.na_uid != nd->nd_cred->cr_uid ||
618 NFSVNO_EXSTRICTACCESS(exp))) {
619 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
621 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
623 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
624 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
625 NFSACCCHK_VPISLOCKED, NULL);
627 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
628 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
629 &stateid, exp, nd, p);
630 if (nd->nd_repstat) {
632 if (nd->nd_flag & ND_NFSV3)
633 nfsrv_postopattr(nd, getret, &nva);
636 if (off >= nva.na_size) {
639 } else if (reqlen == 0)
641 else if ((off + reqlen) > nva.na_size)
642 cnt = nva.na_size - off;
645 len = NFSM_RNDUP(cnt);
648 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
650 if (!(nd->nd_flag & ND_NFSV4)) {
651 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
653 nd->nd_repstat = getret;
655 if (nd->nd_repstat) {
659 if (nd->nd_flag & ND_NFSV3)
660 nfsrv_postopattr(nd, getret, &nva);
665 if (nd->nd_flag & ND_NFSV2) {
666 nfsrv_fillattr(nd, &nva);
667 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
669 if (nd->nd_flag & ND_NFSV3) {
670 nfsrv_postopattr(nd, getret, &nva);
671 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
672 *tl++ = txdr_unsigned(cnt);
674 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
675 if (len < reqlen || eof)
678 *tl++ = newnfs_false;
680 *tl = txdr_unsigned(cnt);
682 mbuf_setnext(nd->nd_mb, m3);
684 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
696 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
697 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
702 struct nfsvattr nva, forat;
703 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
704 int stable = NFSWRITE_FILESYNC;
706 struct nfsstate st, *stp = &st;
707 struct nfslock lo, *lop = &lo;
708 nfsv4stateid_t stateid;
711 if (nd->nd_repstat) {
712 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
715 if (nd->nd_flag & ND_NFSV2) {
716 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
717 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
719 retlen = len = fxdr_unsigned(int32_t, *tl);
720 } else if (nd->nd_flag & ND_NFSV3) {
721 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
722 off = fxdr_hyper(tl);
724 stable = fxdr_unsigned(int, *tl++);
725 retlen = len = fxdr_unsigned(int32_t, *tl);
727 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
728 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
729 lop->lo_flags = NFSLCK_WRITE;
730 stp->ls_ownerlen = 0;
732 stp->ls_uid = nd->nd_cred->cr_uid;
733 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
734 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
735 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
736 if (nd->nd_flag & ND_IMPLIEDCLID) {
737 if (nd->nd_clientid.qval != clientid.qval)
738 printf("EEK! multiple clids\n");
740 nd->nd_flag |= ND_IMPLIEDCLID;
741 nd->nd_clientid.qval = clientid.qval;
743 stp->ls_stateid.other[2] = *tl++;
744 off = fxdr_hyper(tl);
747 stable = fxdr_unsigned(int, *tl++);
748 retlen = len = fxdr_unsigned(int32_t, *tl);
749 lop->lo_end = off + len;
751 * Paranoia, just in case it wraps around, which shouldn't
752 * ever happen anyhow.
754 if (lop->lo_end < lop->lo_first)
755 lop->lo_end = NFS64BITSSET;
759 * Loop through the mbuf chain, counting how many mbufs are a
760 * part of this write operation, so the iovec size is known.
764 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
780 if (retlen > NFS_MAXDATA || retlen < 0)
781 nd->nd_repstat = EIO;
782 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
783 if (nd->nd_flag & ND_NFSV3)
784 nd->nd_repstat = EINVAL;
786 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
789 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
791 nd->nd_repstat = forat_ret;
792 if (!nd->nd_repstat &&
793 (forat.na_uid != nd->nd_cred->cr_uid ||
794 NFSVNO_EXSTRICTACCESS(exp)))
795 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
797 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
798 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
799 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
800 &stateid, exp, nd, p);
802 if (nd->nd_repstat) {
804 if (nd->nd_flag & ND_NFSV3)
805 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
810 * For NFS Version 2, it is not obvious what a write of zero length
811 * should do, but I might as well be consistent with Version 3,
812 * which is to return ok so long as there are no permission problems.
815 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
816 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
817 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
819 panic("nfsrv_write mbuf");
821 if (nd->nd_flag & ND_NFSV4)
824 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
827 nd->nd_repstat = aftat_ret;
828 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
829 if (nd->nd_flag & ND_NFSV3)
830 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
833 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
834 *tl++ = txdr_unsigned(retlen);
835 if (stable == NFSWRITE_UNSTABLE)
836 *tl++ = txdr_unsigned(stable);
838 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
840 * Actually, there is no need to txdr these fields,
841 * but it may make the values more human readable,
842 * for debugging purposes.
844 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
845 *tl = txdr_unsigned(nfsboottime.tv_usec);
846 } else if (!nd->nd_repstat)
847 nfsrv_fillattr(nd, &nva);
855 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
856 * now does a truncate to 0 length via. setattr if it already exists
857 * The core creation routine has been extracted out into nfsrv_creatsub(),
858 * so it can also be used by nfsrv_open() for V4.
861 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
862 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
864 struct nfsvattr nva, dirfor, diraft;
865 struct nfsv2_sattr *sp;
866 struct nameidata named;
868 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
869 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
871 vnode_t vp = NULL, dirp = NULL;
876 int32_t cverf[2], tverf[2] = { 0, 0 };
878 if (nd->nd_repstat) {
879 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
882 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
883 LOCKPARENT | LOCKLEAF | SAVESTART);
884 nfsvno_setpathbuf(&named, &bufp, &hashp);
885 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
888 nfsvno_relpathbuf(&named);
891 if (!nd->nd_repstat) {
892 NFSVNO_ATTRINIT(&nva);
893 if (nd->nd_flag & ND_NFSV2) {
894 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
895 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
898 NFSVNO_SETATTRVAL(&nva, type, vtyp);
899 NFSVNO_SETATTRVAL(&nva, mode,
900 nfstov_mode(sp->sa_mode));
901 switch (nva.na_type) {
903 tsize = fxdr_unsigned(int32_t, sp->sa_size);
905 NFSVNO_SETATTRVAL(&nva, size,
911 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
917 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
918 how = fxdr_unsigned(int, *tl);
920 case NFSCREATE_GUARDED:
921 case NFSCREATE_UNCHECKED:
922 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
926 case NFSCREATE_EXCLUSIVE:
927 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
933 NFSVNO_SETATTRVAL(&nva, type, VREG);
936 if (nd->nd_repstat) {
937 nfsvno_relpathbuf(&named);
938 if (nd->nd_flag & ND_NFSV3) {
939 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
941 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
948 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
950 if (nd->nd_flag & ND_NFSV2) {
954 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
958 if (nd->nd_repstat) {
959 if (nd->nd_flag & ND_NFSV3)
960 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
967 if (!(nd->nd_flag & ND_NFSV2)) {
969 case NFSCREATE_GUARDED:
971 nd->nd_repstat = EEXIST;
973 case NFSCREATE_UNCHECKED:
975 case NFSCREATE_EXCLUSIVE:
976 if (named.ni_vp == NULL)
977 NFSVNO_SETATTRVAL(&nva, mode, 0);
983 * Iff doesn't exist, create it
984 * otherwise just truncate to 0 length
985 * should I set the mode too ?
987 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
988 &exclusive_flag, cverf, rdev, p, exp);
990 if (!nd->nd_repstat) {
991 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
993 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
996 if (!nd->nd_repstat) {
997 tverf[0] = nva.na_atime.tv_sec;
998 tverf[1] = nva.na_atime.tv_nsec;
1001 if (nd->nd_flag & ND_NFSV2) {
1002 if (!nd->nd_repstat) {
1003 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1004 nfsrv_fillattr(nd, &nva);
1007 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1008 || cverf[1] != tverf[1]))
1009 nd->nd_repstat = EEXIST;
1010 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1012 if (!nd->nd_repstat) {
1013 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1014 nfsrv_postopattr(nd, 0, &nva);
1016 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1021 nfsvno_relpathbuf(&named);
1026 * nfs v3 mknod service (and v4 create)
1029 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1030 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1031 struct nfsexstuff *exp)
1033 struct nfsvattr nva, dirfor, diraft;
1035 struct nameidata named;
1036 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1037 u_int32_t major, minor;
1038 enum vtype vtyp = VNON;
1039 nfstype nfs4type = NFNON;
1040 vnode_t vp, dirp = NULL;
1041 nfsattrbit_t attrbits;
1042 char *bufp = NULL, *pathcp = NULL;
1043 u_long *hashp, cnflags;
1044 NFSACL_T *aclp = NULL;
1046 NFSVNO_ATTRINIT(&nva);
1047 cnflags = (LOCKPARENT | SAVESTART);
1048 if (nd->nd_repstat) {
1049 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1052 #ifdef NFS4_ACL_EXTATTR_NAME
1053 aclp = acl_alloc(M_WAITOK);
1058 * For V4, the creation stuff is here, Yuck!
1060 if (nd->nd_flag & ND_NFSV4) {
1061 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1062 vtyp = nfsv34tov_type(*tl);
1063 nfs4type = fxdr_unsigned(nfstype, *tl);
1066 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1070 #ifdef NFS4_ACL_EXTATTR_NAME
1078 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1079 major = fxdr_unsigned(u_int32_t, *tl++);
1080 minor = fxdr_unsigned(u_int32_t, *tl);
1081 nva.na_rdev = NFSMAKEDEV(major, minor);
1087 cnflags = (LOCKPARENT | SAVENAME);
1090 nd->nd_repstat = NFSERR_BADTYPE;
1092 #ifdef NFS4_ACL_EXTATTR_NAME
1098 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1099 nfsvno_setpathbuf(&named, &bufp, &hashp);
1100 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1103 #ifdef NFS4_ACL_EXTATTR_NAME
1106 nfsvno_relpathbuf(&named);
1108 FREE(pathcp, M_TEMP);
1111 if (!nd->nd_repstat) {
1112 if (nd->nd_flag & ND_NFSV3) {
1113 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1114 vtyp = nfsv34tov_type(*tl);
1116 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1119 #ifdef NFS4_ACL_EXTATTR_NAME
1122 nfsvno_relpathbuf(&named);
1124 FREE(pathcp, M_TEMP);
1128 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1129 (vtyp == VCHR || vtyp == VBLK)) {
1130 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1131 major = fxdr_unsigned(u_int32_t, *tl++);
1132 minor = fxdr_unsigned(u_int32_t, *tl);
1133 nva.na_rdev = NFSMAKEDEV(major, minor);
1137 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1138 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1139 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1140 dirfor.na_gid == nva.na_gid)
1141 NFSVNO_UNSET(&nva, gid);
1142 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1144 if (nd->nd_repstat) {
1146 #ifdef NFS4_ACL_EXTATTR_NAME
1149 nfsvno_relpathbuf(&named);
1151 FREE(pathcp, M_TEMP);
1152 if (nd->nd_flag & ND_NFSV3)
1153 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1159 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1160 * in va_mode, so we'll have to set a default here.
1162 if (NFSVNO_NOTSETMODE(&nva)) {
1170 named.ni_cnd.cn_flags |= WILLBEDIR;
1171 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1172 if (nd->nd_repstat) {
1174 if (nd->nd_flag & ND_NFSV3)
1175 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1179 #ifdef NFS4_ACL_EXTATTR_NAME
1182 if (nd->nd_flag & ND_NFSV3)
1183 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1188 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1190 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1192 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1193 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1195 #ifdef NFS4_ACL_EXTATTR_NAME
1199 } else if (vtyp == VLNK) {
1200 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1201 &dirfor, &diraft, &diraft_ret, &attrbits,
1202 aclp, p, exp, pathcp, pathlen);
1203 #ifdef NFS4_ACL_EXTATTR_NAME
1206 FREE(pathcp, M_TEMP);
1211 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1212 if (!nd->nd_repstat) {
1214 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1215 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1216 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1217 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1219 if (vpp != NULL && nd->nd_repstat == 0) {
1226 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1228 if (!nd->nd_repstat) {
1229 if (nd->nd_flag & ND_NFSV3) {
1230 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1231 nfsrv_postopattr(nd, 0, &nva);
1233 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1234 *tl++ = newnfs_false;
1235 txdr_hyper(dirfor.na_filerev, tl);
1237 txdr_hyper(diraft.na_filerev, tl);
1238 (void) nfsrv_putattrbit(nd, &attrbits);
1241 if (nd->nd_flag & ND_NFSV3)
1242 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1243 #ifdef NFS4_ACL_EXTATTR_NAME
1249 #ifdef NFS4_ACL_EXTATTR_NAME
1253 nfsvno_relpathbuf(&named);
1255 FREE(pathcp, M_TEMP);
1260 * nfs remove service
1263 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1264 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1266 struct nameidata named;
1268 int error, dirfor_ret = 1, diraft_ret = 1;
1269 vnode_t dirp = NULL;
1270 struct nfsvattr dirfor, diraft;
1274 if (nd->nd_repstat) {
1275 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1278 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1279 LOCKPARENT | LOCKLEAF);
1280 nfsvno_setpathbuf(&named, &bufp, &hashp);
1281 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1284 nfsvno_relpathbuf(&named);
1287 if (!nd->nd_repstat) {
1288 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1291 nfsvno_relpathbuf(&named);
1294 if (!(nd->nd_flag & ND_NFSV2)) {
1295 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1302 if (!nd->nd_repstat) {
1303 if (nd->nd_flag & ND_NFSV4) {
1304 if (vnode_vtype(named.ni_vp) == VDIR)
1305 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1306 nd->nd_cred, p, exp);
1308 nd->nd_repstat = nfsvno_removesub(&named, 1,
1309 nd->nd_cred, p, exp);
1310 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1311 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1312 nd->nd_cred, p, exp);
1314 nd->nd_repstat = nfsvno_removesub(&named, 0,
1315 nd->nd_cred, p, exp);
1318 if (!(nd->nd_flag & ND_NFSV2)) {
1320 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1324 if (nd->nd_flag & ND_NFSV3) {
1325 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1327 } else if (!nd->nd_repstat) {
1328 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1329 *tl++ = newnfs_false;
1330 txdr_hyper(dirfor.na_filerev, tl);
1332 txdr_hyper(diraft.na_filerev, tl);
1339 * nfs rename service
1342 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1343 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1344 struct nfsexstuff *toexp)
1347 int error, fdirfor_ret = 1, fdiraft_ret = 1;
1348 int tdirfor_ret = 1, tdiraft_ret = 1;
1349 struct nameidata fromnd, tond;
1350 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1351 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1352 struct nfsexstuff tnes;
1354 char *bufp, *tbufp = NULL;
1357 if (nd->nd_repstat) {
1358 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1359 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1362 if (!(nd->nd_flag & ND_NFSV2))
1363 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1364 tond.ni_cnd.cn_nameiop = 0;
1365 tond.ni_startdir = NULL;
1366 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1367 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1368 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1373 nfsvno_relpathbuf(&fromnd);
1376 if (nd->nd_flag & ND_NFSV4) {
1379 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1381 error = nfsrv_mtofh(nd, &tfh);
1384 /* todp is always NULL except NFSv4 */
1385 nfsvno_relpathbuf(&fromnd);
1388 nd->nd_cred->cr_uid = nd->nd_saveduid;
1389 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p);
1391 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1393 NFSVOPUNLOCK(tdp, 0, p);
1396 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1397 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1398 if (!nd->nd_repstat) {
1399 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1404 nfsvno_relpathbuf(&fromnd);
1405 nfsvno_relpathbuf(&tond);
1409 if (nd->nd_repstat) {
1410 if (nd->nd_flag & ND_NFSV3) {
1411 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1413 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1419 nfsvno_relpathbuf(&fromnd);
1420 nfsvno_relpathbuf(&tond);
1425 * Done parsing, now down to business.
1427 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1428 if (nd->nd_repstat) {
1429 if (nd->nd_flag & ND_NFSV3) {
1430 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1432 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1439 nfsvno_relpathbuf(&tond);
1442 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1443 tond.ni_cnd.cn_flags |= WILLBEDIR;
1444 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1445 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1446 nd->nd_flag, nd->nd_cred, p);
1448 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1451 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1457 if (nd->nd_flag & ND_NFSV3) {
1458 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1459 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1460 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1461 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1462 *tl++ = newnfs_false;
1463 txdr_hyper(fdirfor.na_filerev, tl);
1465 txdr_hyper(fdiraft.na_filerev, tl);
1467 *tl++ = newnfs_false;
1468 txdr_hyper(tdirfor.na_filerev, tl);
1470 txdr_hyper(tdiraft.na_filerev, tl);
1479 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1480 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1481 struct nfsexstuff *toexp)
1483 struct nameidata named;
1485 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1486 vnode_t dirp = NULL, dp = NULL;
1487 struct nfsvattr dirfor, diraft, at;
1488 struct nfsexstuff tnes;
1493 if (nd->nd_repstat) {
1494 nfsrv_postopattr(nd, getret, &at);
1495 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1498 NFSVOPUNLOCK(vp, 0, p);
1499 if (vnode_vtype(vp) == VDIR) {
1500 if (nd->nd_flag & ND_NFSV4)
1501 nd->nd_repstat = NFSERR_ISDIR;
1503 nd->nd_repstat = NFSERR_INVAL;
1506 } else if (vnode_vtype(vp) == VLNK) {
1507 if (nd->nd_flag & ND_NFSV2)
1508 nd->nd_repstat = NFSERR_INVAL;
1510 nd->nd_repstat = NFSERR_NOTSUPP;
1514 if (!nd->nd_repstat) {
1515 if (nd->nd_flag & ND_NFSV4) {
1519 error = nfsrv_mtofh(nd, &dfh);
1522 /* tovp is always NULL unless NFSv4 */
1525 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1528 NFSVOPUNLOCK(dp, 0, p);
1531 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1532 LOCKPARENT | SAVENAME);
1533 if (!nd->nd_repstat) {
1534 nfsvno_setpathbuf(&named, &bufp, &hashp);
1535 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1540 nfsvno_relpathbuf(&named);
1543 if (!nd->nd_repstat) {
1544 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1549 nfsvno_relpathbuf(&named);
1553 if (nd->nd_flag & ND_NFSV2) {
1557 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1561 if (!nd->nd_repstat)
1562 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1563 if (nd->nd_flag & ND_NFSV3)
1564 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1566 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1570 if (nd->nd_flag & ND_NFSV3) {
1571 nfsrv_postopattr(nd, getret, &at);
1572 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1573 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1574 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1575 *tl++ = newnfs_false;
1576 txdr_hyper(dirfor.na_filerev, tl);
1578 txdr_hyper(diraft.na_filerev, tl);
1584 * nfs symbolic link service
1587 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1588 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1589 struct nfsexstuff *exp)
1591 struct nfsvattr nva, dirfor, diraft;
1592 struct nameidata named;
1593 int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1594 vnode_t dirp = NULL;
1595 char *bufp, *pathcp = NULL;
1598 if (nd->nd_repstat) {
1599 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1604 NFSVNO_ATTRINIT(&nva);
1605 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1606 LOCKPARENT | SAVESTART);
1607 nfsvno_setpathbuf(&named, &bufp, &hashp);
1608 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1609 if (!error && !nd->nd_repstat)
1610 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1613 nfsvno_relpathbuf(&named);
1616 if (!nd->nd_repstat) {
1617 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1620 nfsvno_relpathbuf(&named);
1622 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1628 * And call nfsrvd_symlinksub() to do the common code. It will
1629 * return EBADRPC upon a parsing error, 0 otherwise.
1631 if (!nd->nd_repstat) {
1633 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1635 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1636 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1638 } else if (dirp != NULL) {
1639 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1643 FREE(pathcp, M_TEMP);
1645 if (nd->nd_flag & ND_NFSV3) {
1646 if (!nd->nd_repstat) {
1647 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1648 nfsrv_postopattr(nd, 0, &nva);
1650 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1656 * Common code for creating a symbolic link.
1659 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1660 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1661 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1662 int *diraft_retp, nfsattrbit_t *attrbitp,
1663 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1668 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1669 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1670 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1671 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1672 if (nd->nd_flag & ND_NFSV3) {
1673 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1674 if (!nd->nd_repstat)
1675 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1676 nvap, nd->nd_cred, p, 1);
1678 if (vpp != NULL && nd->nd_repstat == 0) {
1679 VOP_UNLOCK(ndp->ni_vp, 0);
1685 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1688 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1689 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1690 *tl++ = newnfs_false;
1691 txdr_hyper(dirforp->na_filerev, tl);
1693 txdr_hyper(diraftp->na_filerev, tl);
1694 (void) nfsrv_putattrbit(nd, attrbitp);
1702 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1703 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1704 struct nfsexstuff *exp)
1706 struct nfsvattr nva, dirfor, diraft;
1707 struct nameidata named;
1709 int error, dirfor_ret = 1, diraft_ret = 1;
1710 vnode_t dirp = NULL;
1714 if (nd->nd_repstat) {
1715 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1718 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1719 LOCKPARENT | SAVENAME);
1720 nfsvno_setpathbuf(&named, &bufp, &hashp);
1721 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1724 nfsvno_relpathbuf(&named);
1727 if (!nd->nd_repstat) {
1728 NFSVNO_ATTRINIT(&nva);
1729 if (nd->nd_flag & ND_NFSV3) {
1730 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1733 nfsvno_relpathbuf(&named);
1737 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1738 nva.na_mode = nfstov_mode(*tl++);
1741 if (!nd->nd_repstat) {
1742 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1745 nfsvno_relpathbuf(&named);
1747 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1751 if (nd->nd_repstat) {
1753 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1757 if (nd->nd_flag & ND_NFSV3)
1758 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1763 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1766 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1768 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1769 &diraft_ret, NULL, NULL, p, exp);
1771 if (nd->nd_flag & ND_NFSV3) {
1772 if (!nd->nd_repstat) {
1773 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1774 nfsrv_postopattr(nd, 0, &nva);
1776 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1777 } else if (!nd->nd_repstat) {
1778 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1779 nfsrv_fillattr(nd, &nva);
1784 nfsvno_relpathbuf(&named);
1789 * Code common to mkdir for V2,3 and 4.
1792 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1793 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1794 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1795 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1796 NFSPROC_T *p, struct nfsexstuff *exp)
1801 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1802 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1803 nd->nd_cred, p, exp);
1804 if (!nd->nd_repstat) {
1806 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1807 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1808 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1809 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1811 if (vpp && !nd->nd_repstat) {
1812 NFSVOPUNLOCK(vp, 0, p);
1819 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1822 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1823 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1824 *tl++ = newnfs_false;
1825 txdr_hyper(dirforp->na_filerev, tl);
1827 txdr_hyper(diraftp->na_filerev, tl);
1828 (void) nfsrv_putattrbit(nd, attrbitp);
1833 * nfs commit service
1836 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1837 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1839 struct nfsvattr bfor, aft;
1841 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1844 if (nd->nd_repstat) {
1845 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1848 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1850 * XXX At this time VOP_FSYNC() does not accept offset and byte
1851 * count parameters, so these arguments are useless (someday maybe).
1853 off = fxdr_hyper(tl);
1855 cnt = fxdr_unsigned(int, *tl);
1856 if (nd->nd_flag & ND_NFSV3)
1857 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1858 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1859 if (nd->nd_flag & ND_NFSV3) {
1860 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1861 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1864 if (!nd->nd_repstat) {
1865 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1866 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1867 *tl = txdr_unsigned(nfsboottime.tv_usec);
1876 * nfs statfs service
1879 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1880 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1889 if (nd->nd_repstat) {
1890 nfsrv_postopattr(nd, getret, &at);
1894 nd->nd_repstat = nfsvno_statfs(vp, sf);
1895 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1897 if (nd->nd_flag & ND_NFSV3)
1898 nfsrv_postopattr(nd, getret, &at);
1901 if (nd->nd_flag & ND_NFSV2) {
1902 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1903 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1904 *tl++ = txdr_unsigned(sf->f_bsize);
1905 *tl++ = txdr_unsigned(sf->f_blocks);
1906 *tl++ = txdr_unsigned(sf->f_bfree);
1907 *tl = txdr_unsigned(sf->f_bavail);
1909 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1910 tval = (u_quad_t)sf->f_blocks;
1911 tval *= (u_quad_t)sf->f_bsize;
1912 txdr_hyper(tval, tl); tl += 2;
1913 tval = (u_quad_t)sf->f_bfree;
1914 tval *= (u_quad_t)sf->f_bsize;
1915 txdr_hyper(tval, tl); tl += 2;
1916 tval = (u_quad_t)sf->f_bavail;
1917 tval *= (u_quad_t)sf->f_bsize;
1918 txdr_hyper(tval, tl); tl += 2;
1919 tval = (u_quad_t)sf->f_files;
1920 txdr_hyper(tval, tl); tl += 2;
1921 tval = (u_quad_t)sf->f_ffree;
1922 txdr_hyper(tval, tl); tl += 2;
1923 tval = (u_quad_t)sf->f_ffree;
1924 txdr_hyper(tval, tl); tl += 2;
1931 * nfs fsinfo service
1934 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1935 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1938 struct nfsfsinfo fs;
1942 if (nd->nd_repstat) {
1943 nfsrv_postopattr(nd, getret, &at);
1946 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1947 nfsvno_getfs(&fs, isdgram);
1949 nfsrv_postopattr(nd, getret, &at);
1950 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1951 *tl++ = txdr_unsigned(fs.fs_rtmax);
1952 *tl++ = txdr_unsigned(fs.fs_rtpref);
1953 *tl++ = txdr_unsigned(fs.fs_rtmult);
1954 *tl++ = txdr_unsigned(fs.fs_wtmax);
1955 *tl++ = txdr_unsigned(fs.fs_wtpref);
1956 *tl++ = txdr_unsigned(fs.fs_wtmult);
1957 *tl++ = txdr_unsigned(fs.fs_dtpref);
1958 txdr_hyper(fs.fs_maxfilesize, tl);
1960 txdr_nfsv3time(&fs.fs_timedelta, tl);
1962 *tl = txdr_unsigned(fs.fs_properties);
1967 * nfs pathconf service
1970 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
1971 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1973 struct nfsv3_pathconf *pc;
1975 register_t linkmax, namemax, chownres, notrunc;
1978 if (nd->nd_repstat) {
1979 nfsrv_postopattr(nd, getret, &at);
1982 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
1984 if (!nd->nd_repstat)
1985 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
1987 if (!nd->nd_repstat)
1988 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
1989 &chownres, nd->nd_cred, p);
1990 if (!nd->nd_repstat)
1991 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
1993 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1995 nfsrv_postopattr(nd, getret, &at);
1996 if (!nd->nd_repstat) {
1997 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
1998 pc->pc_linkmax = txdr_unsigned(linkmax);
1999 pc->pc_namemax = txdr_unsigned(namemax);
2000 pc->pc_notrunc = txdr_unsigned(notrunc);
2001 pc->pc_chownrestricted = txdr_unsigned(chownres);
2004 * These should probably be supported by VOP_PATHCONF(), but
2005 * until msdosfs is exportable (why would you want to?), the
2006 * Unix defaults should be ok.
2008 pc->pc_caseinsensitive = newnfs_false;
2009 pc->pc_casepreserving = newnfs_true;
2015 * nfsv4 lock service
2018 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2019 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2023 struct nfsstate *stp = NULL;
2024 struct nfslock *lop;
2025 struct nfslockconflict cf;
2027 u_short flags = NFSLCK_LOCK, lflags;
2028 u_int64_t offset, len;
2029 nfsv4stateid_t stateid;
2032 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2033 i = fxdr_unsigned(int, *tl++);
2035 case NFSV4LOCKT_READW:
2036 flags |= NFSLCK_BLOCKING;
2037 case NFSV4LOCKT_READ:
2038 lflags = NFSLCK_READ;
2040 case NFSV4LOCKT_WRITEW:
2041 flags |= NFSLCK_BLOCKING;
2042 case NFSV4LOCKT_WRITE:
2043 lflags = NFSLCK_WRITE;
2046 nd->nd_repstat = NFSERR_BADXDR;
2049 if (*tl++ == newnfs_true)
2050 flags |= NFSLCK_RECLAIM;
2051 offset = fxdr_hyper(tl);
2053 len = fxdr_hyper(tl);
2055 if (*tl == newnfs_true)
2056 flags |= NFSLCK_OPENTOLOCK;
2057 if (flags & NFSLCK_OPENTOLOCK) {
2058 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2059 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2060 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2061 nd->nd_repstat = NFSERR_BADXDR;
2064 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2065 M_NFSDSTATE, M_WAITOK);
2066 stp->ls_ownerlen = i;
2067 stp->ls_op = nd->nd_rp;
2068 stp->ls_seq = fxdr_unsigned(int, *tl++);
2069 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2070 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2072 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2073 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2074 clientid.lval[0] = *tl++;
2075 clientid.lval[1] = *tl++;
2076 if (nd->nd_flag & ND_IMPLIEDCLID) {
2077 if (nd->nd_clientid.qval != clientid.qval)
2078 printf("EEK! multiple clids\n");
2080 nd->nd_flag |= ND_IMPLIEDCLID;
2081 nd->nd_clientid.qval = clientid.qval;
2083 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2087 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2088 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2089 M_NFSDSTATE, M_WAITOK);
2090 stp->ls_ownerlen = 0;
2091 stp->ls_op = nd->nd_rp;
2092 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2093 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2095 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2096 stp->ls_seq = fxdr_unsigned(int, *tl);
2097 clientid.lval[0] = stp->ls_stateid.other[0];
2098 clientid.lval[1] = stp->ls_stateid.other[1];
2099 if (nd->nd_flag & ND_IMPLIEDCLID) {
2100 if (nd->nd_clientid.qval != clientid.qval)
2101 printf("EEK! multiple clids\n");
2103 nd->nd_flag |= ND_IMPLIEDCLID;
2104 nd->nd_clientid.qval = clientid.qval;
2107 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2108 M_NFSDLOCK, M_WAITOK);
2109 lop->lo_first = offset;
2110 if (len == NFS64BITSSET) {
2111 lop->lo_end = NFS64BITSSET;
2113 lop->lo_end = offset + len;
2114 if (lop->lo_end <= lop->lo_first)
2115 nd->nd_repstat = NFSERR_INVAL;
2117 lop->lo_flags = lflags;
2118 stp->ls_flags = flags;
2119 stp->ls_uid = nd->nd_cred->cr_uid;
2122 * Do basic access checking.
2124 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2125 if (vnode_vtype(vp) == VDIR)
2126 nd->nd_repstat = NFSERR_ISDIR;
2128 nd->nd_repstat = NFSERR_INVAL;
2130 if (!nd->nd_repstat) {
2131 if (lflags & NFSLCK_WRITE) {
2132 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2133 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2134 NFSACCCHK_VPISLOCKED, NULL);
2136 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2137 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2138 NFSACCCHK_VPISLOCKED, NULL);
2140 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2141 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2142 NFSACCCHK_VPISLOCKED, NULL);
2147 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2148 * seqid# gets updated. nfsrv_lockctrl() will return the value
2149 * of nd_repstat, if it gets that far.
2151 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2152 &stateid, exp, nd, p);
2154 FREE((caddr_t)lop, M_NFSDLOCK);
2156 FREE((caddr_t)stp, M_NFSDSTATE);
2157 if (!nd->nd_repstat) {
2158 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2159 *tl++ = txdr_unsigned(stateid.seqid);
2160 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2161 } else if (nd->nd_repstat == NFSERR_DENIED) {
2162 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2163 txdr_hyper(cf.cl_first, tl);
2165 if (cf.cl_end == NFS64BITSSET)
2168 len = cf.cl_end - cf.cl_first;
2169 txdr_hyper(len, tl);
2171 if (cf.cl_flags == NFSLCK_WRITE)
2172 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2174 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2175 *tl++ = stateid.other[0];
2176 *tl = stateid.other[1];
2177 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2184 free((caddr_t)stp, M_NFSDSTATE);
2189 * nfsv4 lock test service
2192 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2193 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2197 struct nfsstate *stp = NULL;
2198 struct nfslock lo, *lop = &lo;
2199 struct nfslockconflict cf;
2201 nfsv4stateid_t stateid;
2205 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2206 i = fxdr_unsigned(int, *(tl + 7));
2207 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2208 nd->nd_repstat = NFSERR_BADXDR;
2211 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2212 M_NFSDSTATE, M_WAITOK);
2213 stp->ls_ownerlen = i;
2215 stp->ls_flags = NFSLCK_TEST;
2216 stp->ls_uid = nd->nd_cred->cr_uid;
2217 i = fxdr_unsigned(int, *tl++);
2219 case NFSV4LOCKT_READW:
2220 stp->ls_flags |= NFSLCK_BLOCKING;
2221 case NFSV4LOCKT_READ:
2222 lo.lo_flags = NFSLCK_READ;
2224 case NFSV4LOCKT_WRITEW:
2225 stp->ls_flags |= NFSLCK_BLOCKING;
2226 case NFSV4LOCKT_WRITE:
2227 lo.lo_flags = NFSLCK_WRITE;
2230 nd->nd_repstat = NFSERR_BADXDR;
2233 lo.lo_first = fxdr_hyper(tl);
2235 len = fxdr_hyper(tl);
2236 if (len == NFS64BITSSET) {
2237 lo.lo_end = NFS64BITSSET;
2239 lo.lo_end = lo.lo_first + len;
2240 if (lo.lo_end <= lo.lo_first)
2241 nd->nd_repstat = NFSERR_INVAL;
2244 clientid.lval[0] = *tl++;
2245 clientid.lval[1] = *tl;
2246 if (nd->nd_flag & ND_IMPLIEDCLID) {
2247 if (nd->nd_clientid.qval != clientid.qval)
2248 printf("EEK! multiple clids\n");
2250 nd->nd_flag |= ND_IMPLIEDCLID;
2251 nd->nd_clientid.qval = clientid.qval;
2253 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2256 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2257 if (vnode_vtype(vp) == VDIR)
2258 nd->nd_repstat = NFSERR_ISDIR;
2260 nd->nd_repstat = NFSERR_INVAL;
2262 if (!nd->nd_repstat)
2263 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2264 &stateid, exp, nd, p);
2266 FREE((caddr_t)stp, M_NFSDSTATE);
2267 if (nd->nd_repstat) {
2268 if (nd->nd_repstat == NFSERR_DENIED) {
2269 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2270 txdr_hyper(cf.cl_first, tl);
2272 if (cf.cl_end == NFS64BITSSET)
2275 len = cf.cl_end - cf.cl_first;
2276 txdr_hyper(len, tl);
2278 if (cf.cl_flags == NFSLCK_WRITE)
2279 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2281 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2282 *tl++ = stp->ls_stateid.other[0];
2283 *tl = stp->ls_stateid.other[1];
2284 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2292 free((caddr_t)stp, M_NFSDSTATE);
2297 * nfsv4 unlock service
2300 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2301 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2305 struct nfsstate *stp;
2306 struct nfslock *lop;
2308 nfsv4stateid_t stateid;
2312 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2313 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2314 M_NFSDSTATE, M_WAITOK);
2315 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2316 M_NFSDLOCK, M_WAITOK);
2317 stp->ls_flags = NFSLCK_UNLOCK;
2318 lop->lo_flags = NFSLCK_UNLOCK;
2319 stp->ls_op = nd->nd_rp;
2320 i = fxdr_unsigned(int, *tl++);
2322 case NFSV4LOCKT_READW:
2323 stp->ls_flags |= NFSLCK_BLOCKING;
2324 case NFSV4LOCKT_READ:
2326 case NFSV4LOCKT_WRITEW:
2327 stp->ls_flags |= NFSLCK_BLOCKING;
2328 case NFSV4LOCKT_WRITE:
2331 nd->nd_repstat = NFSERR_BADXDR;
2332 free(stp, M_NFSDSTATE);
2333 free(lop, M_NFSDLOCK);
2336 stp->ls_ownerlen = 0;
2337 stp->ls_uid = nd->nd_cred->cr_uid;
2338 stp->ls_seq = fxdr_unsigned(int, *tl++);
2339 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2340 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2342 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2343 lop->lo_first = fxdr_hyper(tl);
2345 len = fxdr_hyper(tl);
2346 if (len == NFS64BITSSET) {
2347 lop->lo_end = NFS64BITSSET;
2349 lop->lo_end = lop->lo_first + len;
2350 if (lop->lo_end <= lop->lo_first)
2351 nd->nd_repstat = NFSERR_INVAL;
2353 clientid.lval[0] = stp->ls_stateid.other[0];
2354 clientid.lval[1] = stp->ls_stateid.other[1];
2355 if (nd->nd_flag & ND_IMPLIEDCLID) {
2356 if (nd->nd_clientid.qval != clientid.qval)
2357 printf("EEK! multiple clids\n");
2359 nd->nd_flag |= ND_IMPLIEDCLID;
2360 nd->nd_clientid.qval = clientid.qval;
2362 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2363 if (vnode_vtype(vp) == VDIR)
2364 nd->nd_repstat = NFSERR_ISDIR;
2366 nd->nd_repstat = NFSERR_INVAL;
2369 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2370 * seqid# gets incremented. nfsrv_lockctrl() will return the
2371 * value of nd_repstat, if it gets that far.
2373 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2374 &stateid, exp, nd, p);
2376 FREE((caddr_t)stp, M_NFSDSTATE);
2378 free((caddr_t)lop, M_NFSDLOCK);
2379 if (!nd->nd_repstat) {
2380 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2381 *tl++ = txdr_unsigned(stateid.seqid);
2382 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2390 * nfsv4 open service
2393 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2394 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2395 struct nfsexstuff *exp)
2399 struct nfsstate *stp = NULL;
2400 int error = 0, create, claim, exclusive_flag = 0;
2401 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2402 int how = NFSCREATE_UNCHECKED;
2403 int32_t cverf[2], tverf[2] = { 0, 0 };
2404 vnode_t vp = NULL, dirp = NULL;
2405 struct nfsvattr nva, dirfor, diraft;
2406 struct nameidata named;
2407 nfsv4stateid_t stateid, delegstateid;
2408 nfsattrbit_t attrbits;
2412 NFSACL_T *aclp = NULL;
2414 #ifdef NFS4_ACL_EXTATTR_NAME
2415 aclp = acl_alloc(M_WAITOK);
2418 NFSZERO_ATTRBIT(&attrbits);
2419 named.ni_startdir = NULL;
2420 named.ni_cnd.cn_nameiop = 0;
2421 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2422 i = fxdr_unsigned(int, *(tl + 5));
2423 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2424 nd->nd_repstat = NFSERR_BADXDR;
2426 #ifdef NFS4_ACL_EXTATTR_NAME
2431 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2432 M_NFSDSTATE, M_WAITOK);
2433 stp->ls_ownerlen = i;
2434 stp->ls_op = nd->nd_rp;
2435 stp->ls_flags = NFSLCK_OPEN;
2436 stp->ls_uid = nd->nd_cred->cr_uid;
2437 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2438 i = fxdr_unsigned(int, *tl++);
2440 case NFSV4OPEN_ACCESSREAD:
2441 stp->ls_flags |= NFSLCK_READACCESS;
2443 case NFSV4OPEN_ACCESSWRITE:
2444 stp->ls_flags |= NFSLCK_WRITEACCESS;
2446 case NFSV4OPEN_ACCESSBOTH:
2447 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2450 nd->nd_repstat = NFSERR_INVAL;
2452 i = fxdr_unsigned(int, *tl++);
2454 case NFSV4OPEN_DENYNONE:
2456 case NFSV4OPEN_DENYREAD:
2457 stp->ls_flags |= NFSLCK_READDENY;
2459 case NFSV4OPEN_DENYWRITE:
2460 stp->ls_flags |= NFSLCK_WRITEDENY;
2462 case NFSV4OPEN_DENYBOTH:
2463 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2466 nd->nd_repstat = NFSERR_INVAL;
2468 clientid.lval[0] = *tl++;
2469 clientid.lval[1] = *tl;
2470 if (nd->nd_flag & ND_IMPLIEDCLID) {
2471 if (nd->nd_clientid.qval != clientid.qval)
2472 printf("EEK! multiple clids\n");
2474 nd->nd_flag |= ND_IMPLIEDCLID;
2475 nd->nd_clientid.qval = clientid.qval;
2477 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2480 #ifdef NFS4_ACL_EXTATTR_NAME
2483 FREE((caddr_t)stp, M_NFSDSTATE);
2486 NFSVNO_ATTRINIT(&nva);
2487 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2488 create = fxdr_unsigned(int, *tl);
2489 if (!nd->nd_repstat)
2490 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2491 if (create == NFSV4OPEN_CREATE) {
2494 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2495 how = fxdr_unsigned(int, *tl);
2497 case NFSCREATE_UNCHECKED:
2498 case NFSCREATE_GUARDED:
2499 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2502 #ifdef NFS4_ACL_EXTATTR_NAME
2505 FREE((caddr_t)stp, M_NFSDSTATE);
2509 * If the na_gid being set is the same as that of
2510 * the directory it is going in, clear it, since
2511 * that is what will be set by default. This allows
2512 * a user that isn't in that group to do the create.
2514 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2515 nva.na_gid == dirfor.na_gid)
2516 NFSVNO_UNSET(&nva, gid);
2517 if (!nd->nd_repstat)
2518 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2520 case NFSCREATE_EXCLUSIVE:
2521 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2526 nd->nd_repstat = NFSERR_BADXDR;
2528 #ifdef NFS4_ACL_EXTATTR_NAME
2531 FREE((caddr_t)stp, M_NFSDSTATE);
2534 } else if (create != NFSV4OPEN_NOCREATE) {
2535 nd->nd_repstat = NFSERR_BADXDR;
2537 #ifdef NFS4_ACL_EXTATTR_NAME
2540 FREE((caddr_t)stp, M_NFSDSTATE);
2545 * Now, handle the claim, which usually includes looking up a
2546 * name in the directory referenced by dp. The exception is
2547 * NFSV4OPEN_CLAIMPREVIOUS.
2549 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2550 claim = fxdr_unsigned(int, *tl);
2551 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2552 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2553 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2554 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2555 stp->ls_flags |= NFSLCK_DELEGCUR;
2556 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2557 stp->ls_flags |= NFSLCK_DELEGPREV;
2559 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2560 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2561 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2562 claim != NFSV4OPEN_CLAIMNULL)
2563 nd->nd_repstat = NFSERR_INVAL;
2564 if (nd->nd_repstat) {
2565 nd->nd_repstat = nfsrv_opencheck(clientid,
2566 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2568 #ifdef NFS4_ACL_EXTATTR_NAME
2571 FREE((caddr_t)stp, M_NFSDSTATE);
2574 if (create == NFSV4OPEN_CREATE)
2575 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2576 LOCKPARENT | LOCKLEAF | SAVESTART);
2578 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2579 LOCKLEAF | SAVESTART);
2580 nfsvno_setpathbuf(&named, &bufp, &hashp);
2581 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2584 #ifdef NFS4_ACL_EXTATTR_NAME
2587 FREE((caddr_t)stp, M_NFSDSTATE);
2588 nfsvno_relpathbuf(&named);
2591 if (!nd->nd_repstat) {
2592 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2596 nfsvno_relpathbuf(&named);
2598 if (create == NFSV4OPEN_CREATE) {
2600 case NFSCREATE_UNCHECKED:
2603 * Clear the setable attribute bits, except
2604 * for Size, if it is being truncated.
2606 NFSZERO_ATTRBIT(&attrbits);
2607 if (NFSVNO_ISSETSIZE(&nva))
2608 NFSSETBIT_ATTRBIT(&attrbits,
2612 case NFSCREATE_GUARDED:
2613 if (named.ni_vp && !nd->nd_repstat)
2614 nd->nd_repstat = EEXIST;
2616 case NFSCREATE_EXCLUSIVE:
2622 nfsvno_open(nd, &named, clientid, &stateid, stp,
2623 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2624 nd->nd_cred, p, exp, &vp);
2625 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2626 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2627 i = fxdr_unsigned(int, *tl);
2629 case NFSV4OPEN_DELEGATEREAD:
2630 stp->ls_flags |= NFSLCK_DELEGREAD;
2632 case NFSV4OPEN_DELEGATEWRITE:
2633 stp->ls_flags |= NFSLCK_DELEGWRITE;
2634 case NFSV4OPEN_DELEGATENONE:
2637 nd->nd_repstat = NFSERR_BADXDR;
2639 #ifdef NFS4_ACL_EXTATTR_NAME
2642 FREE((caddr_t)stp, M_NFSDSTATE);
2645 stp->ls_flags |= NFSLCK_RECLAIM;
2647 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2648 if ((vp->v_iflag & VI_DOOMED) == 0)
2649 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2650 stp, vp, nd, p, nd->nd_repstat);
2652 nd->nd_repstat = NFSERR_PERM;
2654 nd->nd_repstat = NFSERR_BADXDR;
2656 #ifdef NFS4_ACL_EXTATTR_NAME
2659 FREE((caddr_t)stp, M_NFSDSTATE);
2664 * Do basic access checking.
2666 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2667 if (vnode_vtype(vp) == VDIR)
2668 nd->nd_repstat = NFSERR_ISDIR;
2669 else if (vnode_vtype(vp) == VLNK)
2670 nd->nd_repstat = NFSERR_SYMLINK;
2672 nd->nd_repstat = NFSERR_INVAL;
2674 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2675 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2676 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2677 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2678 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2679 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2681 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2682 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2683 NFSACCCHK_VPISLOCKED, NULL);
2686 if (!nd->nd_repstat) {
2687 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2688 if (!nd->nd_repstat) {
2689 tverf[0] = nva.na_atime.tv_sec;
2690 tverf[1] = nva.na_atime.tv_nsec;
2693 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2694 cverf[1] != tverf[1]))
2695 nd->nd_repstat = EEXIST;
2697 * Do the open locking/delegation stuff.
2699 if (!nd->nd_repstat)
2700 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2701 &delegstateid, &rflags, exp, p, nva.na_filerev);
2704 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2705 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2706 * (ie: Leave the NFSVOPUNLOCK() about here.)
2709 NFSVOPUNLOCK(vp, 0, p);
2711 FREE((caddr_t)stp, M_NFSDSTATE);
2712 if (!nd->nd_repstat && dirp)
2713 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2715 if (!nd->nd_repstat) {
2716 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2717 *tl++ = txdr_unsigned(stateid.seqid);
2718 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2719 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2720 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2721 *tl++ = newnfs_true;
2727 *tl++ = newnfs_false; /* Since dirp is not locked */
2728 txdr_hyper(dirfor.na_filerev, tl);
2730 txdr_hyper(diraft.na_filerev, tl);
2733 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2734 (void) nfsrv_putattrbit(nd, &attrbits);
2735 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2736 if (rflags & NFSV4OPEN_READDELEGATE)
2737 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2738 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2739 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2741 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2742 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2743 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2744 *tl++ = txdr_unsigned(delegstateid.seqid);
2745 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2747 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2748 if (rflags & NFSV4OPEN_RECALL)
2752 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2753 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2754 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2755 txdr_hyper(nva.na_size, tl);
2757 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2758 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2759 *tl++ = txdr_unsigned(0x0);
2760 acemask = NFSV4ACE_ALLFILESMASK;
2761 if (nva.na_mode & S_IRUSR)
2762 acemask |= NFSV4ACE_READMASK;
2763 if (nva.na_mode & S_IWUSR)
2764 acemask |= NFSV4ACE_WRITEMASK;
2765 if (nva.na_mode & S_IXUSR)
2766 acemask |= NFSV4ACE_EXECUTEMASK;
2767 *tl = txdr_unsigned(acemask);
2768 (void) nfsm_strtom(nd, "OWNER@", 6);
2776 #ifdef NFS4_ACL_EXTATTR_NAME
2782 #ifdef NFS4_ACL_EXTATTR_NAME
2786 FREE((caddr_t)stp, M_NFSDSTATE);
2791 * nfsv4 close service
2794 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2795 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2798 struct nfsstate st, *stp = &st;
2800 nfsv4stateid_t stateid;
2803 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2804 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2805 stp->ls_ownerlen = 0;
2806 stp->ls_op = nd->nd_rp;
2807 stp->ls_uid = nd->nd_cred->cr_uid;
2808 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2809 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2811 stp->ls_flags = NFSLCK_CLOSE;
2812 clientid.lval[0] = stp->ls_stateid.other[0];
2813 clientid.lval[1] = stp->ls_stateid.other[1];
2814 if (nd->nd_flag & ND_IMPLIEDCLID) {
2815 if (nd->nd_clientid.qval != clientid.qval)
2816 printf("EEK! multiple clids\n");
2818 nd->nd_flag |= ND_IMPLIEDCLID;
2819 nd->nd_clientid.qval = clientid.qval;
2821 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2823 if (!nd->nd_repstat) {
2824 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2825 *tl++ = txdr_unsigned(stateid.seqid);
2826 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2835 * nfsv4 delegpurge service
2838 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2839 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2845 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2846 nd->nd_repstat = NFSERR_WRONGSEC;
2849 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2850 clientid.lval[0] = *tl++;
2851 clientid.lval[1] = *tl;
2852 if (nd->nd_flag & ND_IMPLIEDCLID) {
2853 if (nd->nd_clientid.qval != clientid.qval)
2854 printf("EEK! multiple clids\n");
2856 nd->nd_flag |= ND_IMPLIEDCLID;
2857 nd->nd_clientid.qval = clientid.qval;
2859 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2860 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2866 * nfsv4 delegreturn service
2869 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2870 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2874 nfsv4stateid_t stateid;
2877 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2878 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2879 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2880 clientid.lval[0] = stateid.other[0];
2881 clientid.lval[1] = stateid.other[1];
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, &stateid, vp,
2890 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2897 * nfsv4 get file handle service
2900 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2901 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2905 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2907 if (!nd->nd_repstat)
2908 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2913 * nfsv4 open confirm service
2916 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2917 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2920 struct nfsstate st, *stp = &st;
2922 nfsv4stateid_t stateid;
2925 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2926 stp->ls_ownerlen = 0;
2927 stp->ls_op = nd->nd_rp;
2928 stp->ls_uid = nd->nd_cred->cr_uid;
2929 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2930 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2932 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2933 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2934 stp->ls_flags = NFSLCK_CONFIRM;
2935 clientid.lval[0] = stp->ls_stateid.other[0];
2936 clientid.lval[1] = stp->ls_stateid.other[1];
2937 if (nd->nd_flag & ND_IMPLIEDCLID) {
2938 if (nd->nd_clientid.qval != clientid.qval)
2939 printf("EEK! multiple clids\n");
2941 nd->nd_flag |= ND_IMPLIEDCLID;
2942 nd->nd_clientid.qval = clientid.qval;
2944 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2945 if (!nd->nd_repstat) {
2946 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2947 *tl++ = txdr_unsigned(stateid.seqid);
2948 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2956 * nfsv4 open downgrade service
2959 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
2960 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2964 struct nfsstate st, *stp = &st;
2966 nfsv4stateid_t stateid;
2969 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
2970 stp->ls_ownerlen = 0;
2971 stp->ls_op = nd->nd_rp;
2972 stp->ls_uid = nd->nd_cred->cr_uid;
2973 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2974 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2976 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2977 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2978 i = fxdr_unsigned(int, *tl++);
2980 case NFSV4OPEN_ACCESSREAD:
2981 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
2983 case NFSV4OPEN_ACCESSWRITE:
2984 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
2986 case NFSV4OPEN_ACCESSBOTH:
2987 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
2991 nd->nd_repstat = NFSERR_BADXDR;
2993 i = fxdr_unsigned(int, *tl);
2995 case NFSV4OPEN_DENYNONE:
2997 case NFSV4OPEN_DENYREAD:
2998 stp->ls_flags |= NFSLCK_READDENY;
3000 case NFSV4OPEN_DENYWRITE:
3001 stp->ls_flags |= NFSLCK_WRITEDENY;
3003 case NFSV4OPEN_DENYBOTH:
3004 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3007 nd->nd_repstat = NFSERR_BADXDR;
3010 clientid.lval[0] = stp->ls_stateid.other[0];
3011 clientid.lval[1] = stp->ls_stateid.other[1];
3012 if (nd->nd_flag & ND_IMPLIEDCLID) {
3013 if (nd->nd_clientid.qval != clientid.qval)
3014 printf("EEK! multiple clids\n");
3016 nd->nd_flag |= ND_IMPLIEDCLID;
3017 nd->nd_clientid.qval = clientid.qval;
3019 if (!nd->nd_repstat)
3020 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3022 if (!nd->nd_repstat) {
3023 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3024 *tl++ = txdr_unsigned(stateid.seqid);
3025 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3033 * nfsv4 renew lease service
3036 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3037 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3043 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3044 nd->nd_repstat = NFSERR_WRONGSEC;
3047 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3048 clientid.lval[0] = *tl++;
3049 clientid.lval[1] = *tl;
3050 if (nd->nd_flag & ND_IMPLIEDCLID) {
3051 if (nd->nd_clientid.qval != clientid.qval)
3052 printf("EEK! multiple clids\n");
3054 nd->nd_flag |= ND_IMPLIEDCLID;
3055 nd->nd_clientid.qval = clientid.qval;
3057 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3058 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3064 * nfsv4 security info service
3067 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3068 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3072 struct nameidata named;
3073 vnode_t dirp = NULL, vp;
3075 struct nfsexstuff retnes;
3077 int error, savflag, i;
3082 * All this just to get the export flags for the name.
3084 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3085 LOCKLEAF | SAVESTART);
3086 nfsvno_setpathbuf(&named, &bufp, &hashp);
3087 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3090 nfsvno_relpathbuf(&named);
3093 if (!nd->nd_repstat) {
3094 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3097 nfsvno_relpathbuf(&named);
3103 vrele(named.ni_startdir);
3104 nfsvno_relpathbuf(&named);
3105 fh.nfsrvfh_len = NFSX_MYFH;
3107 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3109 savflag = nd->nd_flag;
3110 if (!nd->nd_repstat) {
3111 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3115 nd->nd_flag = savflag;
3120 * Finally have the export flags for name, so we can create
3121 * the security info.
3124 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3125 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3126 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3127 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3128 *tl = txdr_unsigned(RPCAUTH_UNIX);
3130 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3131 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3132 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3133 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3134 nfsgss_mechlist[KERBV_MECH].len);
3135 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3136 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3137 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3139 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3140 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3141 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3142 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3143 nfsgss_mechlist[KERBV_MECH].len);
3144 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3145 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3146 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3148 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3150 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3151 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3152 nfsgss_mechlist[KERBV_MECH].len);
3153 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3154 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3155 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3159 *sizp = txdr_unsigned(len);
3164 * nfsv4 set client id service
3167 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3168 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3172 int error = 0, idlen;
3173 struct nfsclient *clp = NULL;
3174 struct sockaddr_in *rad;
3175 u_char *verf, *ucp, *ucp2, addrbuf[24];
3176 nfsquad_t clientid, confirm;
3178 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3179 nd->nd_repstat = NFSERR_WRONGSEC;
3182 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3183 verf = (u_char *)tl;
3184 tl += (NFSX_VERF / NFSX_UNSIGNED);
3185 i = fxdr_unsigned(int, *tl);
3186 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3187 nd->nd_repstat = NFSERR_BADXDR;
3191 if (nd->nd_flag & ND_GSS)
3192 i += nd->nd_princlen;
3193 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3194 M_NFSDCLIENT, M_WAITOK);
3195 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3196 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3197 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3198 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3199 clp->lc_req.nr_cred = NULL;
3200 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3201 clp->lc_idlen = idlen;
3202 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3205 if (nd->nd_flag & ND_GSS) {
3206 clp->lc_flags = LCL_GSS;
3207 if (nd->nd_flag & ND_GSSINTEGRITY)
3208 clp->lc_flags |= LCL_GSSINTEGRITY;
3209 else if (nd->nd_flag & ND_GSSPRIVACY)
3210 clp->lc_flags |= LCL_GSSPRIVACY;
3214 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3215 clp->lc_flags |= LCL_NAME;
3216 clp->lc_namelen = nd->nd_princlen;
3217 clp->lc_name = &clp->lc_id[idlen];
3218 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3220 clp->lc_uid = nd->nd_cred->cr_uid;
3221 clp->lc_gid = nd->nd_cred->cr_gid;
3223 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3224 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3225 error = nfsrv_getclientipaddr(nd, clp);
3228 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3229 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3232 * nfsrv_setclient() does the actual work of adding it to the
3233 * client list. If there is no error, the structure has been
3234 * linked into the client list and clp should no longer be used
3235 * here. When an error is returned, it has not been linked in,
3236 * so it should be free'd.
3238 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3239 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3240 if (clp->lc_flags & LCL_TCPCALLBACK)
3241 (void) nfsm_strtom(nd, "tcp", 3);
3243 (void) nfsm_strtom(nd, "udp", 3);
3244 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3245 ucp = (u_char *)&rad->sin_addr.s_addr;
3246 ucp2 = (u_char *)&rad->sin_port;
3247 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3248 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3249 ucp2[0] & 0xff, ucp2[1] & 0xff);
3250 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3253 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3254 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3255 free((caddr_t)clp, M_NFSDCLIENT);
3257 if (!nd->nd_repstat) {
3258 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3259 *tl++ = clientid.lval[0];
3260 *tl++ = clientid.lval[1];
3261 *tl++ = confirm.lval[0];
3262 *tl = confirm.lval[1];
3267 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3268 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3269 free((caddr_t)clp, M_NFSDCLIENT);
3275 * nfsv4 set client id confirm service
3278 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3279 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3280 __unused struct nfsexstuff *exp)
3284 nfsquad_t clientid, confirm;
3286 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3287 nd->nd_repstat = NFSERR_WRONGSEC;
3290 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3291 clientid.lval[0] = *tl++;
3292 clientid.lval[1] = *tl++;
3293 confirm.lval[0] = *tl++;
3294 confirm.lval[1] = *tl;
3297 * nfsrv_getclient() searches the client list for a match and
3298 * returns the appropriate NFSERR status.
3300 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3301 NULL, confirm, nd, p);
3307 * nfsv4 verify service
3310 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3311 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3313 int error = 0, ret, fhsize = NFSX_MYFH;
3314 struct nfsvattr nva;
3316 struct nfsfsinfo fs;
3319 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3320 if (!nd->nd_repstat)
3321 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3322 if (!nd->nd_repstat)
3323 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3324 if (!nd->nd_repstat) {
3325 nfsvno_getfs(&fs, isdgram);
3326 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3327 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3329 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3331 nd->nd_repstat = NFSERR_SAME;
3332 else if (ret != NFSERR_NOTSAME)
3333 nd->nd_repstat = ret;
3335 nd->nd_repstat = ret;
3346 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3347 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3348 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3351 int error = 0, createdir;
3353 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3354 createdir = fxdr_unsigned(int, *tl);
3355 nd->nd_repstat = NFSERR_NOTSUPP;
3362 * nfsv4 release lock owner service
3365 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3366 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3369 struct nfsstate *stp = NULL;
3373 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3374 nd->nd_repstat = NFSERR_WRONGSEC;
3377 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3378 len = fxdr_unsigned(int, *(tl + 2));
3379 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3380 nd->nd_repstat = NFSERR_BADXDR;
3383 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3384 M_NFSDSTATE, M_WAITOK);
3385 stp->ls_ownerlen = len;
3387 stp->ls_flags = NFSLCK_RELEASE;
3388 stp->ls_uid = nd->nd_cred->cr_uid;
3389 clientid.lval[0] = *tl++;
3390 clientid.lval[1] = *tl;
3391 if (nd->nd_flag & ND_IMPLIEDCLID) {
3392 if (nd->nd_clientid.qval != clientid.qval)
3393 printf("EEK! multiple clids\n");
3395 nd->nd_flag |= ND_IMPLIEDCLID;
3396 nd->nd_clientid.qval = clientid.qval;
3398 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3401 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3402 FREE((caddr_t)stp, M_NFSDSTATE);
3406 free((caddr_t)stp, M_NFSDSTATE);