2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * nfs version 2, 3 and 4 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42 * function in nfsd_port.c
43 * 3 - build the rpc reply in an mbuf list
44 * For nfsv4, these functions are called for each Op within the Compound RPC.
48 #include <fs/nfs/nfsport.h>
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset;
55 extern int nfsrv_enable_crossmntpt;
56 #endif /* !APPLEKEXT */
59 * This list defines the GSS mechanisms supported.
60 * (Don't ask me how you get these strings from the RFC stuff like
61 * iso(1), org(3)... but someone did it, so I don't need to know.)
63 static struct nfsgss_mechlist nfsgss_mechlist[] = {
64 { 9, "\052\206\110\206\367\022\001\002\002", 11 },
69 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
70 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
71 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
72 int *diraft_retp, nfsattrbit_t *attrbitp,
73 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
75 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
76 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
77 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
78 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
79 NFSPROC_T *p, struct nfsexstuff *exp);
82 * nfs access service (not a part of NFS V2)
85 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
86 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
89 int getret, error = 0;
91 u_int32_t testmode, nfsmode, supported = 0;
95 nfsrv_postopattr(nd, 1, &nva);
98 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
99 nfsmode = fxdr_unsigned(u_int32_t, *tl);
100 if ((nd->nd_flag & ND_NFSV4) &&
101 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
102 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
103 NFSACCESS_EXECUTE))) {
104 nd->nd_repstat = NFSERR_INVAL;
108 if (nfsmode & NFSACCESS_READ) {
109 supported |= NFSACCESS_READ;
110 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
111 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
112 nfsmode &= ~NFSACCESS_READ;
114 if (nfsmode & NFSACCESS_MODIFY) {
115 supported |= NFSACCESS_MODIFY;
116 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
117 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
118 nfsmode &= ~NFSACCESS_MODIFY;
120 if (nfsmode & NFSACCESS_EXTEND) {
121 supported |= NFSACCESS_EXTEND;
122 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
123 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
124 nfsmode &= ~NFSACCESS_EXTEND;
126 if (nfsmode & NFSACCESS_DELETE) {
127 supported |= NFSACCESS_DELETE;
128 if (vp->v_type == VDIR)
129 deletebit = VDELETE_CHILD;
132 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
133 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
134 nfsmode &= ~NFSACCESS_DELETE;
136 if (vnode_vtype(vp) == VDIR)
137 testmode = NFSACCESS_LOOKUP;
139 testmode = NFSACCESS_EXECUTE;
140 if (nfsmode & testmode) {
141 supported |= (nfsmode & testmode);
142 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
143 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
144 nfsmode &= ~testmode;
146 nfsmode &= supported;
147 if (nd->nd_flag & ND_NFSV3) {
148 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
149 nfsrv_postopattr(nd, getret, &nva);
152 if (nd->nd_flag & ND_NFSV4) {
153 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
154 *tl++ = txdr_unsigned(supported);
156 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
157 *tl = txdr_unsigned(nfsmode);
165 * nfs getattr service
168 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
169 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
173 int at_root = 0, error = 0, supports_nfsv4acls;
174 struct nfsreferral *refp;
175 nfsattrbit_t attrbits, tmpbits;
177 struct vnode *tvp = NULL;
179 uint64_t mounted_on_fileno = 0;
184 if (nd->nd_flag & ND_NFSV4) {
185 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
192 * Check for a referral.
194 refp = nfsv4root_getreferral(vp, NULL, 0);
196 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
201 if (nd->nd_repstat == 0) {
203 NFSSET_ATTRBIT(&tmpbits, &attrbits);
204 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
205 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
206 accmode |= VREAD_ACL;
208 if (NFSNONZERO_ATTRBIT(&tmpbits))
209 accmode |= VREAD_ATTRIBUTES;
211 nd->nd_repstat = nfsvno_accchk(vp, accmode,
212 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
213 NFSACCCHK_VPISLOCKED, NULL);
217 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
218 if (!nd->nd_repstat) {
219 if (nd->nd_flag & ND_NFSV4) {
220 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
221 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
223 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
224 &nva, &attrbits, nd->nd_cred, p);
225 if (nd->nd_repstat == 0) {
226 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
228 if (nfsrv_enable_crossmntpt != 0 &&
229 vp->v_type == VDIR &&
230 (vp->v_vflag & VV_ROOT) != 0 &&
232 tvp = mp->mnt_vnodecovered;
240 if ((nd->nd_repstat =
241 vn_lock(tvp, LK_SHARED)) == 0) {
242 nd->nd_repstat = VOP_GETATTR(
243 tvp, &va, nd->nd_cred);
247 if (nd->nd_repstat == 0)
248 mounted_on_fileno = (uint64_t)
253 if (nd->nd_repstat == 0)
254 nd->nd_repstat = vfs_busy(mp, 0);
256 if (nd->nd_repstat == 0) {
257 (void)nfsvno_fillattr(nd, mp, vp, &nva,
258 &fh, 0, &attrbits, nd->nd_cred, p,
259 isdgram, 1, supports_nfsv4acls,
260 at_root, mounted_on_fileno);
267 nfsrv_fillattr(nd, &nva);
277 * nfs setattr service
280 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
281 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
283 struct nfsvattr nva, nva2;
285 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
286 struct timespec guard = { 0, 0 };
287 nfsattrbit_t attrbits, retbits;
288 nfsv4stateid_t stateid;
289 NFSACL_T *aclp = NULL;
291 if (nd->nd_repstat) {
292 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
295 #ifdef NFS4_ACL_EXTATTR_NAME
296 aclp = acl_alloc(M_WAITOK);
299 NFSVNO_ATTRINIT(&nva);
300 NFSZERO_ATTRBIT(&retbits);
301 if (nd->nd_flag & ND_NFSV4) {
302 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
303 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
304 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
306 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
309 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
311 nd->nd_repstat = preat_ret;
312 if (nd->nd_flag & ND_NFSV3) {
313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
314 gcheck = fxdr_unsigned(int, *tl);
316 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
317 fxdr_nfsv3time(tl, &guard);
319 if (!nd->nd_repstat && gcheck &&
320 (nva2.na_ctime.tv_sec != guard.tv_sec ||
321 nva2.na_ctime.tv_nsec != guard.tv_nsec))
322 nd->nd_repstat = NFSERR_NOT_SYNC;
323 if (nd->nd_repstat) {
325 #ifdef NFS4_ACL_EXTATTR_NAME
328 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
331 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
332 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
335 * Now that we have all the fields, lets do it.
336 * If the size is being changed write access is required, otherwise
337 * just check for a read only file system.
339 if (!nd->nd_repstat) {
340 if (NFSVNO_NOTSETSIZE(&nva)) {
341 if (NFSVNO_EXRDONLY(exp) ||
342 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
343 nd->nd_repstat = EROFS;
345 if (vnode_vtype(vp) != VREG)
346 nd->nd_repstat = EINVAL;
347 else if (nva2.na_uid != nd->nd_cred->cr_uid ||
348 NFSVNO_EXSTRICTACCESS(exp))
349 nd->nd_repstat = nfsvno_accchk(vp,
350 VWRITE, nd->nd_cred, exp, p,
351 NFSACCCHK_NOOVERRIDE,
352 NFSACCCHK_VPISLOCKED, NULL);
355 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
356 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
357 &nva, &attrbits, exp, p);
359 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
361 * For V4, try setting the attrbutes in sets, so that the
362 * reply bitmap will be correct for an error case.
364 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
365 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
366 NFSVNO_ATTRINIT(&nva2);
367 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
368 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
369 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
371 if (!nd->nd_repstat) {
372 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
373 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
374 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
375 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
378 if (!nd->nd_repstat &&
379 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
380 NFSVNO_ATTRINIT(&nva2);
381 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
382 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
385 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
387 if (!nd->nd_repstat &&
388 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
389 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
390 NFSVNO_ATTRINIT(&nva2);
391 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
392 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
393 if (nva.na_vaflags & VA_UTIMES_NULL) {
394 nva2.na_vaflags |= VA_UTIMES_NULL;
395 NFSVNO_SETACTIVE(&nva2, vaflags);
397 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
399 if (!nd->nd_repstat) {
400 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
401 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
402 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
403 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
406 if (!nd->nd_repstat &&
407 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
408 NFSVNO_ATTRINIT(&nva2);
409 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
410 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
413 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
416 #ifdef NFS4_ACL_EXTATTR_NAME
417 if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
418 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
419 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
421 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
424 } else if (!nd->nd_repstat) {
425 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
428 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
429 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
431 nd->nd_repstat = postat_ret;
434 #ifdef NFS4_ACL_EXTATTR_NAME
437 if (nd->nd_flag & ND_NFSV3)
438 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
439 else if (nd->nd_flag & ND_NFSV4)
440 (void) nfsrv_putattrbit(nd, &retbits);
441 else if (!nd->nd_repstat)
442 nfsrv_fillattr(nd, &nva);
446 #ifdef NFS4_ACL_EXTATTR_NAME
449 if (nd->nd_flag & ND_NFSV4) {
451 * For all nd_repstat, the V4 reply includes a bitmap,
452 * even NFSERR_BADXDR, which is what this will end up
455 (void) nfsrv_putattrbit(nd, &retbits);
462 * (Also performs lookup parent for v4)
465 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
466 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
467 struct nfsexstuff *exp)
469 struct nameidata named;
470 vnode_t vp, dirp = NULL;
471 int error, dattr_ret = 1;
472 struct nfsvattr nva, dattr;
476 if (nd->nd_repstat) {
477 nfsrv_postopattr(nd, dattr_ret, &dattr);
482 * For some reason, if dp is a symlink, the error
483 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
485 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
486 nd->nd_repstat = NFSERR_SYMLINK;
491 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
492 LOCKLEAF | SAVESTART);
493 nfsvno_setpathbuf(&named, &bufp, &hashp);
494 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
497 nfsvno_relpathbuf(&named);
500 if (!nd->nd_repstat) {
501 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
504 nfsvno_relpathbuf(&named);
506 if (nd->nd_repstat) {
508 if (nd->nd_flag & ND_NFSV3)
509 dattr_ret = nfsvno_getattr(dirp, &dattr,
513 if (nd->nd_flag & ND_NFSV3)
514 nfsrv_postopattr(nd, dattr_ret, &dattr);
517 if (named.ni_startdir)
518 vrele(named.ni_startdir);
519 nfsvno_relpathbuf(&named);
521 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
522 vp->v_type != VDIR && vp->v_type != VLNK)
524 * Only allow lookup of VDIR and VLNK for traversal of
525 * non-exported volumes during NFSv4 mounting.
527 nd->nd_repstat = ENOENT;
528 if (nd->nd_repstat == 0)
529 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
530 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
531 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
532 if (vpp != NULL && nd->nd_repstat == 0)
537 if (nd->nd_flag & ND_NFSV3)
538 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
542 if (nd->nd_repstat) {
543 if (nd->nd_flag & ND_NFSV3)
544 nfsrv_postopattr(nd, dattr_ret, &dattr);
547 if (nd->nd_flag & ND_NFSV2) {
548 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
549 nfsrv_fillattr(nd, &nva);
550 } else if (nd->nd_flag & ND_NFSV3) {
551 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
552 nfsrv_postopattr(nd, 0, &nva);
553 nfsrv_postopattr(nd, dattr_ret, &dattr);
559 * nfs readlink service
562 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
563 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
566 mbuf_t mp = NULL, mpend = NULL;
570 if (nd->nd_repstat) {
571 nfsrv_postopattr(nd, getret, &nva);
574 if (vnode_vtype(vp) != VLNK) {
575 if (nd->nd_flag & ND_NFSV2)
576 nd->nd_repstat = ENXIO;
578 nd->nd_repstat = EINVAL;
581 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
583 if (nd->nd_flag & ND_NFSV3)
584 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
586 if (nd->nd_flag & ND_NFSV3)
587 nfsrv_postopattr(nd, getret, &nva);
590 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
591 *tl = txdr_unsigned(len);
592 mbuf_setnext(nd->nd_mb, mp);
594 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
602 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
603 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
606 int error = 0, cnt, len, getret = 1, reqlen, eof = 0;
610 struct nfsstate st, *stp = &st;
611 struct nfslock lo, *lop = &lo;
612 nfsv4stateid_t stateid;
615 if (nd->nd_repstat) {
616 nfsrv_postopattr(nd, getret, &nva);
619 if (nd->nd_flag & ND_NFSV2) {
620 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
621 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
622 reqlen = fxdr_unsigned(int, *tl);
623 } else if (nd->nd_flag & ND_NFSV3) {
624 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
625 off = fxdr_hyper(tl);
627 reqlen = fxdr_unsigned(int, *tl);
629 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
630 reqlen = fxdr_unsigned(int, *(tl + 6));
632 if (reqlen > NFS_SRVMAXDATA(nd)) {
633 reqlen = NFS_SRVMAXDATA(nd);
634 } else if (reqlen < 0) {
638 if (nd->nd_flag & ND_NFSV4) {
639 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
640 lop->lo_flags = NFSLCK_READ;
641 stp->ls_ownerlen = 0;
643 stp->ls_uid = nd->nd_cred->cr_uid;
644 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
645 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
646 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
647 if (nd->nd_flag & ND_IMPLIEDCLID) {
648 if (nd->nd_clientid.qval != clientid.qval)
649 printf("EEK! multiple clids\n");
651 nd->nd_flag |= ND_IMPLIEDCLID;
652 nd->nd_clientid.qval = clientid.qval;
654 stp->ls_stateid.other[2] = *tl++;
655 off = fxdr_hyper(tl);
658 lop->lo_end = off + reqlen;
660 * Paranoia, just in case it wraps around.
662 if (lop->lo_end < off)
663 lop->lo_end = NFS64BITSSET;
665 if (vnode_vtype(vp) != VREG) {
666 if (nd->nd_flag & ND_NFSV3)
667 nd->nd_repstat = EINVAL;
669 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
672 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
674 nd->nd_repstat = getret;
675 if (!nd->nd_repstat &&
676 (nva.na_uid != nd->nd_cred->cr_uid ||
677 NFSVNO_EXSTRICTACCESS(exp))) {
678 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
680 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
682 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
683 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
684 NFSACCCHK_VPISLOCKED, NULL);
686 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
687 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
688 &stateid, exp, nd, p);
689 if (nd->nd_repstat) {
691 if (nd->nd_flag & ND_NFSV3)
692 nfsrv_postopattr(nd, getret, &nva);
695 if (off >= nva.na_size) {
698 } else if (reqlen == 0)
700 else if ((off + reqlen) > nva.na_size)
701 cnt = nva.na_size - off;
704 len = NFSM_RNDUP(cnt);
707 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
709 if (!(nd->nd_flag & ND_NFSV4)) {
710 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
712 nd->nd_repstat = getret;
714 if (nd->nd_repstat) {
718 if (nd->nd_flag & ND_NFSV3)
719 nfsrv_postopattr(nd, getret, &nva);
724 if (nd->nd_flag & ND_NFSV2) {
725 nfsrv_fillattr(nd, &nva);
726 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
728 if (nd->nd_flag & ND_NFSV3) {
729 nfsrv_postopattr(nd, getret, &nva);
730 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
731 *tl++ = txdr_unsigned(cnt);
733 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
734 if (len < reqlen || eof)
737 *tl++ = newnfs_false;
739 *tl = txdr_unsigned(cnt);
741 mbuf_setnext(nd->nd_mb, m3);
743 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
755 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
756 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
761 struct nfsvattr nva, forat;
762 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
763 int stable = NFSWRITE_FILESYNC;
765 struct nfsstate st, *stp = &st;
766 struct nfslock lo, *lop = &lo;
767 nfsv4stateid_t stateid;
770 if (nd->nd_repstat) {
771 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
774 if (nd->nd_flag & ND_NFSV2) {
775 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
776 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
778 retlen = len = fxdr_unsigned(int32_t, *tl);
779 } else if (nd->nd_flag & ND_NFSV3) {
780 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
781 off = fxdr_hyper(tl);
783 stable = fxdr_unsigned(int, *tl++);
784 retlen = len = fxdr_unsigned(int32_t, *tl);
786 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
787 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
788 lop->lo_flags = NFSLCK_WRITE;
789 stp->ls_ownerlen = 0;
791 stp->ls_uid = nd->nd_cred->cr_uid;
792 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
793 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
794 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
795 if (nd->nd_flag & ND_IMPLIEDCLID) {
796 if (nd->nd_clientid.qval != clientid.qval)
797 printf("EEK! multiple clids\n");
799 nd->nd_flag |= ND_IMPLIEDCLID;
800 nd->nd_clientid.qval = clientid.qval;
802 stp->ls_stateid.other[2] = *tl++;
803 off = fxdr_hyper(tl);
806 stable = fxdr_unsigned(int, *tl++);
807 retlen = len = fxdr_unsigned(int32_t, *tl);
808 lop->lo_end = off + len;
810 * Paranoia, just in case it wraps around, which shouldn't
811 * ever happen anyhow.
813 if (lop->lo_end < lop->lo_first)
814 lop->lo_end = NFS64BITSSET;
818 * Loop through the mbuf chain, counting how many mbufs are a
819 * part of this write operation, so the iovec size is known.
823 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
839 if (retlen > NFS_MAXDATA || retlen < 0)
840 nd->nd_repstat = EIO;
841 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
842 if (nd->nd_flag & ND_NFSV3)
843 nd->nd_repstat = EINVAL;
845 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
848 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
850 nd->nd_repstat = forat_ret;
851 if (!nd->nd_repstat &&
852 (forat.na_uid != nd->nd_cred->cr_uid ||
853 NFSVNO_EXSTRICTACCESS(exp)))
854 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
856 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
857 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
858 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
859 &stateid, exp, nd, p);
861 if (nd->nd_repstat) {
863 if (nd->nd_flag & ND_NFSV3)
864 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
869 * For NFS Version 2, it is not obvious what a write of zero length
870 * should do, but I might as well be consistent with Version 3,
871 * which is to return ok so long as there are no permission problems.
874 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
875 nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
876 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
878 panic("nfsrv_write mbuf");
880 if (nd->nd_flag & ND_NFSV4)
883 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
886 nd->nd_repstat = aftat_ret;
887 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
888 if (nd->nd_flag & ND_NFSV3)
889 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
892 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
893 *tl++ = txdr_unsigned(retlen);
894 if (stable == NFSWRITE_UNSTABLE)
895 *tl++ = txdr_unsigned(stable);
897 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
899 * Actually, there is no need to txdr these fields,
900 * but it may make the values more human readable,
901 * for debugging purposes.
903 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
904 *tl = txdr_unsigned(nfsboottime.tv_usec);
905 } else if (!nd->nd_repstat)
906 nfsrv_fillattr(nd, &nva);
914 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
915 * now does a truncate to 0 length via. setattr if it already exists
916 * The core creation routine has been extracted out into nfsrv_creatsub(),
917 * so it can also be used by nfsrv_open() for V4.
920 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
921 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
923 struct nfsvattr nva, dirfor, diraft;
924 struct nfsv2_sattr *sp;
925 struct nameidata named;
927 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
928 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
930 vnode_t vp = NULL, dirp = NULL;
935 int32_t cverf[2], tverf[2] = { 0, 0 };
937 if (nd->nd_repstat) {
938 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
941 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
942 LOCKPARENT | LOCKLEAF | SAVESTART);
943 nfsvno_setpathbuf(&named, &bufp, &hashp);
944 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
947 nfsvno_relpathbuf(&named);
950 if (!nd->nd_repstat) {
951 NFSVNO_ATTRINIT(&nva);
952 if (nd->nd_flag & ND_NFSV2) {
953 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
954 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
957 NFSVNO_SETATTRVAL(&nva, type, vtyp);
958 NFSVNO_SETATTRVAL(&nva, mode,
959 nfstov_mode(sp->sa_mode));
960 switch (nva.na_type) {
962 tsize = fxdr_unsigned(int32_t, sp->sa_size);
964 NFSVNO_SETATTRVAL(&nva, size,
970 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
976 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
977 how = fxdr_unsigned(int, *tl);
979 case NFSCREATE_GUARDED:
980 case NFSCREATE_UNCHECKED:
981 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
985 case NFSCREATE_EXCLUSIVE:
986 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
992 NFSVNO_SETATTRVAL(&nva, type, VREG);
995 if (nd->nd_repstat) {
996 nfsvno_relpathbuf(&named);
997 if (nd->nd_flag & ND_NFSV3) {
998 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1000 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1007 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1009 if (nd->nd_flag & ND_NFSV2) {
1013 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1017 if (nd->nd_repstat) {
1018 if (nd->nd_flag & ND_NFSV3)
1019 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1026 if (!(nd->nd_flag & ND_NFSV2)) {
1028 case NFSCREATE_GUARDED:
1030 nd->nd_repstat = EEXIST;
1032 case NFSCREATE_UNCHECKED:
1034 case NFSCREATE_EXCLUSIVE:
1035 if (named.ni_vp == NULL)
1036 NFSVNO_SETATTRVAL(&nva, mode, 0);
1042 * Iff doesn't exist, create it
1043 * otherwise just truncate to 0 length
1044 * should I set the mode too ?
1046 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1047 &exclusive_flag, cverf, rdev, p, exp);
1049 if (!nd->nd_repstat) {
1050 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1051 if (!nd->nd_repstat)
1052 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1055 if (!nd->nd_repstat) {
1056 tverf[0] = nva.na_atime.tv_sec;
1057 tverf[1] = nva.na_atime.tv_nsec;
1060 if (nd->nd_flag & ND_NFSV2) {
1061 if (!nd->nd_repstat) {
1062 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1063 nfsrv_fillattr(nd, &nva);
1066 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1067 || cverf[1] != tverf[1]))
1068 nd->nd_repstat = EEXIST;
1069 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1071 if (!nd->nd_repstat) {
1072 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1073 nfsrv_postopattr(nd, 0, &nva);
1075 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1080 nfsvno_relpathbuf(&named);
1085 * nfs v3 mknod service (and v4 create)
1088 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1089 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1090 struct nfsexstuff *exp)
1092 struct nfsvattr nva, dirfor, diraft;
1094 struct nameidata named;
1095 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1096 u_int32_t major, minor;
1097 enum vtype vtyp = VNON;
1098 nfstype nfs4type = NFNON;
1099 vnode_t vp, dirp = NULL;
1100 nfsattrbit_t attrbits;
1101 char *bufp = NULL, *pathcp = NULL;
1102 u_long *hashp, cnflags;
1103 NFSACL_T *aclp = NULL;
1105 NFSVNO_ATTRINIT(&nva);
1106 cnflags = (LOCKPARENT | SAVESTART);
1107 if (nd->nd_repstat) {
1108 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1111 #ifdef NFS4_ACL_EXTATTR_NAME
1112 aclp = acl_alloc(M_WAITOK);
1117 * For V4, the creation stuff is here, Yuck!
1119 if (nd->nd_flag & ND_NFSV4) {
1120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1121 vtyp = nfsv34tov_type(*tl);
1122 nfs4type = fxdr_unsigned(nfstype, *tl);
1125 error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1129 #ifdef NFS4_ACL_EXTATTR_NAME
1137 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1138 major = fxdr_unsigned(u_int32_t, *tl++);
1139 minor = fxdr_unsigned(u_int32_t, *tl);
1140 nva.na_rdev = NFSMAKEDEV(major, minor);
1146 cnflags = (LOCKPARENT | SAVENAME);
1149 nd->nd_repstat = NFSERR_BADTYPE;
1151 #ifdef NFS4_ACL_EXTATTR_NAME
1157 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
1158 nfsvno_setpathbuf(&named, &bufp, &hashp);
1159 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1162 #ifdef NFS4_ACL_EXTATTR_NAME
1165 nfsvno_relpathbuf(&named);
1167 FREE(pathcp, M_TEMP);
1170 if (!nd->nd_repstat) {
1171 if (nd->nd_flag & ND_NFSV3) {
1172 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1173 vtyp = nfsv34tov_type(*tl);
1175 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1178 #ifdef NFS4_ACL_EXTATTR_NAME
1181 nfsvno_relpathbuf(&named);
1183 FREE(pathcp, M_TEMP);
1187 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1188 (vtyp == VCHR || vtyp == VBLK)) {
1189 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1190 major = fxdr_unsigned(u_int32_t, *tl++);
1191 minor = fxdr_unsigned(u_int32_t, *tl);
1192 nva.na_rdev = NFSMAKEDEV(major, minor);
1196 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1197 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1198 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1199 dirfor.na_gid == nva.na_gid)
1200 NFSVNO_UNSET(&nva, gid);
1201 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1203 if (nd->nd_repstat) {
1205 #ifdef NFS4_ACL_EXTATTR_NAME
1208 nfsvno_relpathbuf(&named);
1210 FREE(pathcp, M_TEMP);
1211 if (nd->nd_flag & ND_NFSV3)
1212 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1218 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1219 * in va_mode, so we'll have to set a default here.
1221 if (NFSVNO_NOTSETMODE(&nva)) {
1229 named.ni_cnd.cn_flags |= WILLBEDIR;
1230 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1231 if (nd->nd_repstat) {
1233 if (nd->nd_flag & ND_NFSV3)
1234 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1238 #ifdef NFS4_ACL_EXTATTR_NAME
1241 if (nd->nd_flag & ND_NFSV3)
1242 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1247 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1249 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1251 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1252 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1254 #ifdef NFS4_ACL_EXTATTR_NAME
1258 } else if (vtyp == VLNK) {
1259 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1260 &dirfor, &diraft, &diraft_ret, &attrbits,
1261 aclp, p, exp, pathcp, pathlen);
1262 #ifdef NFS4_ACL_EXTATTR_NAME
1265 FREE(pathcp, M_TEMP);
1270 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1271 if (!nd->nd_repstat) {
1273 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1274 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1275 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1276 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1278 if (vpp != NULL && nd->nd_repstat == 0) {
1285 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1287 if (!nd->nd_repstat) {
1288 if (nd->nd_flag & ND_NFSV3) {
1289 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1290 nfsrv_postopattr(nd, 0, &nva);
1292 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1293 *tl++ = newnfs_false;
1294 txdr_hyper(dirfor.na_filerev, tl);
1296 txdr_hyper(diraft.na_filerev, tl);
1297 (void) nfsrv_putattrbit(nd, &attrbits);
1300 if (nd->nd_flag & ND_NFSV3)
1301 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1302 #ifdef NFS4_ACL_EXTATTR_NAME
1308 #ifdef NFS4_ACL_EXTATTR_NAME
1312 nfsvno_relpathbuf(&named);
1314 FREE(pathcp, M_TEMP);
1319 * nfs remove service
1322 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1323 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1325 struct nameidata named;
1327 int error, dirfor_ret = 1, diraft_ret = 1;
1328 vnode_t dirp = NULL;
1329 struct nfsvattr dirfor, diraft;
1333 if (nd->nd_repstat) {
1334 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1337 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1338 LOCKPARENT | LOCKLEAF);
1339 nfsvno_setpathbuf(&named, &bufp, &hashp);
1340 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1343 nfsvno_relpathbuf(&named);
1346 if (!nd->nd_repstat) {
1347 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1350 nfsvno_relpathbuf(&named);
1353 if (!(nd->nd_flag & ND_NFSV2)) {
1354 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1361 if (!nd->nd_repstat) {
1362 if (nd->nd_flag & ND_NFSV4) {
1363 if (vnode_vtype(named.ni_vp) == VDIR)
1364 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1365 nd->nd_cred, p, exp);
1367 nd->nd_repstat = nfsvno_removesub(&named, 1,
1368 nd->nd_cred, p, exp);
1369 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1370 nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1371 nd->nd_cred, p, exp);
1373 nd->nd_repstat = nfsvno_removesub(&named, 0,
1374 nd->nd_cred, p, exp);
1377 if (!(nd->nd_flag & ND_NFSV2)) {
1379 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1383 if (nd->nd_flag & ND_NFSV3) {
1384 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1386 } else if (!nd->nd_repstat) {
1387 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1388 *tl++ = newnfs_false;
1389 txdr_hyper(dirfor.na_filerev, tl);
1391 txdr_hyper(diraft.na_filerev, tl);
1398 * nfs rename service
1401 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1402 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1403 struct nfsexstuff *toexp)
1406 int error, fdirfor_ret = 1, fdiraft_ret = 1;
1407 int tdirfor_ret = 1, tdiraft_ret = 1;
1408 struct nameidata fromnd, tond;
1409 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1410 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1411 struct nfsexstuff tnes;
1413 char *bufp, *tbufp = NULL;
1416 if (nd->nd_repstat) {
1417 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1418 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1421 if (!(nd->nd_flag & ND_NFSV2))
1422 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1423 tond.ni_cnd.cn_nameiop = 0;
1424 tond.ni_startdir = NULL;
1425 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1426 nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1427 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1432 nfsvno_relpathbuf(&fromnd);
1435 if (nd->nd_flag & ND_NFSV4) {
1438 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
1440 error = nfsrv_mtofh(nd, &tfh);
1443 /* todp is always NULL except NFSv4 */
1444 nfsvno_relpathbuf(&fromnd);
1447 nd->nd_cred->cr_uid = nd->nd_saveduid;
1448 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p);
1450 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1452 NFSVOPUNLOCK(tdp, 0);
1455 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1456 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1457 if (!nd->nd_repstat) {
1458 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1463 nfsvno_relpathbuf(&fromnd);
1464 nfsvno_relpathbuf(&tond);
1468 if (nd->nd_repstat) {
1469 if (nd->nd_flag & ND_NFSV3) {
1470 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1472 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1478 nfsvno_relpathbuf(&fromnd);
1479 nfsvno_relpathbuf(&tond);
1484 * Done parsing, now down to business.
1486 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
1487 if (nd->nd_repstat) {
1488 if (nd->nd_flag & ND_NFSV3) {
1489 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1491 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1498 nfsvno_relpathbuf(&tond);
1501 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1502 tond.ni_cnd.cn_flags |= WILLBEDIR;
1503 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1504 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1505 nd->nd_flag, nd->nd_cred, p);
1507 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1510 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1516 if (nd->nd_flag & ND_NFSV3) {
1517 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1518 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1519 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1520 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1521 *tl++ = newnfs_false;
1522 txdr_hyper(fdirfor.na_filerev, tl);
1524 txdr_hyper(fdiraft.na_filerev, tl);
1526 *tl++ = newnfs_false;
1527 txdr_hyper(tdirfor.na_filerev, tl);
1529 txdr_hyper(tdiraft.na_filerev, tl);
1538 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1539 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1540 struct nfsexstuff *toexp)
1542 struct nameidata named;
1544 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1545 vnode_t dirp = NULL, dp = NULL;
1546 struct nfsvattr dirfor, diraft, at;
1547 struct nfsexstuff tnes;
1552 if (nd->nd_repstat) {
1553 nfsrv_postopattr(nd, getret, &at);
1554 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1557 NFSVOPUNLOCK(vp, 0);
1558 if (vnode_vtype(vp) == VDIR) {
1559 if (nd->nd_flag & ND_NFSV4)
1560 nd->nd_repstat = NFSERR_ISDIR;
1562 nd->nd_repstat = NFSERR_INVAL;
1565 } else if (vnode_vtype(vp) == VLNK) {
1566 if (nd->nd_flag & ND_NFSV2)
1567 nd->nd_repstat = NFSERR_INVAL;
1569 nd->nd_repstat = NFSERR_NOTSUPP;
1573 if (!nd->nd_repstat) {
1574 if (nd->nd_flag & ND_NFSV4) {
1578 error = nfsrv_mtofh(nd, &dfh);
1581 /* tovp is always NULL unless NFSv4 */
1584 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1587 NFSVOPUNLOCK(dp, 0);
1590 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1591 LOCKPARENT | SAVENAME);
1592 if (!nd->nd_repstat) {
1593 nfsvno_setpathbuf(&named, &bufp, &hashp);
1594 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1599 nfsvno_relpathbuf(&named);
1602 if (!nd->nd_repstat) {
1603 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1608 nfsvno_relpathbuf(&named);
1612 if (nd->nd_flag & ND_NFSV2) {
1616 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1620 if (!nd->nd_repstat)
1621 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1622 if (nd->nd_flag & ND_NFSV3)
1623 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1625 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1629 if (nd->nd_flag & ND_NFSV3) {
1630 nfsrv_postopattr(nd, getret, &at);
1631 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1632 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1633 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1634 *tl++ = newnfs_false;
1635 txdr_hyper(dirfor.na_filerev, tl);
1637 txdr_hyper(diraft.na_filerev, tl);
1643 * nfs symbolic link service
1646 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1647 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1648 struct nfsexstuff *exp)
1650 struct nfsvattr nva, dirfor, diraft;
1651 struct nameidata named;
1652 int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1653 vnode_t dirp = NULL;
1654 char *bufp, *pathcp = NULL;
1657 if (nd->nd_repstat) {
1658 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1663 NFSVNO_ATTRINIT(&nva);
1664 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1665 LOCKPARENT | SAVESTART);
1666 nfsvno_setpathbuf(&named, &bufp, &hashp);
1667 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1668 if (!error && !nd->nd_repstat)
1669 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1672 nfsvno_relpathbuf(&named);
1675 if (!nd->nd_repstat) {
1676 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1679 nfsvno_relpathbuf(&named);
1681 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1687 * And call nfsrvd_symlinksub() to do the common code. It will
1688 * return EBADRPC upon a parsing error, 0 otherwise.
1690 if (!nd->nd_repstat) {
1692 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1694 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1695 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1697 } else if (dirp != NULL) {
1698 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1702 FREE(pathcp, M_TEMP);
1704 if (nd->nd_flag & ND_NFSV3) {
1705 if (!nd->nd_repstat) {
1706 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1707 nfsrv_postopattr(nd, 0, &nva);
1709 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1715 * Common code for creating a symbolic link.
1718 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1719 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1720 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1721 int *diraft_retp, nfsattrbit_t *attrbitp,
1722 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1727 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1728 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1729 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1730 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1731 if (nd->nd_flag & ND_NFSV3) {
1732 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1733 if (!nd->nd_repstat)
1734 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1735 nvap, nd->nd_cred, p, 1);
1737 if (vpp != NULL && nd->nd_repstat == 0) {
1738 VOP_UNLOCK(ndp->ni_vp, 0);
1744 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1747 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1748 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1749 *tl++ = newnfs_false;
1750 txdr_hyper(dirforp->na_filerev, tl);
1752 txdr_hyper(diraftp->na_filerev, tl);
1753 (void) nfsrv_putattrbit(nd, attrbitp);
1761 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1762 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1763 struct nfsexstuff *exp)
1765 struct nfsvattr nva, dirfor, diraft;
1766 struct nameidata named;
1768 int error, dirfor_ret = 1, diraft_ret = 1;
1769 vnode_t dirp = NULL;
1773 if (nd->nd_repstat) {
1774 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1777 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1778 LOCKPARENT | SAVENAME);
1779 nfsvno_setpathbuf(&named, &bufp, &hashp);
1780 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1783 nfsvno_relpathbuf(&named);
1786 if (!nd->nd_repstat) {
1787 NFSVNO_ATTRINIT(&nva);
1788 if (nd->nd_flag & ND_NFSV3) {
1789 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1792 nfsvno_relpathbuf(&named);
1796 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1797 nva.na_mode = nfstov_mode(*tl++);
1800 if (!nd->nd_repstat) {
1801 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1804 nfsvno_relpathbuf(&named);
1806 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1810 if (nd->nd_repstat) {
1812 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1816 if (nd->nd_flag & ND_NFSV3)
1817 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1822 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1825 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1827 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1828 &diraft_ret, NULL, NULL, p, exp);
1830 if (nd->nd_flag & ND_NFSV3) {
1831 if (!nd->nd_repstat) {
1832 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1833 nfsrv_postopattr(nd, 0, &nva);
1835 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1836 } else if (!nd->nd_repstat) {
1837 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1838 nfsrv_fillattr(nd, &nva);
1843 nfsvno_relpathbuf(&named);
1848 * Code common to mkdir for V2,3 and 4.
1851 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1852 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1853 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1854 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1855 NFSPROC_T *p, struct nfsexstuff *exp)
1860 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1861 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1862 nd->nd_cred, p, exp);
1863 if (!nd->nd_repstat) {
1865 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1866 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1867 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1868 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1870 if (vpp && !nd->nd_repstat) {
1871 NFSVOPUNLOCK(vp, 0);
1878 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1881 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1882 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1883 *tl++ = newnfs_false;
1884 txdr_hyper(dirforp->na_filerev, tl);
1886 txdr_hyper(diraftp->na_filerev, tl);
1887 (void) nfsrv_putattrbit(nd, attrbitp);
1892 * nfs commit service
1895 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1896 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1898 struct nfsvattr bfor, aft;
1900 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1903 if (nd->nd_repstat) {
1904 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1907 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1909 * XXX At this time VOP_FSYNC() does not accept offset and byte
1910 * count parameters, so these arguments are useless (someday maybe).
1912 off = fxdr_hyper(tl);
1914 cnt = fxdr_unsigned(int, *tl);
1915 if (nd->nd_flag & ND_NFSV3)
1916 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1917 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1918 if (nd->nd_flag & ND_NFSV3) {
1919 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1920 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1923 if (!nd->nd_repstat) {
1924 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1925 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1926 *tl = txdr_unsigned(nfsboottime.tv_usec);
1935 * nfs statfs service
1938 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1939 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1948 if (nd->nd_repstat) {
1949 nfsrv_postopattr(nd, getret, &at);
1953 nd->nd_repstat = nfsvno_statfs(vp, sf);
1954 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1956 if (nd->nd_flag & ND_NFSV3)
1957 nfsrv_postopattr(nd, getret, &at);
1960 if (nd->nd_flag & ND_NFSV2) {
1961 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1962 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1963 *tl++ = txdr_unsigned(sf->f_bsize);
1964 *tl++ = txdr_unsigned(sf->f_blocks);
1965 *tl++ = txdr_unsigned(sf->f_bfree);
1966 *tl = txdr_unsigned(sf->f_bavail);
1968 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1969 tval = (u_quad_t)sf->f_blocks;
1970 tval *= (u_quad_t)sf->f_bsize;
1971 txdr_hyper(tval, tl); tl += 2;
1972 tval = (u_quad_t)sf->f_bfree;
1973 tval *= (u_quad_t)sf->f_bsize;
1974 txdr_hyper(tval, tl); tl += 2;
1975 tval = (u_quad_t)sf->f_bavail;
1976 tval *= (u_quad_t)sf->f_bsize;
1977 txdr_hyper(tval, tl); tl += 2;
1978 tval = (u_quad_t)sf->f_files;
1979 txdr_hyper(tval, tl); tl += 2;
1980 tval = (u_quad_t)sf->f_ffree;
1981 txdr_hyper(tval, tl); tl += 2;
1982 tval = (u_quad_t)sf->f_ffree;
1983 txdr_hyper(tval, tl); tl += 2;
1990 * nfs fsinfo service
1993 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1994 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1997 struct nfsfsinfo fs;
2001 if (nd->nd_repstat) {
2002 nfsrv_postopattr(nd, getret, &at);
2005 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2006 nfsvno_getfs(&fs, isdgram);
2008 nfsrv_postopattr(nd, getret, &at);
2009 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2010 *tl++ = txdr_unsigned(fs.fs_rtmax);
2011 *tl++ = txdr_unsigned(fs.fs_rtpref);
2012 *tl++ = txdr_unsigned(fs.fs_rtmult);
2013 *tl++ = txdr_unsigned(fs.fs_wtmax);
2014 *tl++ = txdr_unsigned(fs.fs_wtpref);
2015 *tl++ = txdr_unsigned(fs.fs_wtmult);
2016 *tl++ = txdr_unsigned(fs.fs_dtpref);
2017 txdr_hyper(fs.fs_maxfilesize, tl);
2019 txdr_nfsv3time(&fs.fs_timedelta, tl);
2021 *tl = txdr_unsigned(fs.fs_properties);
2026 * nfs pathconf service
2029 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2030 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2032 struct nfsv3_pathconf *pc;
2034 register_t linkmax, namemax, chownres, notrunc;
2037 if (nd->nd_repstat) {
2038 nfsrv_postopattr(nd, getret, &at);
2041 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2043 if (!nd->nd_repstat)
2044 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2046 if (!nd->nd_repstat)
2047 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2048 &chownres, nd->nd_cred, p);
2049 if (!nd->nd_repstat)
2050 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2052 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2054 nfsrv_postopattr(nd, getret, &at);
2055 if (!nd->nd_repstat) {
2056 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2057 pc->pc_linkmax = txdr_unsigned(linkmax);
2058 pc->pc_namemax = txdr_unsigned(namemax);
2059 pc->pc_notrunc = txdr_unsigned(notrunc);
2060 pc->pc_chownrestricted = txdr_unsigned(chownres);
2063 * These should probably be supported by VOP_PATHCONF(), but
2064 * until msdosfs is exportable (why would you want to?), the
2065 * Unix defaults should be ok.
2067 pc->pc_caseinsensitive = newnfs_false;
2068 pc->pc_casepreserving = newnfs_true;
2074 * nfsv4 lock service
2077 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2078 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2082 struct nfsstate *stp = NULL;
2083 struct nfslock *lop;
2084 struct nfslockconflict cf;
2086 u_short flags = NFSLCK_LOCK, lflags;
2087 u_int64_t offset, len;
2088 nfsv4stateid_t stateid;
2091 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2092 i = fxdr_unsigned(int, *tl++);
2094 case NFSV4LOCKT_READW:
2095 flags |= NFSLCK_BLOCKING;
2096 case NFSV4LOCKT_READ:
2097 lflags = NFSLCK_READ;
2099 case NFSV4LOCKT_WRITEW:
2100 flags |= NFSLCK_BLOCKING;
2101 case NFSV4LOCKT_WRITE:
2102 lflags = NFSLCK_WRITE;
2105 nd->nd_repstat = NFSERR_BADXDR;
2108 if (*tl++ == newnfs_true)
2109 flags |= NFSLCK_RECLAIM;
2110 offset = fxdr_hyper(tl);
2112 len = fxdr_hyper(tl);
2114 if (*tl == newnfs_true)
2115 flags |= NFSLCK_OPENTOLOCK;
2116 if (flags & NFSLCK_OPENTOLOCK) {
2117 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2118 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2119 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2120 nd->nd_repstat = NFSERR_BADXDR;
2123 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2124 M_NFSDSTATE, M_WAITOK);
2125 stp->ls_ownerlen = i;
2126 stp->ls_op = nd->nd_rp;
2127 stp->ls_seq = fxdr_unsigned(int, *tl++);
2128 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2129 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2131 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2132 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2133 clientid.lval[0] = *tl++;
2134 clientid.lval[1] = *tl++;
2135 if (nd->nd_flag & ND_IMPLIEDCLID) {
2136 if (nd->nd_clientid.qval != clientid.qval)
2137 printf("EEK! multiple clids\n");
2139 nd->nd_flag |= ND_IMPLIEDCLID;
2140 nd->nd_clientid.qval = clientid.qval;
2142 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2146 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2147 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2148 M_NFSDSTATE, M_WAITOK);
2149 stp->ls_ownerlen = 0;
2150 stp->ls_op = nd->nd_rp;
2151 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2152 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2154 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2155 stp->ls_seq = fxdr_unsigned(int, *tl);
2156 clientid.lval[0] = stp->ls_stateid.other[0];
2157 clientid.lval[1] = stp->ls_stateid.other[1];
2158 if (nd->nd_flag & ND_IMPLIEDCLID) {
2159 if (nd->nd_clientid.qval != clientid.qval)
2160 printf("EEK! multiple clids\n");
2162 nd->nd_flag |= ND_IMPLIEDCLID;
2163 nd->nd_clientid.qval = clientid.qval;
2166 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2167 M_NFSDLOCK, M_WAITOK);
2168 lop->lo_first = offset;
2169 if (len == NFS64BITSSET) {
2170 lop->lo_end = NFS64BITSSET;
2172 lop->lo_end = offset + len;
2173 if (lop->lo_end <= lop->lo_first)
2174 nd->nd_repstat = NFSERR_INVAL;
2176 lop->lo_flags = lflags;
2177 stp->ls_flags = flags;
2178 stp->ls_uid = nd->nd_cred->cr_uid;
2181 * Do basic access checking.
2183 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2184 if (vnode_vtype(vp) == VDIR)
2185 nd->nd_repstat = NFSERR_ISDIR;
2187 nd->nd_repstat = NFSERR_INVAL;
2189 if (!nd->nd_repstat) {
2190 if (lflags & NFSLCK_WRITE) {
2191 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2192 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2193 NFSACCCHK_VPISLOCKED, NULL);
2195 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2196 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2197 NFSACCCHK_VPISLOCKED, NULL);
2199 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2200 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2201 NFSACCCHK_VPISLOCKED, NULL);
2206 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2207 * seqid# gets updated. nfsrv_lockctrl() will return the value
2208 * of nd_repstat, if it gets that far.
2210 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2211 &stateid, exp, nd, p);
2213 FREE((caddr_t)lop, M_NFSDLOCK);
2215 FREE((caddr_t)stp, M_NFSDSTATE);
2216 if (!nd->nd_repstat) {
2217 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2218 *tl++ = txdr_unsigned(stateid.seqid);
2219 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2220 } else if (nd->nd_repstat == NFSERR_DENIED) {
2221 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2222 txdr_hyper(cf.cl_first, tl);
2224 if (cf.cl_end == NFS64BITSSET)
2227 len = cf.cl_end - cf.cl_first;
2228 txdr_hyper(len, tl);
2230 if (cf.cl_flags == NFSLCK_WRITE)
2231 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2233 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2234 *tl++ = stateid.other[0];
2235 *tl = stateid.other[1];
2236 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2243 free((caddr_t)stp, M_NFSDSTATE);
2248 * nfsv4 lock test service
2251 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2252 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2256 struct nfsstate *stp = NULL;
2257 struct nfslock lo, *lop = &lo;
2258 struct nfslockconflict cf;
2260 nfsv4stateid_t stateid;
2264 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2265 i = fxdr_unsigned(int, *(tl + 7));
2266 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2267 nd->nd_repstat = NFSERR_BADXDR;
2270 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2271 M_NFSDSTATE, M_WAITOK);
2272 stp->ls_ownerlen = i;
2274 stp->ls_flags = NFSLCK_TEST;
2275 stp->ls_uid = nd->nd_cred->cr_uid;
2276 i = fxdr_unsigned(int, *tl++);
2278 case NFSV4LOCKT_READW:
2279 stp->ls_flags |= NFSLCK_BLOCKING;
2280 case NFSV4LOCKT_READ:
2281 lo.lo_flags = NFSLCK_READ;
2283 case NFSV4LOCKT_WRITEW:
2284 stp->ls_flags |= NFSLCK_BLOCKING;
2285 case NFSV4LOCKT_WRITE:
2286 lo.lo_flags = NFSLCK_WRITE;
2289 nd->nd_repstat = NFSERR_BADXDR;
2292 lo.lo_first = fxdr_hyper(tl);
2294 len = fxdr_hyper(tl);
2295 if (len == NFS64BITSSET) {
2296 lo.lo_end = NFS64BITSSET;
2298 lo.lo_end = lo.lo_first + len;
2299 if (lo.lo_end <= lo.lo_first)
2300 nd->nd_repstat = NFSERR_INVAL;
2303 clientid.lval[0] = *tl++;
2304 clientid.lval[1] = *tl;
2305 if (nd->nd_flag & ND_IMPLIEDCLID) {
2306 if (nd->nd_clientid.qval != clientid.qval)
2307 printf("EEK! multiple clids\n");
2309 nd->nd_flag |= ND_IMPLIEDCLID;
2310 nd->nd_clientid.qval = clientid.qval;
2312 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2315 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2316 if (vnode_vtype(vp) == VDIR)
2317 nd->nd_repstat = NFSERR_ISDIR;
2319 nd->nd_repstat = NFSERR_INVAL;
2321 if (!nd->nd_repstat)
2322 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2323 &stateid, exp, nd, p);
2325 FREE((caddr_t)stp, M_NFSDSTATE);
2326 if (nd->nd_repstat) {
2327 if (nd->nd_repstat == NFSERR_DENIED) {
2328 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2329 txdr_hyper(cf.cl_first, tl);
2331 if (cf.cl_end == NFS64BITSSET)
2334 len = cf.cl_end - cf.cl_first;
2335 txdr_hyper(len, tl);
2337 if (cf.cl_flags == NFSLCK_WRITE)
2338 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2340 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2341 *tl++ = stp->ls_stateid.other[0];
2342 *tl = stp->ls_stateid.other[1];
2343 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2351 free((caddr_t)stp, M_NFSDSTATE);
2356 * nfsv4 unlock service
2359 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2360 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2364 struct nfsstate *stp;
2365 struct nfslock *lop;
2367 nfsv4stateid_t stateid;
2371 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2372 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2373 M_NFSDSTATE, M_WAITOK);
2374 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2375 M_NFSDLOCK, M_WAITOK);
2376 stp->ls_flags = NFSLCK_UNLOCK;
2377 lop->lo_flags = NFSLCK_UNLOCK;
2378 stp->ls_op = nd->nd_rp;
2379 i = fxdr_unsigned(int, *tl++);
2381 case NFSV4LOCKT_READW:
2382 stp->ls_flags |= NFSLCK_BLOCKING;
2383 case NFSV4LOCKT_READ:
2385 case NFSV4LOCKT_WRITEW:
2386 stp->ls_flags |= NFSLCK_BLOCKING;
2387 case NFSV4LOCKT_WRITE:
2390 nd->nd_repstat = NFSERR_BADXDR;
2391 free(stp, M_NFSDSTATE);
2392 free(lop, M_NFSDLOCK);
2395 stp->ls_ownerlen = 0;
2396 stp->ls_uid = nd->nd_cred->cr_uid;
2397 stp->ls_seq = fxdr_unsigned(int, *tl++);
2398 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2399 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2401 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2402 lop->lo_first = fxdr_hyper(tl);
2404 len = fxdr_hyper(tl);
2405 if (len == NFS64BITSSET) {
2406 lop->lo_end = NFS64BITSSET;
2408 lop->lo_end = lop->lo_first + len;
2409 if (lop->lo_end <= lop->lo_first)
2410 nd->nd_repstat = NFSERR_INVAL;
2412 clientid.lval[0] = stp->ls_stateid.other[0];
2413 clientid.lval[1] = stp->ls_stateid.other[1];
2414 if (nd->nd_flag & ND_IMPLIEDCLID) {
2415 if (nd->nd_clientid.qval != clientid.qval)
2416 printf("EEK! multiple clids\n");
2418 nd->nd_flag |= ND_IMPLIEDCLID;
2419 nd->nd_clientid.qval = clientid.qval;
2421 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2422 if (vnode_vtype(vp) == VDIR)
2423 nd->nd_repstat = NFSERR_ISDIR;
2425 nd->nd_repstat = NFSERR_INVAL;
2428 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2429 * seqid# gets incremented. nfsrv_lockctrl() will return the
2430 * value of nd_repstat, if it gets that far.
2432 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2433 &stateid, exp, nd, p);
2435 FREE((caddr_t)stp, M_NFSDSTATE);
2437 free((caddr_t)lop, M_NFSDLOCK);
2438 if (!nd->nd_repstat) {
2439 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2440 *tl++ = txdr_unsigned(stateid.seqid);
2441 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2449 * nfsv4 open service
2452 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2453 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2454 struct nfsexstuff *exp)
2458 struct nfsstate *stp = NULL;
2459 int error = 0, create, claim, exclusive_flag = 0;
2460 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2461 int how = NFSCREATE_UNCHECKED;
2462 int32_t cverf[2], tverf[2] = { 0, 0 };
2463 vnode_t vp = NULL, dirp = NULL;
2464 struct nfsvattr nva, dirfor, diraft;
2465 struct nameidata named;
2466 nfsv4stateid_t stateid, delegstateid;
2467 nfsattrbit_t attrbits;
2471 NFSACL_T *aclp = NULL;
2473 #ifdef NFS4_ACL_EXTATTR_NAME
2474 aclp = acl_alloc(M_WAITOK);
2477 NFSZERO_ATTRBIT(&attrbits);
2478 named.ni_startdir = NULL;
2479 named.ni_cnd.cn_nameiop = 0;
2480 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2481 i = fxdr_unsigned(int, *(tl + 5));
2482 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2483 nd->nd_repstat = NFSERR_BADXDR;
2485 #ifdef NFS4_ACL_EXTATTR_NAME
2490 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2491 M_NFSDSTATE, M_WAITOK);
2492 stp->ls_ownerlen = i;
2493 stp->ls_op = nd->nd_rp;
2494 stp->ls_flags = NFSLCK_OPEN;
2495 stp->ls_uid = nd->nd_cred->cr_uid;
2496 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2497 i = fxdr_unsigned(int, *tl++);
2499 case NFSV4OPEN_ACCESSREAD:
2500 stp->ls_flags |= NFSLCK_READACCESS;
2502 case NFSV4OPEN_ACCESSWRITE:
2503 stp->ls_flags |= NFSLCK_WRITEACCESS;
2505 case NFSV4OPEN_ACCESSBOTH:
2506 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2509 nd->nd_repstat = NFSERR_INVAL;
2511 i = fxdr_unsigned(int, *tl++);
2513 case NFSV4OPEN_DENYNONE:
2515 case NFSV4OPEN_DENYREAD:
2516 stp->ls_flags |= NFSLCK_READDENY;
2518 case NFSV4OPEN_DENYWRITE:
2519 stp->ls_flags |= NFSLCK_WRITEDENY;
2521 case NFSV4OPEN_DENYBOTH:
2522 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2525 nd->nd_repstat = NFSERR_INVAL;
2527 clientid.lval[0] = *tl++;
2528 clientid.lval[1] = *tl;
2529 if (nd->nd_flag & ND_IMPLIEDCLID) {
2530 if (nd->nd_clientid.qval != clientid.qval)
2531 printf("EEK! multiple clids\n");
2533 nd->nd_flag |= ND_IMPLIEDCLID;
2534 nd->nd_clientid.qval = clientid.qval;
2536 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2539 #ifdef NFS4_ACL_EXTATTR_NAME
2542 FREE((caddr_t)stp, M_NFSDSTATE);
2545 NFSVNO_ATTRINIT(&nva);
2546 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2547 create = fxdr_unsigned(int, *tl);
2548 if (!nd->nd_repstat)
2549 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2550 if (create == NFSV4OPEN_CREATE) {
2553 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2554 how = fxdr_unsigned(int, *tl);
2556 case NFSCREATE_UNCHECKED:
2557 case NFSCREATE_GUARDED:
2558 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2561 #ifdef NFS4_ACL_EXTATTR_NAME
2564 FREE((caddr_t)stp, M_NFSDSTATE);
2568 * If the na_gid being set is the same as that of
2569 * the directory it is going in, clear it, since
2570 * that is what will be set by default. This allows
2571 * a user that isn't in that group to do the create.
2573 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2574 nva.na_gid == dirfor.na_gid)
2575 NFSVNO_UNSET(&nva, gid);
2576 if (!nd->nd_repstat)
2577 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2579 case NFSCREATE_EXCLUSIVE:
2580 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2585 nd->nd_repstat = NFSERR_BADXDR;
2587 #ifdef NFS4_ACL_EXTATTR_NAME
2590 FREE((caddr_t)stp, M_NFSDSTATE);
2593 } else if (create != NFSV4OPEN_NOCREATE) {
2594 nd->nd_repstat = NFSERR_BADXDR;
2596 #ifdef NFS4_ACL_EXTATTR_NAME
2599 FREE((caddr_t)stp, M_NFSDSTATE);
2604 * Now, handle the claim, which usually includes looking up a
2605 * name in the directory referenced by dp. The exception is
2606 * NFSV4OPEN_CLAIMPREVIOUS.
2608 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2609 claim = fxdr_unsigned(int, *tl);
2610 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2611 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2612 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2613 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2614 stp->ls_flags |= NFSLCK_DELEGCUR;
2615 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2616 stp->ls_flags |= NFSLCK_DELEGPREV;
2618 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2619 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2620 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2621 claim != NFSV4OPEN_CLAIMNULL)
2622 nd->nd_repstat = NFSERR_INVAL;
2623 if (nd->nd_repstat) {
2624 nd->nd_repstat = nfsrv_opencheck(clientid,
2625 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2627 #ifdef NFS4_ACL_EXTATTR_NAME
2630 FREE((caddr_t)stp, M_NFSDSTATE);
2633 if (create == NFSV4OPEN_CREATE)
2634 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2635 LOCKPARENT | LOCKLEAF | SAVESTART);
2637 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2638 LOCKLEAF | SAVESTART);
2639 nfsvno_setpathbuf(&named, &bufp, &hashp);
2640 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2643 #ifdef NFS4_ACL_EXTATTR_NAME
2646 FREE((caddr_t)stp, M_NFSDSTATE);
2647 nfsvno_relpathbuf(&named);
2650 if (!nd->nd_repstat) {
2651 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2655 nfsvno_relpathbuf(&named);
2657 if (create == NFSV4OPEN_CREATE) {
2659 case NFSCREATE_UNCHECKED:
2662 * Clear the setable attribute bits, except
2663 * for Size, if it is being truncated.
2665 NFSZERO_ATTRBIT(&attrbits);
2666 if (NFSVNO_ISSETSIZE(&nva))
2667 NFSSETBIT_ATTRBIT(&attrbits,
2671 case NFSCREATE_GUARDED:
2672 if (named.ni_vp && !nd->nd_repstat)
2673 nd->nd_repstat = EEXIST;
2675 case NFSCREATE_EXCLUSIVE:
2681 nfsvno_open(nd, &named, clientid, &stateid, stp,
2682 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2683 nd->nd_cred, p, exp, &vp);
2684 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2685 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2686 i = fxdr_unsigned(int, *tl);
2688 case NFSV4OPEN_DELEGATEREAD:
2689 stp->ls_flags |= NFSLCK_DELEGREAD;
2691 case NFSV4OPEN_DELEGATEWRITE:
2692 stp->ls_flags |= NFSLCK_DELEGWRITE;
2693 case NFSV4OPEN_DELEGATENONE:
2696 nd->nd_repstat = NFSERR_BADXDR;
2698 #ifdef NFS4_ACL_EXTATTR_NAME
2701 FREE((caddr_t)stp, M_NFSDSTATE);
2704 stp->ls_flags |= NFSLCK_RECLAIM;
2706 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2707 if ((vp->v_iflag & VI_DOOMED) == 0)
2708 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2709 stp, vp, nd, p, nd->nd_repstat);
2711 nd->nd_repstat = NFSERR_PERM;
2713 nd->nd_repstat = NFSERR_BADXDR;
2715 #ifdef NFS4_ACL_EXTATTR_NAME
2718 FREE((caddr_t)stp, M_NFSDSTATE);
2723 * Do basic access checking.
2725 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2726 if (vnode_vtype(vp) == VDIR)
2727 nd->nd_repstat = NFSERR_ISDIR;
2728 else if (vnode_vtype(vp) == VLNK)
2729 nd->nd_repstat = NFSERR_SYMLINK;
2731 nd->nd_repstat = NFSERR_INVAL;
2733 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2734 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2735 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2736 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2737 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2738 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2740 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2741 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2742 NFSACCCHK_VPISLOCKED, NULL);
2745 if (!nd->nd_repstat) {
2746 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2747 if (!nd->nd_repstat) {
2748 tverf[0] = nva.na_atime.tv_sec;
2749 tverf[1] = nva.na_atime.tv_nsec;
2752 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2753 cverf[1] != tverf[1]))
2754 nd->nd_repstat = EEXIST;
2756 * Do the open locking/delegation stuff.
2758 if (!nd->nd_repstat)
2759 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2760 &delegstateid, &rflags, exp, p, nva.na_filerev);
2763 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2764 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2765 * (ie: Leave the NFSVOPUNLOCK() about here.)
2768 NFSVOPUNLOCK(vp, 0);
2770 FREE((caddr_t)stp, M_NFSDSTATE);
2771 if (!nd->nd_repstat && dirp)
2772 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2774 if (!nd->nd_repstat) {
2775 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2776 *tl++ = txdr_unsigned(stateid.seqid);
2777 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2778 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2779 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2780 *tl++ = newnfs_true;
2786 *tl++ = newnfs_false; /* Since dirp is not locked */
2787 txdr_hyper(dirfor.na_filerev, tl);
2789 txdr_hyper(diraft.na_filerev, tl);
2792 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2793 (void) nfsrv_putattrbit(nd, &attrbits);
2794 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2795 if (rflags & NFSV4OPEN_READDELEGATE)
2796 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2797 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2798 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2800 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2801 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2802 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2803 *tl++ = txdr_unsigned(delegstateid.seqid);
2804 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2806 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2807 if (rflags & NFSV4OPEN_RECALL)
2811 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2812 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2813 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2814 txdr_hyper(nva.na_size, tl);
2816 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2817 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2818 *tl++ = txdr_unsigned(0x0);
2819 acemask = NFSV4ACE_ALLFILESMASK;
2820 if (nva.na_mode & S_IRUSR)
2821 acemask |= NFSV4ACE_READMASK;
2822 if (nva.na_mode & S_IWUSR)
2823 acemask |= NFSV4ACE_WRITEMASK;
2824 if (nva.na_mode & S_IXUSR)
2825 acemask |= NFSV4ACE_EXECUTEMASK;
2826 *tl = txdr_unsigned(acemask);
2827 (void) nfsm_strtom(nd, "OWNER@", 6);
2835 #ifdef NFS4_ACL_EXTATTR_NAME
2841 #ifdef NFS4_ACL_EXTATTR_NAME
2845 FREE((caddr_t)stp, M_NFSDSTATE);
2850 * nfsv4 close service
2853 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2854 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2857 struct nfsstate st, *stp = &st;
2859 nfsv4stateid_t stateid;
2862 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2863 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2864 stp->ls_ownerlen = 0;
2865 stp->ls_op = nd->nd_rp;
2866 stp->ls_uid = nd->nd_cred->cr_uid;
2867 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2868 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2870 stp->ls_flags = NFSLCK_CLOSE;
2871 clientid.lval[0] = stp->ls_stateid.other[0];
2872 clientid.lval[1] = stp->ls_stateid.other[1];
2873 if (nd->nd_flag & ND_IMPLIEDCLID) {
2874 if (nd->nd_clientid.qval != clientid.qval)
2875 printf("EEK! multiple clids\n");
2877 nd->nd_flag |= ND_IMPLIEDCLID;
2878 nd->nd_clientid.qval = clientid.qval;
2880 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2882 if (!nd->nd_repstat) {
2883 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2884 *tl++ = txdr_unsigned(stateid.seqid);
2885 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2894 * nfsv4 delegpurge service
2897 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2898 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2904 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2905 nd->nd_repstat = NFSERR_WRONGSEC;
2908 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2909 clientid.lval[0] = *tl++;
2910 clientid.lval[1] = *tl;
2911 if (nd->nd_flag & ND_IMPLIEDCLID) {
2912 if (nd->nd_clientid.qval != clientid.qval)
2913 printf("EEK! multiple clids\n");
2915 nd->nd_flag |= ND_IMPLIEDCLID;
2916 nd->nd_clientid.qval = clientid.qval;
2918 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2919 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2925 * nfsv4 delegreturn service
2928 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2929 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2933 nfsv4stateid_t stateid;
2936 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2937 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2938 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2939 clientid.lval[0] = stateid.other[0];
2940 clientid.lval[1] = stateid.other[1];
2941 if (nd->nd_flag & ND_IMPLIEDCLID) {
2942 if (nd->nd_clientid.qval != clientid.qval)
2943 printf("EEK! multiple clids\n");
2945 nd->nd_flag |= ND_IMPLIEDCLID;
2946 nd->nd_clientid.qval = clientid.qval;
2948 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2949 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2956 * nfsv4 get file handle service
2959 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2960 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2964 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2966 if (!nd->nd_repstat)
2967 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2972 * nfsv4 open confirm service
2975 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2976 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2979 struct nfsstate st, *stp = &st;
2981 nfsv4stateid_t stateid;
2984 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2985 stp->ls_ownerlen = 0;
2986 stp->ls_op = nd->nd_rp;
2987 stp->ls_uid = nd->nd_cred->cr_uid;
2988 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2989 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2991 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2992 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2993 stp->ls_flags = NFSLCK_CONFIRM;
2994 clientid.lval[0] = stp->ls_stateid.other[0];
2995 clientid.lval[1] = stp->ls_stateid.other[1];
2996 if (nd->nd_flag & ND_IMPLIEDCLID) {
2997 if (nd->nd_clientid.qval != clientid.qval)
2998 printf("EEK! multiple clids\n");
3000 nd->nd_flag |= ND_IMPLIEDCLID;
3001 nd->nd_clientid.qval = clientid.qval;
3003 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3004 if (!nd->nd_repstat) {
3005 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3006 *tl++ = txdr_unsigned(stateid.seqid);
3007 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3015 * nfsv4 open downgrade service
3018 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3019 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3023 struct nfsstate st, *stp = &st;
3025 nfsv4stateid_t stateid;
3028 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3029 stp->ls_ownerlen = 0;
3030 stp->ls_op = nd->nd_rp;
3031 stp->ls_uid = nd->nd_cred->cr_uid;
3032 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3033 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3035 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3036 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3037 i = fxdr_unsigned(int, *tl++);
3039 case NFSV4OPEN_ACCESSREAD:
3040 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3042 case NFSV4OPEN_ACCESSWRITE:
3043 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3045 case NFSV4OPEN_ACCESSBOTH:
3046 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3050 nd->nd_repstat = NFSERR_BADXDR;
3052 i = fxdr_unsigned(int, *tl);
3054 case NFSV4OPEN_DENYNONE:
3056 case NFSV4OPEN_DENYREAD:
3057 stp->ls_flags |= NFSLCK_READDENY;
3059 case NFSV4OPEN_DENYWRITE:
3060 stp->ls_flags |= NFSLCK_WRITEDENY;
3062 case NFSV4OPEN_DENYBOTH:
3063 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3066 nd->nd_repstat = NFSERR_BADXDR;
3069 clientid.lval[0] = stp->ls_stateid.other[0];
3070 clientid.lval[1] = stp->ls_stateid.other[1];
3071 if (nd->nd_flag & ND_IMPLIEDCLID) {
3072 if (nd->nd_clientid.qval != clientid.qval)
3073 printf("EEK! multiple clids\n");
3075 nd->nd_flag |= ND_IMPLIEDCLID;
3076 nd->nd_clientid.qval = clientid.qval;
3078 if (!nd->nd_repstat)
3079 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3081 if (!nd->nd_repstat) {
3082 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3083 *tl++ = txdr_unsigned(stateid.seqid);
3084 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3092 * nfsv4 renew lease service
3095 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3096 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3102 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3103 nd->nd_repstat = NFSERR_WRONGSEC;
3106 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3107 clientid.lval[0] = *tl++;
3108 clientid.lval[1] = *tl;
3109 if (nd->nd_flag & ND_IMPLIEDCLID) {
3110 if (nd->nd_clientid.qval != clientid.qval)
3111 printf("EEK! multiple clids\n");
3113 nd->nd_flag |= ND_IMPLIEDCLID;
3114 nd->nd_clientid.qval = clientid.qval;
3116 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3117 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3123 * nfsv4 security info service
3126 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3127 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3131 struct nameidata named;
3132 vnode_t dirp = NULL, vp;
3134 struct nfsexstuff retnes;
3136 int error, savflag, i;
3141 * All this just to get the export flags for the name.
3143 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3144 LOCKLEAF | SAVESTART);
3145 nfsvno_setpathbuf(&named, &bufp, &hashp);
3146 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3149 nfsvno_relpathbuf(&named);
3152 if (!nd->nd_repstat) {
3153 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3156 nfsvno_relpathbuf(&named);
3162 vrele(named.ni_startdir);
3163 nfsvno_relpathbuf(&named);
3164 fh.nfsrvfh_len = NFSX_MYFH;
3166 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3168 savflag = nd->nd_flag;
3169 if (!nd->nd_repstat) {
3170 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3174 nd->nd_flag = savflag;
3179 * Finally have the export flags for name, so we can create
3180 * the security info.
3183 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3184 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3185 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3186 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3187 *tl = txdr_unsigned(RPCAUTH_UNIX);
3189 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3191 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3192 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3193 nfsgss_mechlist[KERBV_MECH].len);
3194 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3195 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3196 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3198 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3200 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3201 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3202 nfsgss_mechlist[KERBV_MECH].len);
3203 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3204 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3205 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3207 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3208 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3209 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3210 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3211 nfsgss_mechlist[KERBV_MECH].len);
3212 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3213 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3214 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3218 *sizp = txdr_unsigned(len);
3223 * nfsv4 set client id service
3226 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3227 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3231 int error = 0, idlen;
3232 struct nfsclient *clp = NULL;
3233 struct sockaddr_in *rad;
3234 u_char *verf, *ucp, *ucp2, addrbuf[24];
3235 nfsquad_t clientid, confirm;
3237 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3238 nd->nd_repstat = NFSERR_WRONGSEC;
3241 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3242 verf = (u_char *)tl;
3243 tl += (NFSX_VERF / NFSX_UNSIGNED);
3244 i = fxdr_unsigned(int, *tl);
3245 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3246 nd->nd_repstat = NFSERR_BADXDR;
3250 if (nd->nd_flag & ND_GSS)
3251 i += nd->nd_princlen;
3252 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3253 M_NFSDCLIENT, M_WAITOK);
3254 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3255 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3256 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3257 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3258 clp->lc_req.nr_cred = NULL;
3259 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3260 clp->lc_idlen = idlen;
3261 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3264 if (nd->nd_flag & ND_GSS) {
3265 clp->lc_flags = LCL_GSS;
3266 if (nd->nd_flag & ND_GSSINTEGRITY)
3267 clp->lc_flags |= LCL_GSSINTEGRITY;
3268 else if (nd->nd_flag & ND_GSSPRIVACY)
3269 clp->lc_flags |= LCL_GSSPRIVACY;
3273 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3274 clp->lc_flags |= LCL_NAME;
3275 clp->lc_namelen = nd->nd_princlen;
3276 clp->lc_name = &clp->lc_id[idlen];
3277 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3279 clp->lc_uid = nd->nd_cred->cr_uid;
3280 clp->lc_gid = nd->nd_cred->cr_gid;
3282 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3283 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3284 error = nfsrv_getclientipaddr(nd, clp);
3287 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3288 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3291 * nfsrv_setclient() does the actual work of adding it to the
3292 * client list. If there is no error, the structure has been
3293 * linked into the client list and clp should no longer be used
3294 * here. When an error is returned, it has not been linked in,
3295 * so it should be free'd.
3297 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3298 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3299 if (clp->lc_flags & LCL_TCPCALLBACK)
3300 (void) nfsm_strtom(nd, "tcp", 3);
3302 (void) nfsm_strtom(nd, "udp", 3);
3303 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3304 ucp = (u_char *)&rad->sin_addr.s_addr;
3305 ucp2 = (u_char *)&rad->sin_port;
3306 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3307 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3308 ucp2[0] & 0xff, ucp2[1] & 0xff);
3309 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3312 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3313 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3314 free((caddr_t)clp, M_NFSDCLIENT);
3316 if (!nd->nd_repstat) {
3317 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3318 *tl++ = clientid.lval[0];
3319 *tl++ = clientid.lval[1];
3320 *tl++ = confirm.lval[0];
3321 *tl = confirm.lval[1];
3326 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3327 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3328 free((caddr_t)clp, M_NFSDCLIENT);
3334 * nfsv4 set client id confirm service
3337 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3338 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3339 __unused struct nfsexstuff *exp)
3343 nfsquad_t clientid, confirm;
3345 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3346 nd->nd_repstat = NFSERR_WRONGSEC;
3349 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3350 clientid.lval[0] = *tl++;
3351 clientid.lval[1] = *tl++;
3352 confirm.lval[0] = *tl++;
3353 confirm.lval[1] = *tl;
3356 * nfsrv_getclient() searches the client list for a match and
3357 * returns the appropriate NFSERR status.
3359 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3360 NULL, confirm, nd, p);
3366 * nfsv4 verify service
3369 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3370 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3372 int error = 0, ret, fhsize = NFSX_MYFH;
3373 struct nfsvattr nva;
3375 struct nfsfsinfo fs;
3378 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3379 if (!nd->nd_repstat)
3380 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3381 if (!nd->nd_repstat)
3382 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3383 if (!nd->nd_repstat) {
3384 nfsvno_getfs(&fs, isdgram);
3385 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3386 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3388 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3390 nd->nd_repstat = NFSERR_SAME;
3391 else if (ret != NFSERR_NOTSAME)
3392 nd->nd_repstat = ret;
3394 nd->nd_repstat = ret;
3405 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3406 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3407 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3410 int error = 0, createdir;
3412 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3413 createdir = fxdr_unsigned(int, *tl);
3414 nd->nd_repstat = NFSERR_NOTSUPP;
3421 * nfsv4 release lock owner service
3424 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3425 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3428 struct nfsstate *stp = NULL;
3432 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3433 nd->nd_repstat = NFSERR_WRONGSEC;
3436 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3437 len = fxdr_unsigned(int, *(tl + 2));
3438 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3439 nd->nd_repstat = NFSERR_BADXDR;
3442 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3443 M_NFSDSTATE, M_WAITOK);
3444 stp->ls_ownerlen = len;
3446 stp->ls_flags = NFSLCK_RELEASE;
3447 stp->ls_uid = nd->nd_cred->cr_uid;
3448 clientid.lval[0] = *tl++;
3449 clientid.lval[1] = *tl;
3450 if (nd->nd_flag & ND_IMPLIEDCLID) {
3451 if (nd->nd_clientid.qval != clientid.qval)
3452 printf("EEK! multiple clids\n");
3454 nd->nd_flag |= ND_IMPLIEDCLID;
3455 nd->nd_clientid.qval = clientid.qval;
3457 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3460 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3461 FREE((caddr_t)stp, M_NFSDSTATE);
3465 free((caddr_t)stp, M_NFSDSTATE);