]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsserver/nfs_nfsdserv.c
MFV: zlib 1.3
[FreeBSD/FreeBSD.git] / sys / fs / nfsserver / nfs_nfsdserv.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35
36 #include <sys/cdefs.h>
37 #include "opt_inet.h"
38 #include "opt_inet6.h"
39 /*
40  * nfs version 2, 3 and 4 server calls to vnode ops
41  * - these routines generally have 3 phases
42  *   1 - break down and validate rpc request in mbuf list
43  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
44  *       function in nfsd_port.c
45  *   3 - build the rpc reply in an mbuf list
46  * For nfsv4, these functions are called for each Op within the Compound RPC.
47  */
48
49 #include <fs/nfs/nfsport.h>
50 #include <sys/extattr.h>
51 #include <sys/filio.h>
52
53 /* Global vars */
54 extern u_int32_t newnfs_false, newnfs_true;
55 extern __enum_uint8(vtype) nv34tov_type[8];
56 extern struct timeval nfsboottime;
57 extern int nfsrv_enable_crossmntpt;
58 extern int nfsrv_statehashsize;
59 extern int nfsrv_layouthashsize;
60 extern time_t nfsdev_time;
61 extern volatile int nfsrv_devidcnt;
62 extern int nfsd_debuglevel;
63 extern u_long sb_max_adj;
64 extern int nfsrv_pnfsatime;
65 extern int nfsrv_maxpnfsmirror;
66 extern uint32_t nfs_srvmaxio;
67
68 static int      nfs_async = 0;
69 SYSCTL_DECL(_vfs_nfsd);
70 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
71     "Tell client that writes were synced even though they were not");
72 extern int      nfsrv_doflexfile;
73 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
74     &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
75 static int      nfsrv_linux42server = 1;
76 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
77     &nfsrv_linux42server, 0,
78     "Enable Linux style NFSv4.2 server (non-RFC compliant)");
79 static bool     nfsrv_openaccess = true;
80 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
81     &nfsrv_openaccess, 0,
82     "Enable Linux style NFSv4 Open access check");
83 static char nfsrv_scope[NFSV4_OPAQUELIMIT];
84 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN,
85     &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope");
86 static char nfsrv_owner_major[NFSV4_OPAQUELIMIT];
87 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN,
88     &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major");
89 static uint64_t nfsrv_owner_minor;
90 SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN,
91     &nfsrv_owner_minor, 0, "Server owner minor");
92 /*
93  * Only enable this if all your exported file systems
94  * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE.
95  */
96 static bool     nfsrv_doallocate = false;
97 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW,
98     &nfsrv_doallocate, 0,
99     "Enable NFSv4.2 Allocate operation");
100
101 /*
102  * This list defines the GSS mechanisms supported.
103  * (Don't ask me how you get these strings from the RFC stuff like
104  *  iso(1), org(3)... but someone did it, so I don't need to know.)
105  */
106 static struct nfsgss_mechlist nfsgss_mechlist[] = {
107         { 9, "\052\206\110\206\367\022\001\002\002", 11 },
108         { 0, "", 0 },
109 };
110
111 /* local functions */
112 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
113     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
114     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
115     int *diraft_retp, nfsattrbit_t *attrbitp,
116     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
117     int pathlen);
118 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
119     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
120     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
121     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
122     NFSPROC_T *p, struct nfsexstuff *exp);
123
124 /*
125  * nfs access service (not a part of NFS V2)
126  */
127 int
128 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
129     vnode_t vp, struct nfsexstuff *exp)
130 {
131         u_int32_t *tl;
132         int getret, error = 0;
133         struct nfsvattr nva;
134         u_int32_t testmode, nfsmode, supported = 0;
135         accmode_t deletebit;
136         struct thread *p = curthread;
137
138         if (nd->nd_repstat) {
139                 nfsrv_postopattr(nd, 1, &nva);
140                 goto out;
141         }
142         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
143         nfsmode = fxdr_unsigned(u_int32_t, *tl);
144         if ((nd->nd_flag & ND_NFSV4) &&
145             (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
146              NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
147              NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
148              NFSACCESS_XALIST))) {
149                 nd->nd_repstat = NFSERR_INVAL;
150                 vput(vp);
151                 goto out;
152         }
153         if (nfsmode & NFSACCESS_READ) {
154                 supported |= NFSACCESS_READ;
155                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
156                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
157                         nfsmode &= ~NFSACCESS_READ;
158         }
159         if (nfsmode & NFSACCESS_MODIFY) {
160                 supported |= NFSACCESS_MODIFY;
161                 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
162                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
163                         nfsmode &= ~NFSACCESS_MODIFY;
164         }
165         if (nfsmode & NFSACCESS_EXTEND) {
166                 supported |= NFSACCESS_EXTEND;
167                 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
168                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
169                         nfsmode &= ~NFSACCESS_EXTEND;
170         }
171         if (nfsmode & NFSACCESS_XAREAD) {
172                 supported |= NFSACCESS_XAREAD;
173                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
174                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
175                         nfsmode &= ~NFSACCESS_XAREAD;
176         }
177         if (nfsmode & NFSACCESS_XAWRITE) {
178                 supported |= NFSACCESS_XAWRITE;
179                 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
180                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
181                         nfsmode &= ~NFSACCESS_XAWRITE;
182         }
183         if (nfsmode & NFSACCESS_XALIST) {
184                 supported |= NFSACCESS_XALIST;
185                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
186                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
187                         nfsmode &= ~NFSACCESS_XALIST;
188         }
189         if (nfsmode & NFSACCESS_DELETE) {
190                 supported |= NFSACCESS_DELETE;
191                 if (vp->v_type == VDIR)
192                         deletebit = VDELETE_CHILD;
193                 else
194                         deletebit = VDELETE;
195                 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
196                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
197                         nfsmode &= ~NFSACCESS_DELETE;
198         }
199         if (vp->v_type == VDIR)
200                 testmode = NFSACCESS_LOOKUP;
201         else
202                 testmode = NFSACCESS_EXECUTE;
203         if (nfsmode & testmode) {
204                 supported |= (nfsmode & testmode);
205                 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
206                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
207                         nfsmode &= ~testmode;
208         }
209         nfsmode &= supported;
210         if (nd->nd_flag & ND_NFSV3) {
211                 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
212                 nfsrv_postopattr(nd, getret, &nva);
213         }
214         vput(vp);
215         if (nd->nd_flag & ND_NFSV4) {
216                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
217                 *tl++ = txdr_unsigned(supported);
218         } else
219                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
220         *tl = txdr_unsigned(nfsmode);
221
222 out:
223         NFSEXITCODE2(0, nd);
224         return (0);
225 nfsmout:
226         vput(vp);
227         NFSEXITCODE2(error, nd);
228         return (error);
229 }
230
231 /*
232  * nfs getattr service
233  */
234 int
235 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
236     vnode_t vp, __unused struct nfsexstuff *exp)
237 {
238         struct nfsvattr nva;
239         fhandle_t fh;
240         int at_root = 0, error = 0, supports_nfsv4acls;
241         struct nfsreferral *refp;
242         nfsattrbit_t attrbits, tmpbits;
243         struct mount *mp;
244         struct vnode *tvp = NULL;
245         struct vattr va;
246         uint64_t mounted_on_fileno = 0;
247         accmode_t accmode;
248         struct thread *p = curthread;
249
250         if (nd->nd_repstat)
251                 goto out;
252         if (nd->nd_flag & ND_NFSV4) {
253                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
254                 if (error) {
255                         vput(vp);
256                         goto out;
257                 }
258
259                 /*
260                  * Check for a referral.
261                  */
262                 refp = nfsv4root_getreferral(vp, NULL, 0);
263                 if (refp != NULL) {
264                         (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
265                             &nd->nd_repstat);
266                         vput(vp);
267                         goto out;
268                 }
269                 if (nd->nd_repstat == 0) {
270                         accmode = 0;
271                         NFSSET_ATTRBIT(&tmpbits, &attrbits);
272
273                         /*
274                          * GETATTR with write-only attr time_access_set and time_modify_set
275                          * should return NFS4ERR_INVAL.
276                          */
277                         if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
278                                         NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
279                                 error = NFSERR_INVAL;
280                                 vput(vp);
281                                 goto out;
282                         }
283                         if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
284                                 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
285                                 accmode |= VREAD_ACL;
286                         }
287                         if (NFSNONZERO_ATTRBIT(&tmpbits))
288                                 accmode |= VREAD_ATTRIBUTES;
289                         if (accmode != 0)
290                                 nd->nd_repstat = nfsvno_accchk(vp, accmode,
291                                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
292                                     NFSACCCHK_VPISLOCKED, NULL);
293                 }
294         }
295         if (!nd->nd_repstat)
296                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
297         if (!nd->nd_repstat) {
298                 if (nd->nd_flag & ND_NFSV4) {
299                         if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
300                                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
301                         if (!nd->nd_repstat)
302                                 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
303                                     &nva, &attrbits, p);
304                         if (nd->nd_repstat == 0) {
305                                 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
306                                 mp = vp->v_mount;
307                                 if (nfsrv_enable_crossmntpt != 0 &&
308                                     vp->v_type == VDIR &&
309                                     (vp->v_vflag & VV_ROOT) != 0 &&
310                                     vp != rootvnode) {
311                                         tvp = mp->mnt_vnodecovered;
312                                         VREF(tvp);
313                                         at_root = 1;
314                                 } else
315                                         at_root = 0;
316                                 vfs_ref(mp);
317                                 NFSVOPUNLOCK(vp);
318                                 if (at_root != 0) {
319                                         if ((nd->nd_repstat =
320                                              NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
321                                                 nd->nd_repstat = VOP_GETATTR(
322                                                     tvp, &va, nd->nd_cred);
323                                                 vput(tvp);
324                                         } else
325                                                 vrele(tvp);
326                                         if (nd->nd_repstat == 0)
327                                                 mounted_on_fileno = (uint64_t)
328                                                     va.va_fileid;
329                                         else
330                                                 at_root = 0;
331                                 }
332                                 if (nd->nd_repstat == 0)
333                                         nd->nd_repstat = vfs_busy(mp, 0);
334                                 vfs_rel(mp);
335                                 if (nd->nd_repstat == 0) {
336                                         (void)nfsvno_fillattr(nd, mp, vp, &nva,
337                                             &fh, 0, &attrbits, nd->nd_cred, p,
338                                             isdgram, 1, supports_nfsv4acls,
339                                             at_root, mounted_on_fileno);
340                                         vfs_unbusy(mp);
341                                 }
342                                 vrele(vp);
343                         } else
344                                 vput(vp);
345                 } else {
346                         nfsrv_fillattr(nd, &nva);
347                         vput(vp);
348                 }
349         } else {
350                 vput(vp);
351         }
352
353 out:
354         NFSEXITCODE2(error, nd);
355         return (error);
356 }
357
358 /*
359  * nfs setattr service
360  */
361 int
362 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
363     vnode_t vp, struct nfsexstuff *exp)
364 {
365         struct nfsvattr nva, nva2;
366         u_int32_t *tl;
367         int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
368         int gotproxystateid;
369         struct timespec guard = { 0, 0 };
370         nfsattrbit_t attrbits, retbits;
371         nfsv4stateid_t stateid;
372         NFSACL_T *aclp = NULL;
373         struct thread *p = curthread;
374
375         if (nd->nd_repstat) {
376                 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
377                 goto out;
378         }
379 #ifdef NFS4_ACL_EXTATTR_NAME
380         aclp = acl_alloc(M_WAITOK);
381         aclp->acl_cnt = 0;
382 #endif
383         gotproxystateid = 0;
384         NFSVNO_ATTRINIT(&nva);
385         if (nd->nd_flag & ND_NFSV4) {
386                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
387                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
388                 stateid.other[0] = *tl++;
389                 stateid.other[1] = *tl++;
390                 stateid.other[2] = *tl;
391                 if (stateid.other[0] == 0x55555555 &&
392                     stateid.other[1] == 0x55555555 &&
393                     stateid.other[2] == 0x55555555 &&
394                     stateid.seqid == 0xffffffff)
395                         gotproxystateid = 1;
396         }
397         error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
398         if (error)
399                 goto nfsmout;
400
401         /* For NFSv4, only va_uid is used from nva2. */
402         NFSZERO_ATTRBIT(&retbits);
403         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
404         preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
405         if (!nd->nd_repstat)
406                 nd->nd_repstat = preat_ret;
407
408         NFSZERO_ATTRBIT(&retbits);
409         if (nd->nd_flag & ND_NFSV3) {
410                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
411                 gcheck = fxdr_unsigned(int, *tl);
412                 if (gcheck) {
413                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
414                         fxdr_nfsv3time(tl, &guard);
415                 }
416                 if (!nd->nd_repstat && gcheck &&
417                     (nva2.na_ctime.tv_sec != guard.tv_sec ||
418                      nva2.na_ctime.tv_nsec != guard.tv_nsec))
419                         nd->nd_repstat = NFSERR_NOT_SYNC;
420                 if (nd->nd_repstat) {
421                         vput(vp);
422 #ifdef NFS4_ACL_EXTATTR_NAME
423                         acl_free(aclp);
424 #endif
425                         nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
426                         goto out;
427                 }
428         } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
429                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
430
431         /*
432          * Now that we have all the fields, lets do it.
433          * If the size is being changed write access is required, otherwise
434          * just check for a read only file system.
435          */
436         if (!nd->nd_repstat) {
437                 if (NFSVNO_NOTSETSIZE(&nva)) {
438                         if (NFSVNO_EXRDONLY(exp) ||
439                             (vp->v_mount->mnt_flag & MNT_RDONLY))
440                                 nd->nd_repstat = EROFS;
441                 } else {
442                         if (vp->v_type != VREG)
443                                 nd->nd_repstat = EINVAL;
444                         else if (nva2.na_uid != nd->nd_cred->cr_uid ||
445                             NFSVNO_EXSTRICTACCESS(exp))
446                                 nd->nd_repstat = nfsvno_accchk(vp,
447                                     VWRITE, nd->nd_cred, exp, p,
448                                     NFSACCCHK_NOOVERRIDE,
449                                     NFSACCCHK_VPISLOCKED, NULL);
450                 }
451         }
452         /*
453          * Proxy operations from the MDS are allowed via the all 0s special
454          * stateid.
455          */
456         if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
457             gotproxystateid == 0)
458                 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
459                     &nva, &attrbits, exp, p);
460
461         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
462             /*
463              * For V4, try setting the attributes in sets, so that the
464              * reply bitmap will be correct for an error case.
465              */
466             if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
467                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
468                 NFSVNO_ATTRINIT(&nva2);
469                 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
470                 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
471                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
472                     exp);
473                 if (!nd->nd_repstat) {
474                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
475                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
476                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
477                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
478                 }
479             }
480             if (!nd->nd_repstat &&
481                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
482                 NFSVNO_ATTRINIT(&nva2);
483                 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
484                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
485                     exp);
486                 if (!nd->nd_repstat)
487                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
488             }
489             if (!nd->nd_repstat &&
490                 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
491                  NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
492                 NFSVNO_ATTRINIT(&nva2);
493                 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
494                 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
495                 if (nva.na_vaflags & VA_UTIMES_NULL) {
496                         nva2.na_vaflags |= VA_UTIMES_NULL;
497                         NFSVNO_SETACTIVE(&nva2, vaflags);
498                 }
499                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
500                     exp);
501                 if (!nd->nd_repstat) {
502                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
503                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
504                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
505                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
506                 }
507             }
508             if (!nd->nd_repstat &&
509                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) {
510                 NFSVNO_ATTRINIT(&nva2);
511                 NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime);
512                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
513                     exp);
514                 if (!nd->nd_repstat)
515                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE);
516             }
517             if (!nd->nd_repstat &&
518                 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
519                  NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
520                 NFSVNO_ATTRINIT(&nva2);
521                 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
522                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
523                     exp);
524                 if (!nd->nd_repstat) {
525                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
526                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
527                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
528                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
529                 }
530             }
531
532 #ifdef NFS4_ACL_EXTATTR_NAME
533             if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
534                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
535                 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
536                 if (!nd->nd_repstat) 
537                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
538             }
539 #endif
540         } else if (!nd->nd_repstat) {
541                 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
542                     exp);
543         }
544         if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
545                 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
546                 if (!nd->nd_repstat)
547                         nd->nd_repstat = postat_ret;
548         }
549         vput(vp);
550 #ifdef NFS4_ACL_EXTATTR_NAME
551         acl_free(aclp);
552 #endif
553         if (nd->nd_flag & ND_NFSV3)
554                 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
555         else if (nd->nd_flag & ND_NFSV4)
556                 (void) nfsrv_putattrbit(nd, &retbits);
557         else if (!nd->nd_repstat)
558                 nfsrv_fillattr(nd, &nva);
559
560 out:
561         NFSEXITCODE2(0, nd);
562         return (0);
563 nfsmout:
564         vput(vp);
565 #ifdef NFS4_ACL_EXTATTR_NAME
566         acl_free(aclp);
567 #endif
568         if (nd->nd_flag & ND_NFSV4) {
569                 /*
570                  * For all nd_repstat, the V4 reply includes a bitmap,
571                  * even NFSERR_BADXDR, which is what this will end up
572                  * returning.
573                  */
574                 (void) nfsrv_putattrbit(nd, &retbits);
575         }
576         NFSEXITCODE2(error, nd);
577         return (error);
578 }
579
580 /*
581  * nfs lookup rpc
582  * (Also performs lookup parent for v4)
583  */
584 int
585 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
586     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
587 {
588         struct nameidata named;
589         vnode_t vp, dirp = NULL;
590         int error = 0, dattr_ret = 1;
591         struct nfsvattr nva, dattr;
592         char *bufp;
593         u_long *hashp;
594         struct thread *p = curthread;
595
596         if (nd->nd_repstat) {
597                 nfsrv_postopattr(nd, dattr_ret, &dattr);
598                 goto out;
599         }
600
601         /*
602          * For some reason, if dp is a symlink, the error
603          * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
604          */
605         if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
606                 nd->nd_repstat = NFSERR_SYMLINK;
607                 vrele(dp);
608                 goto out;
609         }
610
611         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
612             LOCKLEAF);
613         nfsvno_setpathbuf(&named, &bufp, &hashp);
614         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
615         if (error) {
616                 vrele(dp);
617                 nfsvno_relpathbuf(&named);
618                 goto out;
619         }
620         if (!nd->nd_repstat) {
621                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
622         } else {
623                 vrele(dp);
624                 nfsvno_relpathbuf(&named);
625         }
626         if (nd->nd_repstat) {
627                 if (dirp) {
628                         if (nd->nd_flag & ND_NFSV3)
629                                 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
630                                     0, NULL);
631                         vrele(dirp);
632                 }
633                 if (nd->nd_flag & ND_NFSV3)
634                         nfsrv_postopattr(nd, dattr_ret, &dattr);
635                 goto out;
636         }
637         nfsvno_relpathbuf(&named);
638         vp = named.ni_vp;
639         if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
640             vp->v_type != VDIR && vp->v_type != VLNK)
641                 /*
642                  * Only allow lookup of VDIR and VLNK for traversal of
643                  * non-exported volumes during NFSv4 mounting.
644                  */
645                 nd->nd_repstat = ENOENT;
646         if (nd->nd_repstat == 0) {
647                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
648                 /*
649                  * EOPNOTSUPP indicates the file system cannot be exported,
650                  * so just pretend the entry does not exist.
651                  */
652                 if (nd->nd_repstat == EOPNOTSUPP)
653                         nd->nd_repstat = ENOENT;
654         }
655         if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
656                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
657         if (vpp != NULL && nd->nd_repstat == 0)
658                 *vpp = vp;
659         else
660                 vput(vp);
661         if (dirp) {
662                 if (nd->nd_flag & ND_NFSV3)
663                         dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
664                             NULL);
665                 vrele(dirp);
666         }
667         if (nd->nd_repstat) {
668                 if (nd->nd_flag & ND_NFSV3)
669                         nfsrv_postopattr(nd, dattr_ret, &dattr);
670                 goto out;
671         }
672         if (nd->nd_flag & ND_NFSV2) {
673                 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
674                 nfsrv_fillattr(nd, &nva);
675         } else if (nd->nd_flag & ND_NFSV3) {
676                 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
677                 nfsrv_postopattr(nd, 0, &nva);
678                 nfsrv_postopattr(nd, dattr_ret, &dattr);
679         }
680
681 out:
682         NFSEXITCODE2(error, nd);
683         return (error);
684 }
685
686 /*
687  * nfs readlink service
688  */
689 int
690 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
691     vnode_t vp, __unused struct nfsexstuff *exp)
692 {
693         u_int32_t *tl;
694         struct mbuf *mp = NULL, *mpend = NULL;
695         int getret = 1, len;
696         struct nfsvattr nva;
697         struct thread *p = curthread;
698         uint16_t off;
699
700         if (nd->nd_repstat) {
701                 nfsrv_postopattr(nd, getret, &nva);
702                 goto out;
703         }
704         if (vp->v_type != VLNK) {
705                 if (nd->nd_flag & ND_NFSV2)
706                         nd->nd_repstat = ENXIO;
707                 else
708                         nd->nd_repstat = EINVAL;
709         }
710         if (nd->nd_repstat == 0) {
711                 if ((nd->nd_flag & ND_EXTPG) != 0)
712                         nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
713                             nd->nd_maxextsiz, p, &mp, &mpend, &len);
714                 else
715                         nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
716                             0, p, &mp, &mpend, &len);
717         }
718         if (nd->nd_flag & ND_NFSV3)
719                 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
720         vput(vp);
721         if (nd->nd_flag & ND_NFSV3)
722                 nfsrv_postopattr(nd, getret, &nva);
723         if (nd->nd_repstat)
724                 goto out;
725         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
726         *tl = txdr_unsigned(len);
727         if (mp != NULL) {
728                 nd->nd_mb->m_next = mp;
729                 nd->nd_mb = mpend;
730                 if ((mpend->m_flags & M_EXTPG) != 0) {
731                         nd->nd_bextpg = mpend->m_epg_npgs - 1;
732                         nd->nd_bpos = (char *)(void *)
733                             PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
734                         off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
735                         nd->nd_bpos += off + mpend->m_epg_last_len;
736                         nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
737                             off;
738                 } else
739                         nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
740         }
741
742 out:
743         NFSEXITCODE2(0, nd);
744         return (0);
745 }
746
747 /*
748  * nfs read service
749  */
750 int
751 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
752     vnode_t vp, struct nfsexstuff *exp)
753 {
754         u_int32_t *tl;
755         int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
756         struct mbuf *m2, *m3;
757         struct nfsvattr nva;
758         off_t off = 0x0;
759         struct nfsstate st, *stp = &st;
760         struct nfslock lo, *lop = &lo;
761         nfsv4stateid_t stateid;
762         nfsquad_t clientid;
763         struct thread *p = curthread;
764         uint16_t poff;
765
766         if (nd->nd_repstat) {
767                 nfsrv_postopattr(nd, getret, &nva);
768                 goto out;
769         }
770         if (nd->nd_flag & ND_NFSV2) {
771                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
772                 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
773                 reqlen = fxdr_unsigned(int, *tl);
774         } else if (nd->nd_flag & ND_NFSV3) {
775                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
776                 off = fxdr_hyper(tl);
777                 tl += 2;
778                 reqlen = fxdr_unsigned(int, *tl);
779         } else {
780                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
781                 reqlen = fxdr_unsigned(int, *(tl + 6));
782         }
783         if (reqlen > NFS_SRVMAXDATA(nd)) {
784                 reqlen = NFS_SRVMAXDATA(nd);
785         } else if (reqlen < 0) {
786                 error = EBADRPC;
787                 goto nfsmout;
788         }
789         gotproxystateid = 0;
790         if (nd->nd_flag & ND_NFSV4) {
791                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
792                 lop->lo_flags = NFSLCK_READ;
793                 stp->ls_ownerlen = 0;
794                 stp->ls_op = NULL;
795                 stp->ls_uid = nd->nd_cred->cr_uid;
796                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
797                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
798                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
799                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
800                         if ((nd->nd_flag & ND_NFSV41) != 0)
801                                 clientid.qval = nd->nd_clientid.qval;
802                         else if (nd->nd_clientid.qval != clientid.qval)
803                                 printf("EEK1 multiple clids\n");
804                 } else {
805                         if ((nd->nd_flag & ND_NFSV41) != 0)
806                                 printf("EEK! no clientid from session\n");
807                         nd->nd_flag |= ND_IMPLIEDCLID;
808                         nd->nd_clientid.qval = clientid.qval;
809                 }
810                 stp->ls_stateid.other[2] = *tl++;
811                 /*
812                  * Don't allow the client to use a special stateid for a DS op.
813                  */
814                 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
815                     ((stp->ls_stateid.other[0] == 0x0 &&
816                     stp->ls_stateid.other[1] == 0x0 &&
817                     stp->ls_stateid.other[2] == 0x0) ||
818                     (stp->ls_stateid.other[0] == 0xffffffff &&
819                     stp->ls_stateid.other[1] == 0xffffffff &&
820                     stp->ls_stateid.other[2] == 0xffffffff) ||
821                     stp->ls_stateid.seqid != 0))
822                         nd->nd_repstat = NFSERR_BADSTATEID;
823                 /* However, allow the proxy stateid. */
824                 if (stp->ls_stateid.seqid == 0xffffffff &&
825                     stp->ls_stateid.other[0] == 0x55555555 &&
826                     stp->ls_stateid.other[1] == 0x55555555 &&
827                     stp->ls_stateid.other[2] == 0x55555555)
828                         gotproxystateid = 1;
829                 off = fxdr_hyper(tl);
830                 lop->lo_first = off;
831                 tl += 2;
832                 lop->lo_end = off + reqlen;
833                 /*
834                  * Paranoia, just in case it wraps around.
835                  */
836                 if (lop->lo_end < off)
837                         lop->lo_end = NFS64BITSSET;
838         }
839         if (vp->v_type != VREG) {
840                 if (nd->nd_flag & ND_NFSV3)
841                         nd->nd_repstat = EINVAL;
842                 else
843                         nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
844                             EINVAL;
845         }
846         getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
847         if (!nd->nd_repstat)
848                 nd->nd_repstat = getret;
849         if (!nd->nd_repstat &&
850             (nva.na_uid != nd->nd_cred->cr_uid ||
851              NFSVNO_EXSTRICTACCESS(exp))) {
852                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
853                     nd->nd_cred, exp, p,
854                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
855                 if (nd->nd_repstat)
856                         nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
857                             nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
858                             NFSACCCHK_VPISLOCKED, NULL);
859         }
860         /*
861          * DS reads are marked by ND_DSSERVER or use the proxy special
862          * stateid.
863          */
864         if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
865             ND_NFSV4 && gotproxystateid == 0)
866                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
867                     &stateid, exp, nd, p);
868         if (nd->nd_repstat) {
869                 vput(vp);
870                 if (nd->nd_flag & ND_NFSV3)
871                         nfsrv_postopattr(nd, getret, &nva);
872                 goto out;
873         }
874         if (off >= nva.na_size) {
875                 cnt = 0;
876                 eof = 1;
877         } else if (reqlen == 0)
878                 cnt = 0;
879         else if ((off + reqlen) >= nva.na_size) {
880                 cnt = nva.na_size - off;
881                 eof = 1;
882         } else
883                 cnt = reqlen;
884         m3 = NULL;
885         if (cnt > 0) {
886                 /*
887                  * If cnt > MCLBYTES and the reply will not be saved, use
888                  * ext_pgs mbufs for TLS.
889                  * For NFSv4.0, we do not know for sure if the reply will
890                  * be saved, so do not use ext_pgs mbufs for NFSv4.0.
891                  * Always use ext_pgs mbufs if ND_EXTPG is set.
892                  */
893                 if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
894                     (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
895                     (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
896                         nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
897                             nd->nd_maxextsiz, p, &m3, &m2);
898                 else
899                         nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
900                             0, p, &m3, &m2);
901                 if (!(nd->nd_flag & ND_NFSV4)) {
902                         getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
903                         if (!nd->nd_repstat)
904                                 nd->nd_repstat = getret;
905                 }
906                 if (nd->nd_repstat) {
907                         vput(vp);
908                         if (m3)
909                                 m_freem(m3);
910                         if (nd->nd_flag & ND_NFSV3)
911                                 nfsrv_postopattr(nd, getret, &nva);
912                         goto out;
913                 }
914         }
915         vput(vp);
916         if (nd->nd_flag & ND_NFSV2) {
917                 nfsrv_fillattr(nd, &nva);
918                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
919         } else {
920                 if (nd->nd_flag & ND_NFSV3) {
921                         nfsrv_postopattr(nd, getret, &nva);
922                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
923                         *tl++ = txdr_unsigned(cnt);
924                 } else
925                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
926                 if (eof)
927                         *tl++ = newnfs_true;
928                 else
929                         *tl++ = newnfs_false;
930         }
931         *tl = txdr_unsigned(cnt);
932         if (m3) {
933                 nd->nd_mb->m_next = m3;
934                 nd->nd_mb = m2;
935                 if ((m2->m_flags & M_EXTPG) != 0) {
936                         nd->nd_flag |= ND_EXTPG;
937                         nd->nd_bextpg = m2->m_epg_npgs - 1;
938                         nd->nd_bpos = (char *)(void *)
939                             PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
940                         poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
941                         nd->nd_bpos += poff + m2->m_epg_last_len;
942                         nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
943                             poff;
944                 } else
945                         nd->nd_bpos = mtod(m2, char *) + m2->m_len;
946         }
947
948 out:
949         NFSEXITCODE2(0, nd);
950         return (0);
951 nfsmout:
952         vput(vp);
953         NFSEXITCODE2(error, nd);
954         return (error);
955 }
956
957 /*
958  * nfs write service
959  */
960 int
961 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
962     vnode_t vp, struct nfsexstuff *exp)
963 {
964         u_int32_t *tl;
965         struct nfsvattr nva, forat;
966         int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
967         int gotproxystateid, stable = NFSWRITE_FILESYNC;
968         off_t off;
969         struct nfsstate st, *stp = &st;
970         struct nfslock lo, *lop = &lo;
971         nfsv4stateid_t stateid;
972         nfsquad_t clientid;
973         nfsattrbit_t attrbits;
974         struct thread *p = curthread;
975
976         if (nd->nd_repstat) {
977                 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
978                 goto out;
979         }
980         gotproxystateid = 0;
981         if (nd->nd_flag & ND_NFSV2) {
982                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
983                 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
984                 tl += 2;
985                 retlen = len = fxdr_unsigned(int32_t, *tl);
986         } else if (nd->nd_flag & ND_NFSV3) {
987                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
988                 off = fxdr_hyper(tl);
989                 tl += 3;
990                 stable = fxdr_unsigned(int, *tl++);
991                 retlen = len = fxdr_unsigned(int32_t, *tl);
992         } else {
993                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
994                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
995                 lop->lo_flags = NFSLCK_WRITE;
996                 stp->ls_ownerlen = 0;
997                 stp->ls_op = NULL;
998                 stp->ls_uid = nd->nd_cred->cr_uid;
999                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
1000                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
1001                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
1002                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
1003                         if ((nd->nd_flag & ND_NFSV41) != 0)
1004                                 clientid.qval = nd->nd_clientid.qval;
1005                         else if (nd->nd_clientid.qval != clientid.qval)
1006                                 printf("EEK2 multiple clids\n");
1007                 } else {
1008                         if ((nd->nd_flag & ND_NFSV41) != 0)
1009                                 printf("EEK! no clientid from session\n");
1010                         nd->nd_flag |= ND_IMPLIEDCLID;
1011                         nd->nd_clientid.qval = clientid.qval;
1012                 }
1013                 stp->ls_stateid.other[2] = *tl++;
1014                 /*
1015                  * Don't allow the client to use a special stateid for a DS op.
1016                  */
1017                 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
1018                     ((stp->ls_stateid.other[0] == 0x0 &&
1019                     stp->ls_stateid.other[1] == 0x0 &&
1020                     stp->ls_stateid.other[2] == 0x0) ||
1021                     (stp->ls_stateid.other[0] == 0xffffffff &&
1022                     stp->ls_stateid.other[1] == 0xffffffff &&
1023                     stp->ls_stateid.other[2] == 0xffffffff) ||
1024                     stp->ls_stateid.seqid != 0))
1025                         nd->nd_repstat = NFSERR_BADSTATEID;
1026                 /* However, allow the proxy stateid. */
1027                 if (stp->ls_stateid.seqid == 0xffffffff &&
1028                     stp->ls_stateid.other[0] == 0x55555555 &&
1029                     stp->ls_stateid.other[1] == 0x55555555 &&
1030                     stp->ls_stateid.other[2] == 0x55555555)
1031                         gotproxystateid = 1;
1032                 off = fxdr_hyper(tl);
1033                 lop->lo_first = off;
1034                 tl += 2;
1035                 stable = fxdr_unsigned(int, *tl++);
1036                 retlen = len = fxdr_unsigned(int32_t, *tl);
1037                 lop->lo_end = off + len;
1038                 /*
1039                  * Paranoia, just in case it wraps around, which shouldn't
1040                  * ever happen anyhow.
1041                  */
1042                 if (lop->lo_end < lop->lo_first)
1043                         lop->lo_end = NFS64BITSSET;
1044         }
1045
1046         if (retlen > nfs_srvmaxio || retlen < 0)
1047                 nd->nd_repstat = EIO;
1048         if (vp->v_type != VREG && !nd->nd_repstat) {
1049                 if (nd->nd_flag & ND_NFSV3)
1050                         nd->nd_repstat = EINVAL;
1051                 else
1052                         nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
1053                             EINVAL;
1054         }
1055         NFSZERO_ATTRBIT(&attrbits);
1056         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
1057         forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
1058         if (!nd->nd_repstat)
1059                 nd->nd_repstat = forat_ret;
1060         if (!nd->nd_repstat &&
1061             (forat.na_uid != nd->nd_cred->cr_uid ||
1062              NFSVNO_EXSTRICTACCESS(exp)))
1063                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
1064                     nd->nd_cred, exp, p,
1065                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
1066         /*
1067          * DS reads are marked by ND_DSSERVER or use the proxy special
1068          * stateid.
1069          */
1070         if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1071             ND_NFSV4 && gotproxystateid == 0)
1072                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1073                     &stateid, exp, nd, p);
1074         if (nd->nd_repstat) {
1075                 vput(vp);
1076                 if (nd->nd_flag & ND_NFSV3)
1077                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1078                 goto out;
1079         }
1080
1081         /*
1082          * For NFS Version 2, it is not obvious what a write of zero length
1083          * should do, but I might as well be consistent with Version 3,
1084          * which is to return ok so long as there are no permission problems.
1085          */
1086         if (retlen > 0) {
1087                 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1088                     nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1089                 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1090                 if (error)
1091                         goto nfsmout;
1092         }
1093         if (nd->nd_flag & ND_NFSV4)
1094                 aftat_ret = 0;
1095         else
1096                 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1097         vput(vp);
1098         if (!nd->nd_repstat)
1099                 nd->nd_repstat = aftat_ret;
1100         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1101                 if (nd->nd_flag & ND_NFSV3)
1102                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1103                 if (nd->nd_repstat)
1104                         goto out;
1105                 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1106                 *tl++ = txdr_unsigned(retlen);
1107                 /*
1108                  * If nfs_async is set, then pretend the write was FILESYNC.
1109                  * Warning: Doing this violates RFC1813 and runs a risk
1110                  * of data written by a client being lost when the server
1111                  * crashes/reboots.
1112                  */
1113                 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1114                         *tl++ = txdr_unsigned(stable);
1115                 else
1116                         *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1117                 /*
1118                  * Actually, there is no need to txdr these fields,
1119                  * but it may make the values more human readable,
1120                  * for debugging purposes.
1121                  */
1122                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1123                 *tl = txdr_unsigned(nfsboottime.tv_usec);
1124         } else if (!nd->nd_repstat)
1125                 nfsrv_fillattr(nd, &nva);
1126
1127 out:
1128         NFSEXITCODE2(0, nd);
1129         return (0);
1130 nfsmout:
1131         vput(vp);
1132         NFSEXITCODE2(error, nd);
1133         return (error);
1134 }
1135
1136 /*
1137  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1138  * now does a truncate to 0 length via. setattr if it already exists
1139  * The core creation routine has been extracted out into nfsrv_creatsub(),
1140  * so it can also be used by nfsrv_open() for V4.
1141  */
1142 int
1143 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1144     vnode_t dp, struct nfsexstuff *exp)
1145 {
1146         struct nfsvattr nva, dirfor, diraft;
1147         struct nfsv2_sattr *sp;
1148         struct nameidata named;
1149         u_int32_t *tl;
1150         int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1151         int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1152         NFSDEV_T rdev = 0;
1153         vnode_t vp = NULL, dirp = NULL;
1154         fhandle_t fh;
1155         char *bufp;
1156         u_long *hashp;
1157         __enum_uint8(vtype) vtyp;
1158         int32_t cverf[2], tverf[2] = { 0, 0 };
1159         struct thread *p = curthread;
1160
1161         if (nd->nd_repstat) {
1162                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1163                 goto out;
1164         }
1165         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1166             LOCKPARENT | LOCKLEAF | NOCACHE);
1167         nfsvno_setpathbuf(&named, &bufp, &hashp);
1168         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1169         if (error)
1170                 goto nfsmout;
1171         if (!nd->nd_repstat) {
1172                 NFSVNO_ATTRINIT(&nva);
1173                 if (nd->nd_flag & ND_NFSV2) {
1174                         NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1175                         vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1176                         if (vtyp == VNON)
1177                                 vtyp = VREG;
1178                         NFSVNO_SETATTRVAL(&nva, type, vtyp);
1179                         NFSVNO_SETATTRVAL(&nva, mode,
1180                             nfstov_mode(sp->sa_mode));
1181                         switch (nva.na_type) {
1182                         case VREG:
1183                                 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1184                                 if (tsize != -1)
1185                                         NFSVNO_SETATTRVAL(&nva, size,
1186                                             (u_quad_t)tsize);
1187                                 break;
1188                         case VCHR:
1189                         case VBLK:
1190                         case VFIFO:
1191                                 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1192                                 break;
1193                         default:
1194                                 break;
1195                         }
1196                 } else {
1197                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1198                         how = fxdr_unsigned(int, *tl);
1199                         switch (how) {
1200                         case NFSCREATE_GUARDED:
1201                         case NFSCREATE_UNCHECKED:
1202                                 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1203                                 if (error)
1204                                         goto nfsmout;
1205                                 break;
1206                         case NFSCREATE_EXCLUSIVE:
1207                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1208                                 cverf[0] = *tl++;
1209                                 cverf[1] = *tl;
1210                                 exclusive_flag = 1;
1211                                 break;
1212                         }
1213                         NFSVNO_SETATTRVAL(&nva, type, VREG);
1214                 }
1215         }
1216         if (nd->nd_repstat) {
1217                 nfsvno_relpathbuf(&named);
1218                 if (nd->nd_flag & ND_NFSV3) {
1219                         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1220                             NULL);
1221                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1222                             &diraft);
1223                 }
1224                 vput(dp);
1225                 goto out;
1226         }
1227
1228         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1229         if (dirp) {
1230                 if (nd->nd_flag & ND_NFSV2) {
1231                         vrele(dirp);
1232                         dirp = NULL;
1233                 } else {
1234                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1235                             NULL);
1236                 }
1237         }
1238         if (nd->nd_repstat) {
1239                 if (nd->nd_flag & ND_NFSV3)
1240                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1241                             &diraft);
1242                 if (dirp)
1243                         vrele(dirp);
1244                 goto out;
1245         }
1246
1247         if (!(nd->nd_flag & ND_NFSV2)) {
1248                 switch (how) {
1249                 case NFSCREATE_GUARDED:
1250                         if (named.ni_vp)
1251                                 nd->nd_repstat = EEXIST;
1252                         break;
1253                 case NFSCREATE_UNCHECKED:
1254                         break;
1255                 case NFSCREATE_EXCLUSIVE:
1256                         if (named.ni_vp == NULL)
1257                                 NFSVNO_SETATTRVAL(&nva, mode, 0);
1258                         break;
1259                 }
1260         }
1261
1262         /*
1263          * Iff doesn't exist, create it
1264          * otherwise just truncate to 0 length
1265          *   should I set the mode too ?
1266          */
1267         nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1268             &exclusive_flag, cverf, rdev, exp);
1269
1270         if (!nd->nd_repstat) {
1271                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1272                 if (!nd->nd_repstat)
1273                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1274                             NULL);
1275                 vput(vp);
1276                 if (!nd->nd_repstat) {
1277                         tverf[0] = nva.na_atime.tv_sec;
1278                         tverf[1] = nva.na_atime.tv_nsec;
1279                 }
1280         }
1281         if (nd->nd_flag & ND_NFSV2) {
1282                 if (!nd->nd_repstat) {
1283                         (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
1284                         nfsrv_fillattr(nd, &nva);
1285                 }
1286         } else {
1287                 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1288                     || cverf[1] != tverf[1]))
1289                         nd->nd_repstat = EEXIST;
1290                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1291                 vrele(dirp);
1292                 if (!nd->nd_repstat) {
1293                         (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1);
1294                         nfsrv_postopattr(nd, 0, &nva);
1295                 }
1296                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1297         }
1298
1299 out:
1300         NFSEXITCODE2(0, nd);
1301         return (0);
1302 nfsmout:
1303         vput(dp);
1304         nfsvno_relpathbuf(&named);
1305         NFSEXITCODE2(error, nd);
1306         return (error);
1307 }
1308
1309 /*
1310  * nfs v3 mknod service (and v4 create)
1311  */
1312 int
1313 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1314     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1315 {
1316         struct nfsvattr nva, dirfor, diraft;
1317         u_int32_t *tl;
1318         struct nameidata named;
1319         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1320         u_int32_t major, minor;
1321         __enum_uint8(vtype) vtyp = VNON;
1322         nfstype nfs4type = NFNON;
1323         vnode_t vp, dirp = NULL;
1324         nfsattrbit_t attrbits;
1325         char *bufp = NULL, *pathcp = NULL;
1326         u_long *hashp, cnflags;
1327         NFSACL_T *aclp = NULL;
1328         struct thread *p = curthread;
1329
1330         NFSVNO_ATTRINIT(&nva);
1331         cnflags = LOCKPARENT;
1332         if (nd->nd_repstat) {
1333                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1334                 goto out;
1335         }
1336 #ifdef NFS4_ACL_EXTATTR_NAME
1337         aclp = acl_alloc(M_WAITOK);
1338         aclp->acl_cnt = 0;
1339 #endif
1340
1341         /*
1342          * For V4, the creation stuff is here, Yuck!
1343          */
1344         if (nd->nd_flag & ND_NFSV4) {
1345                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1346                 vtyp = nfsv34tov_type(*tl);
1347                 nfs4type = fxdr_unsigned(nfstype, *tl);
1348                 switch (nfs4type) {
1349                 case NFLNK:
1350                         error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1351                             &pathlen);
1352                         if (error)
1353                                 goto nfsmout;
1354                         break;
1355                 case NFCHR:
1356                 case NFBLK:
1357                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1358                         major = fxdr_unsigned(u_int32_t, *tl++);
1359                         minor = fxdr_unsigned(u_int32_t, *tl);
1360                         nva.na_rdev = NFSMAKEDEV(major, minor);
1361                         break;
1362                 case NFSOCK:
1363                 case NFFIFO:
1364                         break;
1365                 case NFDIR:
1366                         cnflags = LOCKPARENT;
1367                         break;
1368                 default:
1369                         nd->nd_repstat = NFSERR_BADTYPE;
1370                         vrele(dp);
1371 #ifdef NFS4_ACL_EXTATTR_NAME
1372                         acl_free(aclp);
1373 #endif
1374                         goto out;
1375                 }
1376         }
1377         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1378         nfsvno_setpathbuf(&named, &bufp, &hashp);
1379         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1380         if (error)
1381                 goto nfsmout;
1382         if (!nd->nd_repstat) {
1383                 if (nd->nd_flag & ND_NFSV3) {
1384                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1385                         vtyp = nfsv34tov_type(*tl);
1386                 }
1387                 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1388                 if (error)
1389                         goto nfsmout;
1390                 nva.na_type = vtyp;
1391                 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1392                     (vtyp == VCHR || vtyp == VBLK)) {
1393                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1394                         major = fxdr_unsigned(u_int32_t, *tl++);
1395                         minor = fxdr_unsigned(u_int32_t, *tl);
1396                         nva.na_rdev = NFSMAKEDEV(major, minor);
1397                 }
1398         }
1399
1400         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1401         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1402                 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1403                     dirfor.na_gid == nva.na_gid)
1404                         NFSVNO_UNSET(&nva, gid);
1405                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1406         }
1407         if (nd->nd_repstat) {
1408                 vrele(dp);
1409 #ifdef NFS4_ACL_EXTATTR_NAME
1410                 acl_free(aclp);
1411 #endif
1412                 nfsvno_relpathbuf(&named);
1413                 if (pathcp)
1414                         free(pathcp, M_TEMP);
1415                 if (nd->nd_flag & ND_NFSV3)
1416                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1417                             &diraft);
1418                 goto out;
1419         }
1420
1421         /*
1422          * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1423          * in va_mode, so we'll have to set a default here.
1424          */
1425         if (NFSVNO_NOTSETMODE(&nva)) {
1426                 if (vtyp == VLNK)
1427                         nva.na_mode = 0755;
1428                 else
1429                         nva.na_mode = 0400;
1430         }
1431
1432         if (vtyp == VDIR)
1433                 named.ni_cnd.cn_flags |= WILLBEDIR;
1434         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
1435         if (nd->nd_repstat) {
1436                 if (dirp) {
1437                         if (nd->nd_flag & ND_NFSV3)
1438                                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1439                                     p, 0, NULL);
1440                         vrele(dirp);
1441                 }
1442 #ifdef NFS4_ACL_EXTATTR_NAME
1443                 acl_free(aclp);
1444 #endif
1445                 if (nd->nd_flag & ND_NFSV3)
1446                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1447                             &diraft);
1448                 goto out;
1449         }
1450         if (dirp)
1451                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1452
1453         if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1454                 if (vtyp == VDIR) {
1455                         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1456                             &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1457                             exp);
1458 #ifdef NFS4_ACL_EXTATTR_NAME
1459                         acl_free(aclp);
1460 #endif
1461                         goto out;
1462                 } else if (vtyp == VLNK) {
1463                         nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1464                             &dirfor, &diraft, &diraft_ret, &attrbits,
1465                             aclp, p, exp, pathcp, pathlen);
1466 #ifdef NFS4_ACL_EXTATTR_NAME
1467                         acl_free(aclp);
1468 #endif
1469                         free(pathcp, M_TEMP);
1470                         goto out;
1471                 }
1472         }
1473
1474         nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1475         if (!nd->nd_repstat) {
1476                 vp = named.ni_vp;
1477                 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1478                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1479                 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1480                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1481                             NULL);
1482                 if (vpp != NULL && nd->nd_repstat == 0) {
1483                         NFSVOPUNLOCK(vp);
1484                         *vpp = vp;
1485                 } else
1486                         vput(vp);
1487         }
1488
1489         diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1490         vrele(dirp);
1491         if (!nd->nd_repstat) {
1492                 if (nd->nd_flag & ND_NFSV3) {
1493                         (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
1494                         nfsrv_postopattr(nd, 0, &nva);
1495                 } else {
1496                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1497                         *tl++ = newnfs_false;
1498                         txdr_hyper(dirfor.na_filerev, tl);
1499                         tl += 2;
1500                         txdr_hyper(diraft.na_filerev, tl);
1501                         (void) nfsrv_putattrbit(nd, &attrbits);
1502                 }
1503         }
1504         if (nd->nd_flag & ND_NFSV3)
1505                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1506 #ifdef NFS4_ACL_EXTATTR_NAME
1507         acl_free(aclp);
1508 #endif
1509
1510 out:
1511         NFSEXITCODE2(0, nd);
1512         return (0);
1513 nfsmout:
1514         vrele(dp);
1515 #ifdef NFS4_ACL_EXTATTR_NAME
1516         acl_free(aclp);
1517 #endif
1518         if (bufp)
1519                 nfsvno_relpathbuf(&named);
1520         if (pathcp)
1521                 free(pathcp, M_TEMP);
1522
1523         NFSEXITCODE2(error, nd);
1524         return (error);
1525 }
1526
1527 /*
1528  * nfs remove service
1529  */
1530 int
1531 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1532     vnode_t dp, struct nfsexstuff *exp)
1533 {
1534         struct nameidata named;
1535         u_int32_t *tl;
1536         int error = 0, dirfor_ret = 1, diraft_ret = 1;
1537         vnode_t dirp = NULL;
1538         struct nfsvattr dirfor, diraft;
1539         char *bufp;
1540         u_long *hashp;
1541         struct thread *p = curthread;
1542
1543         if (nd->nd_repstat) {
1544                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1545                 goto out;
1546         }
1547         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1548             LOCKPARENT | LOCKLEAF);
1549         nfsvno_setpathbuf(&named, &bufp, &hashp);
1550         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1551         if (error) {
1552                 vput(dp);
1553                 nfsvno_relpathbuf(&named);
1554                 goto out;
1555         }
1556         if (!nd->nd_repstat) {
1557                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1558         } else {
1559                 vput(dp);
1560                 nfsvno_relpathbuf(&named);
1561         }
1562         if (dirp) {
1563                 if (!(nd->nd_flag & ND_NFSV2)) {
1564                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1565                             NULL);
1566                 } else {
1567                         vrele(dirp);
1568                         dirp = NULL;
1569                 }
1570         }
1571         if (!nd->nd_repstat) {
1572                 if (nd->nd_flag & ND_NFSV4) {
1573                         if (named.ni_vp->v_type == VDIR)
1574                                 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1575                                     nd->nd_cred, p, exp);
1576                         else
1577                                 nd->nd_repstat = nfsvno_removesub(&named, 1,
1578                                     nd->nd_cred, p, exp);
1579                 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1580                         nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1581                             nd->nd_cred, p, exp);
1582                 } else {
1583                         nd->nd_repstat = nfsvno_removesub(&named, 0,
1584                             nd->nd_cred, p, exp);
1585                 }
1586         }
1587         if (!(nd->nd_flag & ND_NFSV2)) {
1588                 if (dirp) {
1589                         diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1590                             NULL);
1591                         vrele(dirp);
1592                 }
1593                 if (nd->nd_flag & ND_NFSV3) {
1594                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1595                             &diraft);
1596                 } else if (!nd->nd_repstat) {
1597                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1598                         *tl++ = newnfs_false;
1599                         txdr_hyper(dirfor.na_filerev, tl);
1600                         tl += 2;
1601                         txdr_hyper(diraft.na_filerev, tl);
1602                 }
1603         }
1604
1605 out:
1606         NFSEXITCODE2(error, nd);
1607         return (error);
1608 }
1609
1610 /*
1611  * nfs rename service
1612  */
1613 int
1614 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1615     vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1616 {
1617         u_int32_t *tl;
1618         int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1619         int tdirfor_ret = 1, tdiraft_ret = 1;
1620         struct nameidata fromnd, tond;
1621         vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1622         struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1623         struct nfsexstuff tnes;
1624         struct nfsrvfh tfh;
1625         char *bufp, *tbufp = NULL;
1626         u_long *hashp;
1627         fhandle_t fh;
1628         struct thread *p = curthread;
1629
1630         if (nd->nd_repstat) {
1631                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1632                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1633                 goto out;
1634         }
1635         if (!(nd->nd_flag & ND_NFSV2))
1636                 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1637         tond.ni_cnd.cn_nameiop = 0;
1638         tond.ni_startdir = NULL;
1639         NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT);
1640         nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1641         error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1642         if (error) {
1643                 vput(dp);
1644                 if (todp)
1645                         vrele(todp);
1646                 nfsvno_relpathbuf(&fromnd);
1647                 goto out;
1648         }
1649         /*
1650          * Unlock dp in this code section, so it is unlocked before
1651          * tdp gets locked. This avoids a potential LOR if tdp is the
1652          * parent directory of dp.
1653          */
1654         if (nd->nd_flag & ND_NFSV4) {
1655                 tdp = todp;
1656                 tnes = *toexp;
1657                 if (dp != tdp) {
1658                         NFSVOPUNLOCK(dp);
1659                         /* Might lock tdp. */
1660                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1661                             NULL);
1662                 } else {
1663                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1664                             NULL);
1665                         NFSVOPUNLOCK(dp);
1666                 }
1667         } else {
1668                 tfh.nfsrvfh_len = 0;
1669                 error = nfsrv_mtofh(nd, &tfh);
1670                 if (error == 0)
1671                         error = nfsvno_getfh(dp, &fh, p);
1672                 if (error) {
1673                         vput(dp);
1674                         /* todp is always NULL except NFSv4 */
1675                         nfsvno_relpathbuf(&fromnd);
1676                         goto out;
1677                 }
1678
1679                 /* If this is the same file handle, just VREF() the vnode. */
1680                 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1681                     !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1682                         VREF(dp);
1683                         tdp = dp;
1684                         tnes = *exp;
1685                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1686                             NULL);
1687                         NFSVOPUNLOCK(dp);
1688                 } else {
1689                         NFSVOPUNLOCK(dp);
1690                         nd->nd_cred->cr_uid = nd->nd_saveduid;
1691                         nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1692                             0, -1);     /* Locks tdp. */
1693                         if (tdp) {
1694                                 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1695                                     p, 1, NULL);
1696                                 NFSVOPUNLOCK(tdp);
1697                         }
1698                 }
1699         }
1700         NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE);
1701         nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1702         if (!nd->nd_repstat) {
1703                 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1704                 if (error) {
1705                         if (tdp)
1706                                 vrele(tdp);
1707                         vrele(dp);
1708                         nfsvno_relpathbuf(&fromnd);
1709                         nfsvno_relpathbuf(&tond);
1710                         goto out;
1711                 }
1712         }
1713         if (nd->nd_repstat) {
1714                 if (nd->nd_flag & ND_NFSV3) {
1715                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1716                             &fdiraft);
1717                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1718                             &tdiraft);
1719                 }
1720                 if (tdp)
1721                         vrele(tdp);
1722                 vrele(dp);
1723                 nfsvno_relpathbuf(&fromnd);
1724                 nfsvno_relpathbuf(&tond);
1725                 goto out;
1726         }
1727
1728         /*
1729          * Done parsing, now down to business.
1730          */
1731         nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp);
1732         if (nd->nd_repstat) {
1733                 if (nd->nd_flag & ND_NFSV3) {
1734                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1735                             &fdiraft);
1736                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1737                             &tdiraft);
1738                 }
1739                 if (fdirp)
1740                         vrele(fdirp);
1741                 if (tdp)
1742                         vrele(tdp);
1743                 nfsvno_relpathbuf(&tond);
1744                 goto out;
1745         }
1746         if (fromnd.ni_vp->v_type == VDIR)
1747                 tond.ni_cnd.cn_flags |= WILLBEDIR;
1748         nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp);
1749         nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1750             nd->nd_flag, nd->nd_cred, p);
1751         if (fdirp)
1752                 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1753         if (tdirp)
1754                 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1755         if (fdirp)
1756                 vrele(fdirp);
1757         if (tdirp)
1758                 vrele(tdirp);
1759         if (nd->nd_flag & ND_NFSV3) {
1760                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1761                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1762         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1763                 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1764                 *tl++ = newnfs_false;
1765                 txdr_hyper(fdirfor.na_filerev, tl);
1766                 tl += 2;
1767                 txdr_hyper(fdiraft.na_filerev, tl);
1768                 tl += 2;
1769                 *tl++ = newnfs_false;
1770                 txdr_hyper(tdirfor.na_filerev, tl);
1771                 tl += 2;
1772                 txdr_hyper(tdiraft.na_filerev, tl);
1773         }
1774
1775 out:
1776         NFSEXITCODE2(error, nd);
1777         return (error);
1778 }
1779
1780 /*
1781  * nfs link service
1782  */
1783 int
1784 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1785     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1786 {
1787         struct nameidata named;
1788         u_int32_t *tl;
1789         int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1790         vnode_t dirp = NULL, dp = NULL;
1791         struct nfsvattr dirfor, diraft, at;
1792         struct nfsexstuff tnes;
1793         struct nfsrvfh dfh;
1794         char *bufp;
1795         u_long *hashp;
1796         struct thread *p = curthread;
1797
1798         if (nd->nd_repstat) {
1799                 nfsrv_postopattr(nd, getret, &at);
1800                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1801                 goto out;
1802         }
1803         NFSVOPUNLOCK(vp);
1804         if (vp->v_type == VDIR) {
1805                 if (nd->nd_flag & ND_NFSV4)
1806                         nd->nd_repstat = NFSERR_ISDIR;
1807                 else
1808                         nd->nd_repstat = NFSERR_INVAL;
1809                 if (tovp)
1810                         vrele(tovp);
1811         }
1812         if (!nd->nd_repstat) {
1813                 if (nd->nd_flag & ND_NFSV4) {
1814                         dp = tovp;
1815                         tnes = *toexp;
1816                 } else {
1817                         error = nfsrv_mtofh(nd, &dfh);
1818                         if (error) {
1819                                 vrele(vp);
1820                                 /* tovp is always NULL unless NFSv4 */
1821                                 goto out;
1822                         }
1823                         nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL,
1824                             0, -1);
1825                         if (dp)
1826                                 NFSVOPUNLOCK(dp);
1827                 }
1828         }
1829         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
1830         if (!nd->nd_repstat) {
1831                 nfsvno_setpathbuf(&named, &bufp, &hashp);
1832                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1833                 if (error) {
1834                         vrele(vp);
1835                         if (dp)
1836                                 vrele(dp);
1837                         nfsvno_relpathbuf(&named);
1838                         goto out;
1839                 }
1840                 if (!nd->nd_repstat) {
1841                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1842                             &dirp);
1843                 } else {
1844                         if (dp)
1845                                 vrele(dp);
1846                         nfsvno_relpathbuf(&named);
1847                 }
1848         }
1849         if (dirp) {
1850                 if (nd->nd_flag & ND_NFSV2) {
1851                         vrele(dirp);
1852                         dirp = NULL;
1853                 } else {
1854                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1855                             NULL);
1856                 }
1857         }
1858         if (!nd->nd_repstat)
1859                 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1860         if (nd->nd_flag & ND_NFSV3)
1861                 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1862         if (dirp) {
1863                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1864                 vrele(dirp);
1865         }
1866         vrele(vp);
1867         if (nd->nd_flag & ND_NFSV3) {
1868                 nfsrv_postopattr(nd, getret, &at);
1869                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1870         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1871                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1872                 *tl++ = newnfs_false;
1873                 txdr_hyper(dirfor.na_filerev, tl);
1874                 tl += 2;
1875                 txdr_hyper(diraft.na_filerev, tl);
1876         }
1877
1878 out:
1879         NFSEXITCODE2(error, nd);
1880         return (error);
1881 }
1882
1883 /*
1884  * nfs symbolic link service
1885  */
1886 int
1887 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1888     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1889 {
1890         struct nfsvattr nva, dirfor, diraft;
1891         struct nameidata named;
1892         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1893         vnode_t dirp = NULL;
1894         char *bufp, *pathcp = NULL;
1895         u_long *hashp;
1896         struct thread *p = curthread;
1897
1898         if (nd->nd_repstat) {
1899                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1900                 goto out;
1901         }
1902         if (vpp)
1903                 *vpp = NULL;
1904         NFSVNO_ATTRINIT(&nva);
1905         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1906             LOCKPARENT | NOCACHE);
1907         nfsvno_setpathbuf(&named, &bufp, &hashp);
1908         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1909         if (!error && !nd->nd_repstat)
1910                 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1911         if (error) {
1912                 vrele(dp);
1913                 nfsvno_relpathbuf(&named);
1914                 goto out;
1915         }
1916         if (!nd->nd_repstat) {
1917                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
1918         } else {
1919                 vrele(dp);
1920                 nfsvno_relpathbuf(&named);
1921         }
1922         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1923                 vrele(dirp);
1924                 dirp = NULL;
1925         }
1926
1927         /*
1928          * And call nfsrvd_symlinksub() to do the common code. It will
1929          * return EBADRPC upon a parsing error, 0 otherwise.
1930          */
1931         if (!nd->nd_repstat) {
1932                 if (dirp != NULL)
1933                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1934                             NULL);
1935                 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1936                     &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1937                     pathcp, pathlen);
1938         } else if (dirp != NULL) {
1939                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1940                 vrele(dirp);
1941         }
1942         if (pathcp)
1943                 free(pathcp, M_TEMP);
1944
1945         if (nd->nd_flag & ND_NFSV3) {
1946                 if (!nd->nd_repstat) {
1947                         (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
1948                         nfsrv_postopattr(nd, 0, &nva);
1949                 }
1950                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1951         }
1952
1953 out:
1954         NFSEXITCODE2(error, nd);
1955         return (error);
1956 }
1957
1958 /*
1959  * Common code for creating a symbolic link.
1960  */
1961 static void
1962 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1963     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1964     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1965     int *diraft_retp, nfsattrbit_t *attrbitp,
1966     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1967     int pathlen)
1968 {
1969         u_int32_t *tl;
1970
1971         nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1972             !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1973         if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1974                 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1975                 if (nd->nd_flag & ND_NFSV3) {
1976                         nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1977                         if (!nd->nd_repstat)
1978                                 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1979                                     nvap, nd, p, 1, NULL);
1980                 }
1981                 if (vpp != NULL && nd->nd_repstat == 0) {
1982                         NFSVOPUNLOCK(ndp->ni_vp);
1983                         *vpp = ndp->ni_vp;
1984                 } else
1985                         vput(ndp->ni_vp);
1986         }
1987         if (dirp) {
1988                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
1989                 vrele(dirp);
1990         }
1991         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1992                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1993                 *tl++ = newnfs_false;
1994                 txdr_hyper(dirforp->na_filerev, tl);
1995                 tl += 2;
1996                 txdr_hyper(diraftp->na_filerev, tl);
1997                 (void) nfsrv_putattrbit(nd, attrbitp);
1998         }
1999
2000         NFSEXITCODE2(0, nd);
2001 }
2002
2003 /*
2004  * nfs mkdir service
2005  */
2006 int
2007 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
2008     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
2009 {
2010         struct nfsvattr nva, dirfor, diraft;
2011         struct nameidata named;
2012         u_int32_t *tl;
2013         int error = 0, dirfor_ret = 1, diraft_ret = 1;
2014         vnode_t dirp = NULL;
2015         char *bufp;
2016         u_long *hashp;
2017         struct thread *p = curthread;
2018
2019         if (nd->nd_repstat) {
2020                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2021                 goto out;
2022         }
2023         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
2024         nfsvno_setpathbuf(&named, &bufp, &hashp);
2025         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2026         if (error)
2027                 goto nfsmout;
2028         if (!nd->nd_repstat) {
2029                 NFSVNO_ATTRINIT(&nva);
2030                 if (nd->nd_flag & ND_NFSV3) {
2031                         error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
2032                         if (error)
2033                                 goto nfsmout;
2034                 } else {
2035                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2036                         nva.na_mode = nfstov_mode(*tl++);
2037                 }
2038         }
2039         if (!nd->nd_repstat) {
2040                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
2041         } else {
2042                 vrele(dp);
2043                 nfsvno_relpathbuf(&named);
2044         }
2045         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2046                 vrele(dirp);
2047                 dirp = NULL;
2048         }
2049         if (nd->nd_repstat) {
2050                 if (dirp != NULL) {
2051                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2052                             NULL);
2053                         vrele(dirp);
2054                 }
2055                 if (nd->nd_flag & ND_NFSV3)
2056                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
2057                             &diraft);
2058                 goto out;
2059         }
2060         if (dirp != NULL)
2061                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2062
2063         /*
2064          * Call nfsrvd_mkdirsub() for the code common to V4 as well.
2065          */
2066         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
2067             &diraft_ret, NULL, NULL, p, exp);
2068
2069         if (nd->nd_flag & ND_NFSV3) {
2070                 if (!nd->nd_repstat) {
2071                         (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
2072                         nfsrv_postopattr(nd, 0, &nva);
2073                 }
2074                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2075         } else if (!nd->nd_repstat) {
2076                 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
2077                 nfsrv_fillattr(nd, &nva);
2078         }
2079
2080 out:
2081         NFSEXITCODE2(0, nd);
2082         return (0);
2083 nfsmout:
2084         vrele(dp);
2085         nfsvno_relpathbuf(&named);
2086         NFSEXITCODE2(error, nd);
2087         return (error);
2088 }
2089
2090 /*
2091  * Code common to mkdir for V2,3 and 4.
2092  */
2093 static void
2094 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2095     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2096     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2097     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2098     NFSPROC_T *p, struct nfsexstuff *exp)
2099 {
2100         vnode_t vp;
2101         u_int32_t *tl;
2102
2103         NFSVNO_SETATTRVAL(nvap, type, VDIR);
2104         nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2105             nd->nd_cred, p, exp);
2106         if (!nd->nd_repstat) {
2107                 vp = ndp->ni_vp;
2108                 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2109                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2110                 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2111                         nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2112                             NULL);
2113                 if (vpp && !nd->nd_repstat) {
2114                         NFSVOPUNLOCK(vp);
2115                         *vpp = vp;
2116                 } else {
2117                         vput(vp);
2118                 }
2119         }
2120         if (dirp) {
2121                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2122                 vrele(dirp);
2123         }
2124         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2125                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2126                 *tl++ = newnfs_false;
2127                 txdr_hyper(dirforp->na_filerev, tl);
2128                 tl += 2;
2129                 txdr_hyper(diraftp->na_filerev, tl);
2130                 (void) nfsrv_putattrbit(nd, attrbitp);
2131         }
2132
2133         NFSEXITCODE2(0, nd);
2134 }
2135
2136 /*
2137  * nfs commit service
2138  */
2139 int
2140 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2141     vnode_t vp, __unused struct nfsexstuff *exp)
2142 {
2143         struct nfsvattr bfor, aft;
2144         u_int32_t *tl;
2145         int error = 0, for_ret = 1, aft_ret = 1, cnt;
2146         u_int64_t off;
2147         struct thread *p = curthread;
2148
2149        if (nd->nd_repstat) {
2150                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2151                 goto out;
2152         }
2153
2154         /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2155         if (vp->v_type != VREG) {
2156                 if (nd->nd_flag & ND_NFSV3)
2157                         error = NFSERR_NOTSUPP;
2158                 else
2159                         error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2160                 goto nfsmout;
2161         }
2162         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2163
2164         /*
2165          * XXX At this time VOP_FSYNC() does not accept offset and byte
2166          * count parameters, so these arguments are useless (someday maybe).
2167          */
2168         off = fxdr_hyper(tl);
2169         tl += 2;
2170         cnt = fxdr_unsigned(int, *tl);
2171         if (nd->nd_flag & ND_NFSV3)
2172                 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2173         nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2174         if (nd->nd_flag & ND_NFSV3) {
2175                 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2176                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2177         }
2178         vput(vp);
2179         if (!nd->nd_repstat) {
2180                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2181                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
2182                 *tl = txdr_unsigned(nfsboottime.tv_usec);
2183         }
2184
2185 out:
2186         NFSEXITCODE2(0, nd);
2187         return (0);
2188 nfsmout:
2189         vput(vp);
2190         NFSEXITCODE2(error, nd);
2191         return (error);
2192 }
2193
2194 /*
2195  * nfs statfs service
2196  */
2197 int
2198 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2199     vnode_t vp, __unused struct nfsexstuff *exp)
2200 {
2201         struct statfs *sf;
2202         u_int32_t *tl;
2203         int getret = 1;
2204         struct nfsvattr at;
2205         u_quad_t tval;
2206         struct thread *p = curthread;
2207
2208         sf = NULL;
2209         if (nd->nd_repstat) {
2210                 nfsrv_postopattr(nd, getret, &at);
2211                 goto out;
2212         }
2213         sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2214         nd->nd_repstat = nfsvno_statfs(vp, sf);
2215         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2216         vput(vp);
2217         if (nd->nd_flag & ND_NFSV3)
2218                 nfsrv_postopattr(nd, getret, &at);
2219         if (nd->nd_repstat)
2220                 goto out;
2221         if (nd->nd_flag & ND_NFSV2) {
2222                 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2223                 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2224                 *tl++ = txdr_unsigned(sf->f_bsize);
2225                 *tl++ = txdr_unsigned(sf->f_blocks);
2226                 *tl++ = txdr_unsigned(sf->f_bfree);
2227                 *tl = txdr_unsigned(sf->f_bavail);
2228         } else {
2229                 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2230                 tval = (u_quad_t)sf->f_blocks;
2231                 tval *= (u_quad_t)sf->f_bsize;
2232                 txdr_hyper(tval, tl); tl += 2;
2233                 tval = (u_quad_t)sf->f_bfree;
2234                 tval *= (u_quad_t)sf->f_bsize;
2235                 txdr_hyper(tval, tl); tl += 2;
2236                 tval = (u_quad_t)sf->f_bavail;
2237                 tval *= (u_quad_t)sf->f_bsize;
2238                 txdr_hyper(tval, tl); tl += 2;
2239                 tval = (u_quad_t)sf->f_files;
2240                 txdr_hyper(tval, tl); tl += 2;
2241                 tval = (u_quad_t)sf->f_ffree;
2242                 txdr_hyper(tval, tl); tl += 2;
2243                 tval = (u_quad_t)sf->f_ffree;
2244                 txdr_hyper(tval, tl); tl += 2;
2245                 *tl = 0;
2246         }
2247
2248 out:
2249         free(sf, M_STATFS);
2250         NFSEXITCODE2(0, nd);
2251         return (0);
2252 }
2253
2254 /*
2255  * nfs fsinfo service
2256  */
2257 int
2258 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2259     vnode_t vp, __unused struct nfsexstuff *exp)
2260 {
2261         u_int32_t *tl;
2262         struct nfsfsinfo fs;
2263         int getret = 1;
2264         struct nfsvattr at;
2265         struct thread *p = curthread;
2266
2267         if (nd->nd_repstat) {
2268                 nfsrv_postopattr(nd, getret, &at);
2269                 goto out;
2270         }
2271         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2272         nfsvno_getfs(&fs, isdgram);
2273         vput(vp);
2274         nfsrv_postopattr(nd, getret, &at);
2275         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2276         *tl++ = txdr_unsigned(fs.fs_rtmax);
2277         *tl++ = txdr_unsigned(fs.fs_rtpref);
2278         *tl++ = txdr_unsigned(fs.fs_rtmult);
2279         *tl++ = txdr_unsigned(fs.fs_wtmax);
2280         *tl++ = txdr_unsigned(fs.fs_wtpref);
2281         *tl++ = txdr_unsigned(fs.fs_wtmult);
2282         *tl++ = txdr_unsigned(fs.fs_dtpref);
2283         txdr_hyper(fs.fs_maxfilesize, tl);
2284         tl += 2;
2285         txdr_nfsv3time(&fs.fs_timedelta, tl);
2286         tl += 2;
2287         *tl = txdr_unsigned(fs.fs_properties);
2288
2289 out:
2290         NFSEXITCODE2(0, nd);
2291         return (0);
2292 }
2293
2294 /*
2295  * nfs pathconf service
2296  */
2297 int
2298 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2299     vnode_t vp, __unused struct nfsexstuff *exp)
2300 {
2301         struct nfsv3_pathconf *pc;
2302         int getret = 1;
2303         long linkmax, namemax, chownres, notrunc;
2304         struct nfsvattr at;
2305         struct thread *p = curthread;
2306
2307         if (nd->nd_repstat) {
2308                 nfsrv_postopattr(nd, getret, &at);
2309                 goto out;
2310         }
2311         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2312             nd->nd_cred, p);
2313         if (!nd->nd_repstat)
2314                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2315                     nd->nd_cred, p);
2316         if (!nd->nd_repstat)
2317                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2318                     &chownres, nd->nd_cred, p);
2319         if (!nd->nd_repstat)
2320                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2321                     nd->nd_cred, p);
2322         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2323         vput(vp);
2324         nfsrv_postopattr(nd, getret, &at);
2325         if (!nd->nd_repstat) {
2326                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2327                 pc->pc_linkmax = txdr_unsigned(linkmax);
2328                 pc->pc_namemax = txdr_unsigned(namemax);
2329                 pc->pc_notrunc = txdr_unsigned(notrunc);
2330                 pc->pc_chownrestricted = txdr_unsigned(chownres);
2331
2332                 /*
2333                  * These should probably be supported by VOP_PATHCONF(), but
2334                  * until msdosfs is exportable (why would you want to?), the
2335                  * Unix defaults should be ok.
2336                  */
2337                 pc->pc_caseinsensitive = newnfs_false;
2338                 pc->pc_casepreserving = newnfs_true;
2339         }
2340
2341 out:
2342         NFSEXITCODE2(0, nd);
2343         return (0);
2344 }
2345
2346 /*
2347  * nfsv4 lock service
2348  */
2349 int
2350 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2351     vnode_t vp, struct nfsexstuff *exp)
2352 {
2353         u_int32_t *tl;
2354         int i;
2355         struct nfsstate *stp = NULL;
2356         struct nfslock *lop;
2357         struct nfslockconflict cf;
2358         int error = 0;
2359         u_short flags = NFSLCK_LOCK, lflags;
2360         u_int64_t offset, len;
2361         nfsv4stateid_t stateid;
2362         nfsquad_t clientid;
2363         struct thread *p = curthread;
2364
2365         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2366         i = fxdr_unsigned(int, *tl++);
2367         switch (i) {
2368         case NFSV4LOCKT_READW:
2369                 flags |= NFSLCK_BLOCKING;
2370         case NFSV4LOCKT_READ:
2371                 lflags = NFSLCK_READ;
2372                 break;
2373         case NFSV4LOCKT_WRITEW:
2374                 flags |= NFSLCK_BLOCKING;
2375         case NFSV4LOCKT_WRITE:
2376                 lflags = NFSLCK_WRITE;
2377                 break;
2378         default:
2379                 nd->nd_repstat = NFSERR_BADXDR;
2380                 goto nfsmout;
2381         }
2382         if (*tl++ == newnfs_true)
2383                 flags |= NFSLCK_RECLAIM;
2384         offset = fxdr_hyper(tl);
2385         tl += 2;
2386         len = fxdr_hyper(tl);
2387         tl += 2;
2388         if (*tl == newnfs_true)
2389                 flags |= NFSLCK_OPENTOLOCK;
2390         if (flags & NFSLCK_OPENTOLOCK) {
2391                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2392                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2393                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2394                         nd->nd_repstat = NFSERR_BADXDR;
2395                         goto nfsmout;
2396                 }
2397                 stp = malloc(sizeof (struct nfsstate) + i,
2398                         M_NFSDSTATE, M_WAITOK);
2399                 stp->ls_ownerlen = i;
2400                 stp->ls_op = nd->nd_rp;
2401                 stp->ls_seq = fxdr_unsigned(int, *tl++);
2402                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2403                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2404                         NFSX_STATEIDOTHER);
2405                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2406
2407                 /*
2408                  * For the special stateid of other all 0s and seqid == 1, set
2409                  * the stateid to the current stateid, if it is set.
2410                  */
2411                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2412                     stp->ls_stateid.seqid == 1 &&
2413                     stp->ls_stateid.other[0] == 0 &&
2414                     stp->ls_stateid.other[1] == 0 &&
2415                     stp->ls_stateid.other[2] == 0) {
2416                         if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2417                                 stp->ls_stateid = nd->nd_curstateid;
2418                                 stp->ls_stateid.seqid = 0;
2419                         } else {
2420                                 nd->nd_repstat = NFSERR_BADSTATEID;
2421                                 goto nfsmout;
2422                         }
2423                 }
2424
2425                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2426                 clientid.lval[0] = *tl++;
2427                 clientid.lval[1] = *tl++;
2428                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2429                         if ((nd->nd_flag & ND_NFSV41) != 0)
2430                                 clientid.qval = nd->nd_clientid.qval;
2431                         else if (nd->nd_clientid.qval != clientid.qval)
2432                                 printf("EEK3 multiple clids\n");
2433                 } else {
2434                         if ((nd->nd_flag & ND_NFSV41) != 0)
2435                                 printf("EEK! no clientid from session\n");
2436                         nd->nd_flag |= ND_IMPLIEDCLID;
2437                         nd->nd_clientid.qval = clientid.qval;
2438                 }
2439                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2440                 if (error)
2441                         goto nfsmout;
2442         } else {
2443                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2444                 stp = malloc(sizeof (struct nfsstate),
2445                         M_NFSDSTATE, M_WAITOK);
2446                 stp->ls_ownerlen = 0;
2447                 stp->ls_op = nd->nd_rp;
2448                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2449                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2450                         NFSX_STATEIDOTHER);
2451                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2452
2453                 /*
2454                  * For the special stateid of other all 0s and seqid == 1, set
2455                  * the stateid to the current stateid, if it is set.
2456                  */
2457                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
2458                     stp->ls_stateid.seqid == 1 &&
2459                     stp->ls_stateid.other[0] == 0 &&
2460                     stp->ls_stateid.other[1] == 0 &&
2461                     stp->ls_stateid.other[2] == 0) {
2462                         if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2463                                 stp->ls_stateid = nd->nd_curstateid;
2464                                 stp->ls_stateid.seqid = 0;
2465                         } else {
2466                                 nd->nd_repstat = NFSERR_BADSTATEID;
2467                                 goto nfsmout;
2468                         }
2469                 }
2470
2471                 stp->ls_seq = fxdr_unsigned(int, *tl);
2472                 clientid.lval[0] = stp->ls_stateid.other[0];
2473                 clientid.lval[1] = stp->ls_stateid.other[1];
2474                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2475                         if ((nd->nd_flag & ND_NFSV41) != 0)
2476                                 clientid.qval = nd->nd_clientid.qval;
2477                         else if (nd->nd_clientid.qval != clientid.qval)
2478                                 printf("EEK4 multiple clids\n");
2479                 } else {
2480                         if ((nd->nd_flag & ND_NFSV41) != 0)
2481                                 printf("EEK! no clientid from session\n");
2482                         nd->nd_flag |= ND_IMPLIEDCLID;
2483                         nd->nd_clientid.qval = clientid.qval;
2484                 }
2485         }
2486         lop = malloc(sizeof (struct nfslock),
2487                 M_NFSDLOCK, M_WAITOK);
2488         lop->lo_first = offset;
2489         if (len == NFS64BITSSET) {
2490                 lop->lo_end = NFS64BITSSET;
2491         } else {
2492                 lop->lo_end = offset + len;
2493                 if (lop->lo_end <= lop->lo_first)
2494                         nd->nd_repstat = NFSERR_INVAL;
2495         }
2496         lop->lo_flags = lflags;
2497         stp->ls_flags = flags;
2498         stp->ls_uid = nd->nd_cred->cr_uid;
2499
2500         /*
2501          * Do basic access checking.
2502          */
2503         if (!nd->nd_repstat && vp->v_type != VREG) {
2504             if (vp->v_type == VDIR)
2505                 nd->nd_repstat = NFSERR_ISDIR;
2506             else
2507                 nd->nd_repstat = NFSERR_INVAL;
2508         }
2509         if (!nd->nd_repstat) {
2510             if (lflags & NFSLCK_WRITE) {
2511                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2512                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2513                     NFSACCCHK_VPISLOCKED, NULL);
2514             } else {
2515                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2516                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2517                     NFSACCCHK_VPISLOCKED, NULL);
2518                 if (nd->nd_repstat)
2519                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2520                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2521                         NFSACCCHK_VPISLOCKED, NULL);
2522             }
2523         }
2524
2525         /*
2526          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2527          * seqid# gets updated. nfsrv_lockctrl() will return the value
2528          * of nd_repstat, if it gets that far.
2529          */
2530         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
2531                 &stateid, exp, nd, p);
2532         if (lop)
2533                 free(lop, M_NFSDLOCK);
2534         if (stp)
2535                 free(stp, M_NFSDSTATE);
2536         if (!nd->nd_repstat) {
2537                 /* For NFSv4.1, set the Current StateID. */
2538                 if ((nd->nd_flag & ND_NFSV41) != 0) {
2539                         nd->nd_curstateid = stateid;
2540                         nd->nd_flag |= ND_CURSTATEID;
2541                 }
2542                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2543                 *tl++ = txdr_unsigned(stateid.seqid);
2544                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2545         } else if (nd->nd_repstat == NFSERR_DENIED) {
2546                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2547                 txdr_hyper(cf.cl_first, tl);
2548                 tl += 2;
2549                 if (cf.cl_end == NFS64BITSSET)
2550                         len = NFS64BITSSET;
2551                 else
2552                         len = cf.cl_end - cf.cl_first;
2553                 txdr_hyper(len, tl);
2554                 tl += 2;
2555                 if (cf.cl_flags == NFSLCK_WRITE)
2556                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2557                 else
2558                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2559                 *tl++ = stateid.other[0];
2560                 *tl = stateid.other[1];
2561                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2562         }
2563         vput(vp);
2564         NFSEXITCODE2(0, nd);
2565         return (0);
2566 nfsmout:
2567         vput(vp);
2568         if (stp)
2569                 free(stp, M_NFSDSTATE);
2570         NFSEXITCODE2(error, nd);
2571         return (error);
2572 }
2573
2574 /*
2575  * nfsv4 lock test service
2576  */
2577 int
2578 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2579     vnode_t vp, struct nfsexstuff *exp)
2580 {
2581         u_int32_t *tl;
2582         int i;
2583         struct nfsstate *stp = NULL;
2584         struct nfslock lo, *lop = &lo;
2585         struct nfslockconflict cf;
2586         int error = 0;
2587         nfsv4stateid_t stateid;
2588         nfsquad_t clientid;
2589         u_int64_t len;
2590         struct thread *p = curthread;
2591
2592         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2593         i = fxdr_unsigned(int, *(tl + 7));
2594         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2595                 nd->nd_repstat = NFSERR_BADXDR;
2596                 goto nfsmout;
2597         }
2598         stp = malloc(sizeof (struct nfsstate) + i,
2599             M_NFSDSTATE, M_WAITOK);
2600         stp->ls_ownerlen = i;
2601         stp->ls_op = NULL;
2602         stp->ls_flags = NFSLCK_TEST;
2603         stp->ls_uid = nd->nd_cred->cr_uid;
2604         i = fxdr_unsigned(int, *tl++);
2605         switch (i) {
2606         case NFSV4LOCKT_READW:
2607                 stp->ls_flags |= NFSLCK_BLOCKING;
2608         case NFSV4LOCKT_READ:
2609                 lo.lo_flags = NFSLCK_READ;
2610                 break;
2611         case NFSV4LOCKT_WRITEW:
2612                 stp->ls_flags |= NFSLCK_BLOCKING;
2613         case NFSV4LOCKT_WRITE:
2614                 lo.lo_flags = NFSLCK_WRITE;
2615                 break;
2616         default:
2617                 nd->nd_repstat = NFSERR_BADXDR;
2618                 goto nfsmout;
2619         }
2620         lo.lo_first = fxdr_hyper(tl);
2621         tl += 2;
2622         len = fxdr_hyper(tl);
2623         if (len == NFS64BITSSET) {
2624                 lo.lo_end = NFS64BITSSET;
2625         } else {
2626                 lo.lo_end = lo.lo_first + len;
2627                 if (lo.lo_end <= lo.lo_first)
2628                         nd->nd_repstat = NFSERR_INVAL;
2629         }
2630         tl += 2;
2631         clientid.lval[0] = *tl++;
2632         clientid.lval[1] = *tl;
2633         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2634                 if ((nd->nd_flag & ND_NFSV41) != 0)
2635                         clientid.qval = nd->nd_clientid.qval;
2636                 else if (nd->nd_clientid.qval != clientid.qval)
2637                         printf("EEK5 multiple clids\n");
2638         } else {
2639                 if ((nd->nd_flag & ND_NFSV41) != 0)
2640                         printf("EEK! no clientid from session\n");
2641                 nd->nd_flag |= ND_IMPLIEDCLID;
2642                 nd->nd_clientid.qval = clientid.qval;
2643         }
2644         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2645         if (error)
2646                 goto nfsmout;
2647         if (!nd->nd_repstat && vp->v_type != VREG) {
2648             if (vp->v_type == VDIR)
2649                 nd->nd_repstat = NFSERR_ISDIR;
2650             else
2651                 nd->nd_repstat = NFSERR_INVAL;
2652         }
2653         if (!nd->nd_repstat)
2654           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2655             &stateid, exp, nd, p);
2656         if (nd->nd_repstat) {
2657             if (nd->nd_repstat == NFSERR_DENIED) {
2658                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2659                 txdr_hyper(cf.cl_first, tl);
2660                 tl += 2;
2661                 if (cf.cl_end == NFS64BITSSET)
2662                         len = NFS64BITSSET;
2663                 else
2664                         len = cf.cl_end - cf.cl_first;
2665                 txdr_hyper(len, tl);
2666                 tl += 2;
2667                 if (cf.cl_flags == NFSLCK_WRITE)
2668                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2669                 else
2670                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2671                 *tl++ = stp->ls_stateid.other[0];
2672                 *tl = stp->ls_stateid.other[1];
2673                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2674             }
2675         }
2676         vput(vp);
2677         if (stp)
2678                 free(stp, M_NFSDSTATE);
2679         NFSEXITCODE2(0, nd);
2680         return (0);
2681 nfsmout:
2682         vput(vp);
2683         if (stp)
2684                 free(stp, M_NFSDSTATE);
2685         NFSEXITCODE2(error, nd);
2686         return (error);
2687 }
2688
2689 /*
2690  * nfsv4 unlock service
2691  */
2692 int
2693 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2694     vnode_t vp, struct nfsexstuff *exp)
2695 {
2696         u_int32_t *tl;
2697         int i;
2698         struct nfsstate *stp;
2699         struct nfslock *lop;
2700         int error = 0;
2701         nfsv4stateid_t stateid;
2702         nfsquad_t clientid;
2703         u_int64_t len;
2704         struct thread *p = curthread;
2705
2706         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2707         stp = malloc(sizeof (struct nfsstate),
2708             M_NFSDSTATE, M_WAITOK);
2709         lop = malloc(sizeof (struct nfslock),
2710             M_NFSDLOCK, M_WAITOK);
2711         stp->ls_flags = NFSLCK_UNLOCK;
2712         lop->lo_flags = NFSLCK_UNLOCK;
2713         stp->ls_op = nd->nd_rp;
2714         i = fxdr_unsigned(int, *tl++);
2715         switch (i) {
2716         case NFSV4LOCKT_READW:
2717                 stp->ls_flags |= NFSLCK_BLOCKING;
2718         case NFSV4LOCKT_READ:
2719                 break;
2720         case NFSV4LOCKT_WRITEW:
2721                 stp->ls_flags |= NFSLCK_BLOCKING;
2722         case NFSV4LOCKT_WRITE:
2723                 break;
2724         default:
2725                 nd->nd_repstat = NFSERR_BADXDR;
2726                 free(stp, M_NFSDSTATE);
2727                 free(lop, M_NFSDLOCK);
2728                 goto nfsmout;
2729         }
2730         stp->ls_ownerlen = 0;
2731         stp->ls_uid = nd->nd_cred->cr_uid;
2732         stp->ls_seq = fxdr_unsigned(int, *tl++);
2733         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2734         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2735             NFSX_STATEIDOTHER);
2736         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2737
2738         /*
2739          * For the special stateid of other all 0s and seqid == 1, set the
2740          * stateid to the current stateid, if it is set.
2741          */
2742         if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2743             stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2744             stp->ls_stateid.other[2] == 0) {
2745                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2746                         stp->ls_stateid = nd->nd_curstateid;
2747                         stp->ls_stateid.seqid = 0;
2748                 } else {
2749                         nd->nd_repstat = NFSERR_BADSTATEID;
2750                         free(stp, M_NFSDSTATE);
2751                         free(lop, M_NFSDLOCK);
2752                         goto nfsmout;
2753                 }
2754         }
2755
2756         lop->lo_first = fxdr_hyper(tl);
2757         tl += 2;
2758         len = fxdr_hyper(tl);
2759         if (len == NFS64BITSSET) {
2760                 lop->lo_end = NFS64BITSSET;
2761         } else {
2762                 lop->lo_end = lop->lo_first + len;
2763                 if (lop->lo_end <= lop->lo_first)
2764                         nd->nd_repstat = NFSERR_INVAL;
2765         }
2766         clientid.lval[0] = stp->ls_stateid.other[0];
2767         clientid.lval[1] = stp->ls_stateid.other[1];
2768         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2769                 if ((nd->nd_flag & ND_NFSV41) != 0)
2770                         clientid.qval = nd->nd_clientid.qval;
2771                 else if (nd->nd_clientid.qval != clientid.qval)
2772                         printf("EEK6 multiple clids\n");
2773         } else {
2774                 if ((nd->nd_flag & ND_NFSV41) != 0)
2775                         printf("EEK! no clientid from session\n");
2776                 nd->nd_flag |= ND_IMPLIEDCLID;
2777                 nd->nd_clientid.qval = clientid.qval;
2778         }
2779         if (!nd->nd_repstat && vp->v_type != VREG) {
2780             if (vp->v_type == VDIR)
2781                 nd->nd_repstat = NFSERR_ISDIR;
2782             else
2783                 nd->nd_repstat = NFSERR_INVAL;
2784         }
2785         /*
2786          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2787          * seqid# gets incremented. nfsrv_lockctrl() will return the
2788          * value of nd_repstat, if it gets that far.
2789          */
2790         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2791             &stateid, exp, nd, p);
2792         if (stp)
2793                 free(stp, M_NFSDSTATE);
2794         if (lop)
2795                 free(lop, M_NFSDLOCK);
2796         if (!nd->nd_repstat) {
2797                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2798                 *tl++ = txdr_unsigned(stateid.seqid);
2799                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2800         }
2801 nfsmout:
2802         vput(vp);
2803         NFSEXITCODE2(error, nd);
2804         return (error);
2805 }
2806
2807 /*
2808  * nfsv4 open service
2809  */
2810 int
2811 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2812     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2813 {
2814         u_int32_t *tl;
2815         int i, retext;
2816         struct nfsstate *stp = NULL;
2817         int error = 0, create, claim, exclusive_flag = 0, override;
2818         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2819         int how = NFSCREATE_UNCHECKED;
2820         int32_t cverf[2], tverf[2] = { 0, 0 };
2821         vnode_t vp = NULL, dirp = NULL;
2822         struct nfsvattr nva, dirfor, diraft;
2823         struct nameidata named;
2824         nfsv4stateid_t stateid, delegstateid;
2825         nfsattrbit_t attrbits;
2826         nfsquad_t clientid;
2827         char *bufp = NULL;
2828         u_long *hashp;
2829         NFSACL_T *aclp = NULL;
2830         struct thread *p = curthread;
2831         bool done_namei;
2832
2833 #ifdef NFS4_ACL_EXTATTR_NAME
2834         aclp = acl_alloc(M_WAITOK);
2835         aclp->acl_cnt = 0;
2836 #endif
2837         NFSZERO_ATTRBIT(&attrbits);
2838         done_namei = false;
2839         named.ni_cnd.cn_nameiop = 0;
2840         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2841         i = fxdr_unsigned(int, *(tl + 5));
2842         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2843                 nd->nd_repstat = NFSERR_BADXDR;
2844                 goto nfsmout;
2845         }
2846         stp = malloc(sizeof (struct nfsstate) + i,
2847             M_NFSDSTATE, M_WAITOK);
2848         stp->ls_ownerlen = i;
2849         stp->ls_op = nd->nd_rp;
2850         stp->ls_flags = NFSLCK_OPEN;
2851         stp->ls_uid = nd->nd_cred->cr_uid;
2852         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2853         i = fxdr_unsigned(int, *tl++);
2854         retext = 0;
2855         if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2856             NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2857                 retext = 1;
2858                 /* For now, ignore these. */
2859                 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2860                 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2861                 case NFSV4OPEN_WANTANYDELEG:
2862                         stp->ls_flags |= (NFSLCK_WANTRDELEG |
2863                             NFSLCK_WANTWDELEG);
2864                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2865                         break;
2866                 case NFSV4OPEN_WANTREADDELEG:
2867                         stp->ls_flags |= NFSLCK_WANTRDELEG;
2868                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2869                         break;
2870                 case NFSV4OPEN_WANTWRITEDELEG:
2871                         stp->ls_flags |= NFSLCK_WANTWDELEG;
2872                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2873                         break;
2874                 case NFSV4OPEN_WANTNODELEG:
2875                         stp->ls_flags |= NFSLCK_WANTNODELEG;
2876                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2877                         break;
2878                 case NFSV4OPEN_WANTCANCEL:
2879                         printf("NFSv4: ignore Open WantCancel\n");
2880                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2881                         break;
2882                 default:
2883                         /* nd_repstat will be set to NFSERR_INVAL below. */
2884                         break;
2885                 }
2886         }
2887         switch (i) {
2888         case NFSV4OPEN_ACCESSREAD:
2889                 stp->ls_flags |= NFSLCK_READACCESS;
2890                 break;
2891         case NFSV4OPEN_ACCESSWRITE:
2892                 stp->ls_flags |= NFSLCK_WRITEACCESS;
2893                 break;
2894         case NFSV4OPEN_ACCESSBOTH:
2895                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2896                 break;
2897         default:
2898                 nd->nd_repstat = NFSERR_INVAL;
2899         }
2900         i = fxdr_unsigned(int, *tl++);
2901         switch (i) {
2902         case NFSV4OPEN_DENYNONE:
2903                 break;
2904         case NFSV4OPEN_DENYREAD:
2905                 stp->ls_flags |= NFSLCK_READDENY;
2906                 break;
2907         case NFSV4OPEN_DENYWRITE:
2908                 stp->ls_flags |= NFSLCK_WRITEDENY;
2909                 break;
2910         case NFSV4OPEN_DENYBOTH:
2911                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2912                 break;
2913         default:
2914                 nd->nd_repstat = NFSERR_INVAL;
2915         }
2916         clientid.lval[0] = *tl++;
2917         clientid.lval[1] = *tl;
2918         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2919                 if ((nd->nd_flag & ND_NFSV41) != 0)
2920                         clientid.qval = nd->nd_clientid.qval;
2921                 else if (nd->nd_clientid.qval != clientid.qval)
2922                         printf("EEK7 multiple clids\n");
2923         } else {
2924                 if ((nd->nd_flag & ND_NFSV41) != 0)
2925                         printf("EEK! no clientid from session\n");
2926                 nd->nd_flag |= ND_IMPLIEDCLID;
2927                 nd->nd_clientid.qval = clientid.qval;
2928         }
2929         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2930         if (error)
2931                 goto nfsmout;
2932         NFSVNO_ATTRINIT(&nva);
2933         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2934         create = fxdr_unsigned(int, *tl);
2935         if (!nd->nd_repstat)
2936                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
2937         if (create == NFSV4OPEN_CREATE) {
2938                 nva.na_type = VREG;
2939                 nva.na_mode = 0;
2940                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2941                 how = fxdr_unsigned(int, *tl);
2942                 switch (how) {
2943                 case NFSCREATE_UNCHECKED:
2944                 case NFSCREATE_GUARDED:
2945                         error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2946                         if (error)
2947                                 goto nfsmout;
2948                         /*
2949                          * If the na_gid being set is the same as that of
2950                          * the directory it is going in, clear it, since
2951                          * that is what will be set by default. This allows
2952                          * a user that isn't in that group to do the create.
2953                          */
2954                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2955                             nva.na_gid == dirfor.na_gid)
2956                                 NFSVNO_UNSET(&nva, gid);
2957                         if (!nd->nd_repstat)
2958                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2959                         break;
2960                 case NFSCREATE_EXCLUSIVE:
2961                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2962                         cverf[0] = *tl++;
2963                         cverf[1] = *tl;
2964                         break;
2965                 case NFSCREATE_EXCLUSIVE41:
2966                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2967                         cverf[0] = *tl++;
2968                         cverf[1] = *tl;
2969                         error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2970                         if (error != 0)
2971                                 goto nfsmout;
2972                         if (NFSISSET_ATTRBIT(&attrbits,
2973                             NFSATTRBIT_TIMEACCESSSET))
2974                                 nd->nd_repstat = NFSERR_INVAL;
2975                         /*
2976                          * If the na_gid being set is the same as that of
2977                          * the directory it is going in, clear it, since
2978                          * that is what will be set by default. This allows
2979                          * a user that isn't in that group to do the create.
2980                          */
2981                         if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2982                             nva.na_gid == dirfor.na_gid)
2983                                 NFSVNO_UNSET(&nva, gid);
2984                         if (nd->nd_repstat == 0)
2985                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2986                         break;
2987                 default:
2988                         nd->nd_repstat = NFSERR_BADXDR;
2989                         goto nfsmout;
2990                 }
2991         } else if (create != NFSV4OPEN_NOCREATE) {
2992                 nd->nd_repstat = NFSERR_BADXDR;
2993                 goto nfsmout;
2994         }
2995
2996         /*
2997          * Now, handle the claim, which usually includes looking up a
2998          * name in the directory referenced by dp. The exception is
2999          * NFSV4OPEN_CLAIMPREVIOUS.
3000          */
3001         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3002         claim = fxdr_unsigned(int, *tl);
3003         if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim ==
3004             NFSV4OPEN_CLAIMDELEGATECURFH) {
3005                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3006                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3007                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3008                 stp->ls_flags |= NFSLCK_DELEGCUR;
3009         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim ==
3010             NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3011                 stp->ls_flags |= NFSLCK_DELEGPREV;
3012         }
3013         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
3014             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
3015                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
3016                     claim != NFSV4OPEN_CLAIMNULL)
3017                         nd->nd_repstat = NFSERR_INVAL;
3018                 if (nd->nd_repstat) {
3019                         nd->nd_repstat = nfsrv_opencheck(clientid,
3020                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
3021                         goto nfsmout;
3022                 }
3023                 if (create == NFSV4OPEN_CREATE)
3024                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
3025                         LOCKPARENT | LOCKLEAF | NOCACHE);
3026                 else
3027                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3028                         LOCKLEAF);
3029                 nfsvno_setpathbuf(&named, &bufp, &hashp);
3030                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3031                 if (error) {
3032                         vrele(dp);
3033 #ifdef NFS4_ACL_EXTATTR_NAME
3034                         acl_free(aclp);
3035 #endif
3036                         free(stp, M_NFSDSTATE);
3037                         nfsvno_relpathbuf(&named);
3038                         NFSEXITCODE2(error, nd);
3039                         return (error);
3040                 }
3041                 if (!nd->nd_repstat) {
3042                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
3043                             &dirp);
3044                 } else {
3045                         vrele(dp);
3046                         nfsvno_relpathbuf(&named);
3047                 }
3048                 if (create == NFSV4OPEN_CREATE) {
3049                     switch (how) {
3050                     case NFSCREATE_UNCHECKED:
3051                         if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3052                                 /*
3053                                  * Clear the setable attribute bits, except
3054                                  * for Size, if it is being truncated.
3055                                  */
3056                                 NFSZERO_ATTRBIT(&attrbits);
3057                                 if (NFSVNO_ISSETSIZE(&nva))
3058                                         NFSSETBIT_ATTRBIT(&attrbits,
3059                                             NFSATTRBIT_SIZE);
3060                         }
3061                         break;
3062                     case NFSCREATE_GUARDED:
3063                         if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3064                                 nd->nd_repstat = EEXIST;
3065                                 done_namei = true;
3066                         }
3067                         break;
3068                     case NFSCREATE_EXCLUSIVE:
3069                         exclusive_flag = 1;
3070                         if (nd->nd_repstat == 0 && named.ni_vp == NULL)
3071                                 nva.na_mode = 0;
3072                         break;
3073                     case NFSCREATE_EXCLUSIVE41:
3074                         exclusive_flag = 1;
3075                         break;
3076                     }
3077                 }
3078                 nfsvno_open(nd, &named, clientid, &stateid, stp,
3079                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3080                     nd->nd_cred, done_namei, exp, &vp);
3081         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3082             NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH ||
3083             claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3084                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3085                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3086                         i = fxdr_unsigned(int, *tl);
3087                         switch (i) {
3088                         case NFSV4OPEN_DELEGATEREAD:
3089                                 stp->ls_flags |= NFSLCK_DELEGREAD;
3090                                 break;
3091                         case NFSV4OPEN_DELEGATEWRITE:
3092                                 stp->ls_flags |= NFSLCK_DELEGWRITE;
3093                         case NFSV4OPEN_DELEGATENONE:
3094                                 break;
3095                         default:
3096                                 nd->nd_repstat = NFSERR_BADXDR;
3097                                 goto nfsmout;
3098                         }
3099                         stp->ls_flags |= NFSLCK_RECLAIM;
3100                 } else {
3101                         if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3102                                 nd->nd_repstat = NFSERR_INVAL;
3103                 }
3104                 vp = dp;
3105                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3106                 if (!VN_IS_DOOMED(vp))
3107                         nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3108                             stp, vp, nd, p, nd->nd_repstat);
3109                 else
3110                         nd->nd_repstat = NFSERR_PERM;
3111         } else {
3112                 nd->nd_repstat = NFSERR_BADXDR;
3113                 goto nfsmout;
3114         }
3115
3116         /*
3117          * Do basic access checking.
3118          */
3119         if (!nd->nd_repstat && vp->v_type != VREG) {
3120                 /*
3121                  * The IETF working group decided that this is the correct
3122                  * error return for all non-regular files.
3123                  */
3124                 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3125         }
3126
3127         /*
3128          * If the Open is being done for a file that already exists, apply
3129          * normal permission checking including for the file owner, if
3130          * vfs.nfsd.v4openaccess is set.
3131          * Previously, the owner was always allowed to open the file to
3132          * be consistent with the NFS tradition of always allowing the
3133          * owner of the file to write to the file regardless of permissions.
3134          * It now appears that the Linux client expects the owner
3135          * permissions to be checked for opens that are not creating the
3136          * file.  I believe the correct approach is to use the Access
3137          * operation's results to be consistent with NFSv3, but that is
3138          * not what the current Linux client appears to be doing.
3139          * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3140          * I have enabled it by default.  Since Linux does not apply this
3141          * check for claim_delegate_cur, this code does the same.
3142          * If this semantic change causes a problem, it can be disabled by
3143          * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3144          * previous semantics.
3145          */
3146         if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE &&
3147             (stp->ls_flags & NFSLCK_DELEGCUR) == 0)
3148                 override = NFSACCCHK_NOOVERRIDE;
3149         else
3150                 override = NFSACCCHK_ALLOWOWNER;
3151         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3152             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3153                 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3154         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3155             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3156                 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3157             if (nd->nd_repstat)
3158                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3159                     nd->nd_cred, exp, p, override,
3160                     NFSACCCHK_VPISLOCKED, NULL);
3161         }
3162
3163         if (!nd->nd_repstat) {
3164                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3165                 if (!nd->nd_repstat) {
3166                         tverf[0] = nva.na_atime.tv_sec;
3167                         tverf[1] = nva.na_atime.tv_nsec;
3168                 }
3169         }
3170         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
3171             cverf[1] != tverf[1]))
3172                 nd->nd_repstat = EEXIST;
3173         /*
3174          * Do the open locking/delegation stuff.
3175          */
3176         if (!nd->nd_repstat)
3177             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3178                 &delegstateid, &rflags, exp, p, nva.na_filerev);
3179
3180         /*
3181          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3182          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3183          * (ie: Leave the NFSVOPUNLOCK() about here.)
3184          */
3185         if (vp)
3186                 NFSVOPUNLOCK(vp);
3187         if (stp)
3188                 free(stp, M_NFSDSTATE);
3189         if (!nd->nd_repstat && dirp)
3190                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3191         if (!nd->nd_repstat) {
3192                 /* For NFSv4.1, set the Current StateID. */
3193                 if ((nd->nd_flag & ND_NFSV41) != 0) {
3194                         nd->nd_curstateid = stateid;
3195                         nd->nd_flag |= ND_CURSTATEID;
3196                 }
3197                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3198                 *tl++ = txdr_unsigned(stateid.seqid);
3199                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3200                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3201                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3202                         *tl++ = newnfs_true;
3203                         *tl++ = 0;
3204                         *tl++ = 0;
3205                         *tl++ = 0;
3206                         *tl++ = 0;
3207                 } else {
3208                         *tl++ = newnfs_false;   /* Since dirp is not locked */
3209                         txdr_hyper(dirfor.na_filerev, tl);
3210                         tl += 2;
3211                         txdr_hyper(diraft.na_filerev, tl);
3212                         tl += 2;
3213                 }
3214                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3215                 (void) nfsrv_putattrbit(nd, &attrbits);
3216                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3217                 if (rflags & NFSV4OPEN_READDELEGATE)
3218                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3219                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3220                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3221                 else if (retext != 0) {
3222                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3223                         if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3224                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3225                                 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3226                         } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3227                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3228                                 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3229                         } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3230                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3231                                 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3232                                 *tl = newnfs_false;
3233                         } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3234                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3235                                 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3236                                 *tl = newnfs_false;
3237                         } else {
3238                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3239                                 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3240                         }
3241                 } else
3242                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3243                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3244                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3245                         *tl++ = txdr_unsigned(delegstateid.seqid);
3246                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3247                             NFSX_STATEIDOTHER);
3248                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3249                         if (rflags & NFSV4OPEN_RECALL)
3250                                 *tl = newnfs_true;
3251                         else
3252                                 *tl = newnfs_false;
3253                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3254                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3255                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3256                                 txdr_hyper(nva.na_size, tl);
3257                         }
3258                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3259                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3260                         *tl++ = txdr_unsigned(0x0);
3261                         acemask = NFSV4ACE_ALLFILESMASK;
3262                         if (nva.na_mode & S_IRUSR)
3263                             acemask |= NFSV4ACE_READMASK;
3264                         if (nva.na_mode & S_IWUSR)
3265                             acemask |= NFSV4ACE_WRITEMASK;
3266                         if (nva.na_mode & S_IXUSR)
3267                             acemask |= NFSV4ACE_EXECUTEMASK;
3268                         *tl = txdr_unsigned(acemask);
3269                         (void) nfsm_strtom(nd, "OWNER@", 6);
3270                 }
3271                 *vpp = vp;
3272         } else if (vp) {
3273                 vrele(vp);
3274         }
3275         if (dirp)
3276                 vrele(dirp);
3277 #ifdef NFS4_ACL_EXTATTR_NAME
3278         acl_free(aclp);
3279 #endif
3280         NFSEXITCODE2(0, nd);
3281         return (0);
3282 nfsmout:
3283         vrele(dp);
3284 #ifdef NFS4_ACL_EXTATTR_NAME
3285         acl_free(aclp);
3286 #endif
3287         if (stp)
3288                 free(stp, M_NFSDSTATE);
3289         NFSEXITCODE2(error, nd);
3290         return (error);
3291 }
3292
3293 /*
3294  * nfsv4 close service
3295  */
3296 int
3297 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3298     vnode_t vp, __unused struct nfsexstuff *exp)
3299 {
3300         u_int32_t *tl;
3301         struct nfsstate st, *stp = &st;
3302         int error = 0, writeacc;
3303         nfsv4stateid_t stateid;
3304         nfsquad_t clientid;
3305         struct nfsvattr na;
3306         struct thread *p = curthread;
3307
3308         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3309         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3310         stp->ls_ownerlen = 0;
3311         stp->ls_op = nd->nd_rp;
3312         stp->ls_uid = nd->nd_cred->cr_uid;
3313         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3314         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3315             NFSX_STATEIDOTHER);
3316
3317         /*
3318          * For the special stateid of other all 0s and seqid == 1, set the
3319          * stateid to the current stateid, if it is set.
3320          */
3321         if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3322             stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3323             stp->ls_stateid.other[2] == 0) {
3324                 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3325                         stp->ls_stateid = nd->nd_curstateid;
3326                 else {
3327                         nd->nd_repstat = NFSERR_BADSTATEID;
3328                         goto nfsmout;
3329                 }
3330         }
3331
3332         stp->ls_flags = NFSLCK_CLOSE;
3333         clientid.lval[0] = stp->ls_stateid.other[0];
3334         clientid.lval[1] = stp->ls_stateid.other[1];
3335         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3336                 if ((nd->nd_flag & ND_NFSV41) != 0)
3337                         clientid.qval = nd->nd_clientid.qval;
3338                 else if (nd->nd_clientid.qval != clientid.qval)
3339                         printf("EEK8 multiple clids\n");
3340         } else {
3341                 if ((nd->nd_flag & ND_NFSV41) != 0)
3342                         printf("EEK! no clientid from session\n");
3343                 nd->nd_flag |= ND_IMPLIEDCLID;
3344                 nd->nd_clientid.qval = clientid.qval;
3345         }
3346         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3347             &writeacc);
3348         /* For pNFS, update the attributes. */
3349         if (writeacc != 0 || nfsrv_pnfsatime != 0)
3350                 nfsrv_updatemdsattr(vp, &na, p);
3351         vput(vp);
3352         if (!nd->nd_repstat) {
3353                 /*
3354                  * If the stateid that has been closed is the current stateid,
3355                  * unset it.
3356                  */
3357                 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3358                     stateid.other[0] == nd->nd_curstateid.other[0] &&
3359                     stateid.other[1] == nd->nd_curstateid.other[1] &&
3360                     stateid.other[2] == nd->nd_curstateid.other[2])
3361                         nd->nd_flag &= ~ND_CURSTATEID;
3362                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3363                 *tl++ = txdr_unsigned(stateid.seqid);
3364                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3365         }
3366         NFSEXITCODE2(0, nd);
3367         return (0);
3368 nfsmout:
3369         vput(vp);
3370         NFSEXITCODE2(error, nd);
3371         return (error);
3372 }
3373
3374 /*
3375  * nfsv4 delegpurge service
3376  */
3377 int
3378 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3379     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3380 {
3381         u_int32_t *tl;
3382         int error = 0;
3383         nfsquad_t clientid;
3384         struct thread *p = curthread;
3385
3386         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3387                 goto nfsmout;
3388         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3389         clientid.lval[0] = *tl++;
3390         clientid.lval[1] = *tl;
3391         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3392                 if ((nd->nd_flag & ND_NFSV41) != 0)
3393                         clientid.qval = nd->nd_clientid.qval;
3394                 else if (nd->nd_clientid.qval != clientid.qval)
3395                         printf("EEK9 multiple clids\n");
3396         } else {
3397                 if ((nd->nd_flag & ND_NFSV41) != 0)
3398                         printf("EEK! no clientid from session\n");
3399                 nd->nd_flag |= ND_IMPLIEDCLID;
3400                 nd->nd_clientid.qval = clientid.qval;
3401         }
3402         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3403             NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3404 nfsmout:
3405         NFSEXITCODE2(error, nd);
3406         return (error);
3407 }
3408
3409 /*
3410  * nfsv4 delegreturn service
3411  */
3412 int
3413 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3414     vnode_t vp, __unused struct nfsexstuff *exp)
3415 {
3416         u_int32_t *tl;
3417         int error = 0, writeacc;
3418         nfsv4stateid_t stateid;
3419         nfsquad_t clientid;
3420         struct nfsvattr na;
3421         struct thread *p = curthread;
3422
3423         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3424         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3425         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3426         clientid.lval[0] = stateid.other[0];
3427         clientid.lval[1] = stateid.other[1];
3428         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3429                 if ((nd->nd_flag & ND_NFSV41) != 0)
3430                         clientid.qval = nd->nd_clientid.qval;
3431                 else if (nd->nd_clientid.qval != clientid.qval)
3432                         printf("EEK10 multiple clids\n");
3433         } else {
3434                 if ((nd->nd_flag & ND_NFSV41) != 0)
3435                         printf("EEK! no clientid from session\n");
3436                 nd->nd_flag |= ND_IMPLIEDCLID;
3437                 nd->nd_clientid.qval = clientid.qval;
3438         }
3439         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3440             NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3441         /* For pNFS, update the attributes. */
3442         if (writeacc != 0 || nfsrv_pnfsatime != 0)
3443                 nfsrv_updatemdsattr(vp, &na, p);
3444 nfsmout:
3445         vput(vp);
3446         NFSEXITCODE2(error, nd);
3447         return (error);
3448 }
3449
3450 /*
3451  * nfsv4 get file handle service
3452  */
3453 int
3454 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3455     vnode_t vp, __unused struct nfsexstuff *exp)
3456 {
3457         fhandle_t fh;
3458         struct thread *p = curthread;
3459
3460         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3461         vput(vp);
3462         if (!nd->nd_repstat)
3463                 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
3464         NFSEXITCODE2(0, nd);
3465         return (0);
3466 }
3467
3468 /*
3469  * nfsv4 open confirm service
3470  */
3471 int
3472 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3473     vnode_t vp, __unused struct nfsexstuff *exp)
3474 {
3475         u_int32_t *tl;
3476         struct nfsstate st, *stp = &st;
3477         int error = 0;
3478         nfsv4stateid_t stateid;
3479         nfsquad_t clientid;
3480         struct thread *p = curthread;
3481
3482         if ((nd->nd_flag & ND_NFSV41) != 0) {
3483                 nd->nd_repstat = NFSERR_NOTSUPP;
3484                 goto nfsmout;
3485         }
3486         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3487         stp->ls_ownerlen = 0;
3488         stp->ls_op = nd->nd_rp;
3489         stp->ls_uid = nd->nd_cred->cr_uid;
3490         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3491         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3492             NFSX_STATEIDOTHER);
3493         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3494         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3495         stp->ls_flags = NFSLCK_CONFIRM;
3496         clientid.lval[0] = stp->ls_stateid.other[0];
3497         clientid.lval[1] = stp->ls_stateid.other[1];
3498         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3499                 if ((nd->nd_flag & ND_NFSV41) != 0)
3500                         clientid.qval = nd->nd_clientid.qval;
3501                 else if (nd->nd_clientid.qval != clientid.qval)
3502                         printf("EEK11 multiple clids\n");
3503         } else {
3504                 if ((nd->nd_flag & ND_NFSV41) != 0)
3505                         printf("EEK! no clientid from session\n");
3506                 nd->nd_flag |= ND_IMPLIEDCLID;
3507                 nd->nd_clientid.qval = clientid.qval;
3508         }
3509         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3510             NULL);
3511         if (!nd->nd_repstat) {
3512                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3513                 *tl++ = txdr_unsigned(stateid.seqid);
3514                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3515         }
3516 nfsmout:
3517         vput(vp);
3518         NFSEXITCODE2(error, nd);
3519         return (error);
3520 }
3521
3522 /*
3523  * nfsv4 open downgrade service
3524  */
3525 int
3526 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3527     vnode_t vp, __unused struct nfsexstuff *exp)
3528 {
3529         u_int32_t *tl;
3530         int i;
3531         struct nfsstate st, *stp = &st;
3532         int error = 0;
3533         nfsv4stateid_t stateid;
3534         nfsquad_t clientid;
3535         struct thread *p = curthread;
3536
3537         /* opendowngrade can only work on a file object.*/
3538         if (vp->v_type != VREG) {
3539                 error = NFSERR_INVAL;
3540                 goto nfsmout;
3541         }
3542         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3543         stp->ls_ownerlen = 0;
3544         stp->ls_op = nd->nd_rp;
3545         stp->ls_uid = nd->nd_cred->cr_uid;
3546         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3547         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3548             NFSX_STATEIDOTHER);
3549         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3550
3551         /*
3552          * For the special stateid of other all 0s and seqid == 1, set the
3553          * stateid to the current stateid, if it is set.
3554          */
3555         if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3556             stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3557             stp->ls_stateid.other[2] == 0) {
3558                 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3559                         stp->ls_stateid = nd->nd_curstateid;
3560                 else {
3561                         nd->nd_repstat = NFSERR_BADSTATEID;
3562                         goto nfsmout;
3563                 }
3564         }
3565
3566         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3567         i = fxdr_unsigned(int, *tl++);
3568         if ((nd->nd_flag & ND_NFSV41) != 0)
3569                 i &= ~NFSV4OPEN_WANTDELEGMASK;
3570         switch (i) {
3571         case NFSV4OPEN_ACCESSREAD:
3572                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3573                 break;
3574         case NFSV4OPEN_ACCESSWRITE:
3575                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3576                 break;
3577         case NFSV4OPEN_ACCESSBOTH:
3578                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3579                     NFSLCK_DOWNGRADE);
3580                 break;
3581         default:
3582                 nd->nd_repstat = NFSERR_INVAL;
3583         }
3584         i = fxdr_unsigned(int, *tl);
3585         switch (i) {
3586         case NFSV4OPEN_DENYNONE:
3587                 break;
3588         case NFSV4OPEN_DENYREAD:
3589                 stp->ls_flags |= NFSLCK_READDENY;
3590                 break;
3591         case NFSV4OPEN_DENYWRITE:
3592                 stp->ls_flags |= NFSLCK_WRITEDENY;
3593                 break;
3594         case NFSV4OPEN_DENYBOTH:
3595                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3596                 break;
3597         default:
3598                 nd->nd_repstat = NFSERR_INVAL;
3599         }
3600
3601         clientid.lval[0] = stp->ls_stateid.other[0];
3602         clientid.lval[1] = stp->ls_stateid.other[1];
3603         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3604                 if ((nd->nd_flag & ND_NFSV41) != 0)
3605                         clientid.qval = nd->nd_clientid.qval;
3606                 else if (nd->nd_clientid.qval != clientid.qval)
3607                         printf("EEK12 multiple clids\n");
3608         } else {
3609                 if ((nd->nd_flag & ND_NFSV41) != 0)
3610                         printf("EEK! no clientid from session\n");
3611                 nd->nd_flag |= ND_IMPLIEDCLID;
3612                 nd->nd_clientid.qval = clientid.qval;
3613         }
3614         if (!nd->nd_repstat)
3615                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3616                     nd, p, NULL);
3617         if (!nd->nd_repstat) {
3618                 /* For NFSv4.1, set the Current StateID. */
3619                 if ((nd->nd_flag & ND_NFSV41) != 0) {
3620                         nd->nd_curstateid = stateid;
3621                         nd->nd_flag |= ND_CURSTATEID;
3622                 }
3623                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3624                 *tl++ = txdr_unsigned(stateid.seqid);
3625                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3626         }
3627 nfsmout:
3628         vput(vp);
3629         NFSEXITCODE2(error, nd);
3630         return (error);
3631 }
3632
3633 /*
3634  * nfsv4 renew lease service
3635  */
3636 int
3637 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3638     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3639 {
3640         u_int32_t *tl;
3641         int error = 0;
3642         nfsquad_t clientid;
3643         struct thread *p = curthread;
3644
3645         if ((nd->nd_flag & ND_NFSV41) != 0) {
3646                 nd->nd_repstat = NFSERR_NOTSUPP;
3647                 goto nfsmout;
3648         }
3649         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3650                 goto nfsmout;
3651         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3652         clientid.lval[0] = *tl++;
3653         clientid.lval[1] = *tl;
3654         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3655                 if ((nd->nd_flag & ND_NFSV41) != 0)
3656                         clientid.qval = nd->nd_clientid.qval;
3657                 else if (nd->nd_clientid.qval != clientid.qval)
3658                         printf("EEK13 multiple clids\n");
3659         } else {
3660                 if ((nd->nd_flag & ND_NFSV41) != 0)
3661                         printf("EEK! no clientid from session\n");
3662                 nd->nd_flag |= ND_IMPLIEDCLID;
3663                 nd->nd_clientid.qval = clientid.qval;
3664         }
3665         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3666             NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3667 nfsmout:
3668         NFSEXITCODE2(error, nd);
3669         return (error);
3670 }
3671
3672 /*
3673  * nfsv4 security info service
3674  */
3675 int
3676 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3677     vnode_t dp, struct nfsexstuff *exp)
3678 {
3679         u_int32_t *tl;
3680         int len;
3681         struct nameidata named;
3682         vnode_t dirp = NULL, vp;
3683         struct nfsrvfh fh;
3684         struct nfsexstuff retnes;
3685         u_int32_t *sizp;
3686         int error = 0, i;
3687         uint64_t savflag;
3688         char *bufp;
3689         u_long *hashp;
3690         struct thread *p = curthread;
3691
3692         /*
3693          * All this just to get the export flags for the name.
3694          */
3695         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3696             LOCKLEAF);
3697         nfsvno_setpathbuf(&named, &bufp, &hashp);
3698         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3699         if (error) {
3700                 vput(dp);
3701                 nfsvno_relpathbuf(&named);
3702                 goto out;
3703         }
3704         if (!nd->nd_repstat) {
3705                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3706         } else {
3707                 vput(dp);
3708                 nfsvno_relpathbuf(&named);
3709         }
3710         if (dirp)
3711                 vrele(dirp);
3712         if (nd->nd_repstat)
3713                 goto out;
3714         nfsvno_relpathbuf(&named);
3715         fh.nfsrvfh_len = NFSX_MYFH;
3716         vp = named.ni_vp;
3717         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3718         vput(vp);
3719         savflag = nd->nd_flag;
3720         if (!nd->nd_repstat) {
3721                 /*
3722                  * Pretend the next op is Secinfo, so that no wrongsec
3723                  * test will be done.
3724                  */
3725                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3726                     NFSV4OP_SECINFO);
3727                 if (vp)
3728                         vput(vp);
3729         }
3730         nd->nd_flag = savflag;
3731         if (nd->nd_repstat)
3732                 goto out;
3733
3734         /*
3735          * Finally have the export flags for name, so we can create
3736          * the security info.
3737          */
3738         len = 0;
3739         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3740
3741         /* If nes_numsecflavor == 0, all are allowed. */
3742         if (retnes.nes_numsecflavor == 0) {
3743                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3744                 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3745                 *tl = txdr_unsigned(RPCAUTH_GSS);
3746                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3747                     nfsgss_mechlist[KERBV_MECH].len);
3748                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3749                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3750                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3751                 *tl = txdr_unsigned(RPCAUTH_GSS);
3752                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3753                     nfsgss_mechlist[KERBV_MECH].len);
3754                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3755                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3756                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3757                 *tl = txdr_unsigned(RPCAUTH_GSS);
3758                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3759                     nfsgss_mechlist[KERBV_MECH].len);
3760                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3761                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3762                 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3763                 len = 4;
3764         }
3765         for (i = 0; i < retnes.nes_numsecflavor; i++) {
3766                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3767                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3768                         *tl = txdr_unsigned(RPCAUTH_UNIX);
3769                         len++;
3770                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3771                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3772                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3773                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3774                             nfsgss_mechlist[KERBV_MECH].len);
3775                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3776                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3777                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3778                         len++;
3779                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3780                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3781                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3782                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3783                             nfsgss_mechlist[KERBV_MECH].len);
3784                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3785                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3786                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3787                         len++;
3788                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3789                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3790                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3791                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3792                             nfsgss_mechlist[KERBV_MECH].len);
3793                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3794                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3795                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3796                         len++;
3797                 }
3798         }
3799         *sizp = txdr_unsigned(len);
3800
3801 out:
3802         NFSEXITCODE2(error, nd);
3803         return (error);
3804 }
3805
3806 /*
3807  * nfsv4 security info no name service
3808  */
3809 int
3810 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
3811     vnode_t dp, struct nfsexstuff *exp)
3812 {
3813         uint32_t *tl, *sizp;
3814         struct nameidata named;
3815         vnode_t dirp = NULL, vp;
3816         struct nfsrvfh fh;
3817         struct nfsexstuff retnes;
3818         int error = 0, fhstyle, i, len;
3819         uint64_t savflag;
3820         char *bufp;
3821         u_long *hashp;
3822         struct thread *p = curthread;
3823
3824         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3825         fhstyle = fxdr_unsigned(int, *tl);
3826         switch (fhstyle) {
3827         case NFSSECINFONONAME_PARENT:
3828                 if (dp->v_type != VDIR) {
3829                         vput(dp);
3830                         nd->nd_repstat = NFSERR_NOTDIR;
3831                         goto nfsmout;
3832                 }
3833                 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3834                     LOCKLEAF);
3835                 nfsvno_setpathbuf(&named, &bufp, &hashp);
3836                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3837                 if (error != 0) {
3838                         vput(dp);
3839                         nfsvno_relpathbuf(&named);
3840                         goto nfsmout;
3841                 }
3842                 if (nd->nd_repstat == 0)
3843                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3844                 else
3845                         vput(dp);
3846                 if (dirp != NULL)
3847                         vrele(dirp);
3848                 nfsvno_relpathbuf(&named);
3849                 vp = named.ni_vp;
3850                 break;
3851         case NFSSECINFONONAME_CURFH:
3852                 vp = dp;
3853                 break;
3854         default:
3855                 nd->nd_repstat = NFSERR_INVAL;
3856                 vput(dp);
3857         }
3858         if (nd->nd_repstat != 0)
3859                 goto nfsmout;
3860         fh.nfsrvfh_len = NFSX_MYFH;
3861         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3862         vput(vp);
3863         savflag = nd->nd_flag;
3864         if (nd->nd_repstat == 0) {
3865                 /*
3866                  * Pretend the next op is Secinfo, so that no wrongsec
3867                  * test will be done.
3868                  */
3869                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3870                     NFSV4OP_SECINFO);
3871                 if (vp != NULL)
3872                         vput(vp);
3873         }
3874         nd->nd_flag = savflag;
3875         if (nd->nd_repstat != 0)
3876                 goto nfsmout;
3877
3878         /*
3879          * Finally have the export flags for fh/parent, so we can create
3880          * the security info.
3881          */
3882         len = 0;
3883         NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
3884
3885         /* If nes_numsecflavor == 0, all are allowed. */
3886         if (retnes.nes_numsecflavor == 0) {
3887                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3888                 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3889                 *tl = txdr_unsigned(RPCAUTH_GSS);
3890                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3891                     nfsgss_mechlist[KERBV_MECH].len);
3892                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3893                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3894                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3895                 *tl = txdr_unsigned(RPCAUTH_GSS);
3896                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3897                     nfsgss_mechlist[KERBV_MECH].len);
3898                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3899                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3900                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3901                 *tl = txdr_unsigned(RPCAUTH_GSS);
3902                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3903                     nfsgss_mechlist[KERBV_MECH].len);
3904                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3905                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3906                 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3907                 len = 4;
3908         }
3909         for (i = 0; i < retnes.nes_numsecflavor; i++) {
3910                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3911                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3912                         *tl = txdr_unsigned(RPCAUTH_UNIX);
3913                         len++;
3914                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3915                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3916                         *tl = txdr_unsigned(RPCAUTH_GSS);
3917                         nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3918                             nfsgss_mechlist[KERBV_MECH].len);
3919                         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3920                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3921                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3922                         len++;
3923                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3924                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3925                         *tl = txdr_unsigned(RPCAUTH_GSS);
3926                         nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3927                             nfsgss_mechlist[KERBV_MECH].len);
3928                         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3929                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3930                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3931                         len++;
3932                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3933                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3934                         *tl = txdr_unsigned(RPCAUTH_GSS);
3935                         nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3936                             nfsgss_mechlist[KERBV_MECH].len);
3937                         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3938                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3939                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3940                         len++;
3941                 }
3942         }
3943         *sizp = txdr_unsigned(len);
3944
3945 nfsmout:
3946         NFSEXITCODE2(error, nd);
3947         return (error);
3948 }
3949
3950 /*
3951  * nfsv4 set client id service
3952  */
3953 int
3954 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3955     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3956 {
3957         u_int32_t *tl;
3958         int i;
3959         int error = 0, idlen;
3960         struct nfsclient *clp = NULL;
3961 #ifdef INET
3962         struct sockaddr_in *rin;
3963 #endif
3964 #ifdef INET6
3965         struct sockaddr_in6 *rin6;
3966 #endif
3967 #if defined(INET) || defined(INET6)
3968         u_char *ucp, *ucp2;
3969 #endif
3970         u_char *verf, *addrbuf;
3971         nfsquad_t clientid, confirm;
3972         struct thread *p = curthread;
3973
3974         if ((nd->nd_flag & ND_NFSV41) != 0) {
3975                 nd->nd_repstat = NFSERR_NOTSUPP;
3976                 goto nfsmout;
3977         }
3978         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3979                 goto out;
3980         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3981         verf = (u_char *)tl;
3982         tl += (NFSX_VERF / NFSX_UNSIGNED);
3983         i = fxdr_unsigned(int, *tl);
3984         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3985                 nd->nd_repstat = NFSERR_BADXDR;
3986                 goto nfsmout;
3987         }
3988         idlen = i;
3989         if (nd->nd_flag & ND_GSS)
3990                 i += nd->nd_princlen;
3991         clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3992             M_ZERO);
3993         clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3994             nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3995         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3996         /* Allocated large enough for an AF_INET or AF_INET6 socket. */
3997         clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3998             M_WAITOK | M_ZERO);
3999         clp->lc_req.nr_cred = NULL;
4000         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4001         clp->lc_idlen = idlen;
4002         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4003         if (error)
4004                 goto nfsmout;
4005         if (nd->nd_flag & ND_GSS) {
4006                 clp->lc_flags = LCL_GSS;
4007                 if (nd->nd_flag & ND_GSSINTEGRITY)
4008                         clp->lc_flags |= LCL_GSSINTEGRITY;
4009                 else if (nd->nd_flag & ND_GSSPRIVACY)
4010                         clp->lc_flags |= LCL_GSSPRIVACY;
4011         } else {
4012                 clp->lc_flags = 0;
4013         }
4014         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
4015                 clp->lc_flags |= LCL_NAME;
4016                 clp->lc_namelen = nd->nd_princlen;
4017                 clp->lc_name = &clp->lc_id[idlen];
4018                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4019         } else {
4020                 clp->lc_uid = nd->nd_cred->cr_uid;
4021                 clp->lc_gid = nd->nd_cred->cr_gid;
4022         }
4023
4024         /* If the client is using TLS, do so for the callback connection. */
4025         if (nd->nd_flag & ND_TLS)
4026                 clp->lc_flags |= LCL_TLSCB;
4027
4028         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4029         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
4030         error = nfsrv_getclientipaddr(nd, clp);
4031         if (error)
4032                 goto nfsmout;
4033         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4034         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
4035
4036         /*
4037          * nfsrv_setclient() does the actual work of adding it to the
4038          * client list. If there is no error, the structure has been
4039          * linked into the client list and clp should no longer be used
4040          * here. When an error is returned, it has not been linked in,
4041          * so it should be free'd.
4042          */
4043         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4044         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
4045                 /*
4046                  * 8 is the maximum length of the port# string.
4047                  */
4048                 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
4049                 switch (clp->lc_req.nr_nam->sa_family) {
4050 #ifdef INET
4051                 case AF_INET:
4052                         if (clp->lc_flags & LCL_TCPCALLBACK)
4053                                 (void) nfsm_strtom(nd, "tcp", 3);
4054                         else 
4055                                 (void) nfsm_strtom(nd, "udp", 3);
4056                         rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4057                         ucp = (u_char *)&rin->sin_addr.s_addr;
4058                         ucp2 = (u_char *)&rin->sin_port;
4059                         sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
4060                             ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
4061                             ucp2[0] & 0xff, ucp2[1] & 0xff);
4062                         break;
4063 #endif
4064 #ifdef INET6
4065                 case AF_INET6:
4066                         if (clp->lc_flags & LCL_TCPCALLBACK)
4067                                 (void) nfsm_strtom(nd, "tcp6", 4);
4068                         else 
4069                                 (void) nfsm_strtom(nd, "udp6", 4);
4070                         rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4071                         ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
4072                             INET6_ADDRSTRLEN);
4073                         if (ucp != NULL)
4074                                 i = strlen(ucp);
4075                         else
4076                                 i = 0;
4077                         ucp2 = (u_char *)&rin6->sin6_port;
4078                         sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
4079                             ucp2[1] & 0xff);
4080                         break;
4081 #endif
4082                 }
4083                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
4084                 free(addrbuf, M_TEMP);
4085         }
4086         if (clp) {
4087                 free(clp->lc_req.nr_nam, M_SONAME);
4088                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4089                 free(clp->lc_stateid, M_NFSDCLIENT);
4090                 free(clp, M_NFSDCLIENT);
4091         }
4092         if (!nd->nd_repstat) {
4093                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
4094                 *tl++ = clientid.lval[0];
4095                 *tl++ = clientid.lval[1];
4096                 *tl++ = confirm.lval[0];
4097                 *tl = confirm.lval[1];
4098         }
4099
4100 out:
4101         NFSEXITCODE2(0, nd);
4102         return (0);
4103 nfsmout:
4104         if (clp) {
4105                 free(clp->lc_req.nr_nam, M_SONAME);
4106                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4107                 free(clp->lc_stateid, M_NFSDCLIENT);
4108                 free(clp, M_NFSDCLIENT);
4109         }
4110         NFSEXITCODE2(error, nd);
4111         return (error);
4112 }
4113
4114 /*
4115  * nfsv4 set client id confirm service
4116  */
4117 int
4118 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
4119     __unused int isdgram, __unused vnode_t vp,
4120     __unused struct nfsexstuff *exp)
4121 {
4122         u_int32_t *tl;
4123         int error = 0;
4124         nfsquad_t clientid, confirm;
4125         struct thread *p = curthread;
4126
4127         if ((nd->nd_flag & ND_NFSV41) != 0) {
4128                 nd->nd_repstat = NFSERR_NOTSUPP;
4129                 goto nfsmout;
4130         }
4131         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4132                 goto nfsmout;
4133         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
4134         clientid.lval[0] = *tl++;
4135         clientid.lval[1] = *tl++;
4136         confirm.lval[0] = *tl++;
4137         confirm.lval[1] = *tl;
4138
4139         /*
4140          * nfsrv_getclient() searches the client list for a match and
4141          * returns the appropriate NFSERR status.
4142          */
4143         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
4144             NULL, NULL, confirm, 0, nd, p);
4145 nfsmout:
4146         NFSEXITCODE2(error, nd);
4147         return (error);
4148 }
4149
4150 /*
4151  * nfsv4 verify service
4152  */
4153 int
4154 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
4155     vnode_t vp, __unused struct nfsexstuff *exp)
4156 {
4157         int error = 0, ret, fhsize = NFSX_MYFH;
4158         struct nfsvattr nva;
4159         struct statfs *sf;
4160         struct nfsfsinfo fs;
4161         fhandle_t fh;
4162         struct thread *p = curthread;
4163
4164         sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4165         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4166         if (!nd->nd_repstat)
4167                 nd->nd_repstat = nfsvno_statfs(vp, sf);
4168         if (!nd->nd_repstat)
4169                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
4170         if (!nd->nd_repstat) {
4171                 nfsvno_getfs(&fs, isdgram);
4172                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
4173                     sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
4174                 if (!error) {
4175                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
4176                                 if (ret == 0)
4177                                         nd->nd_repstat = NFSERR_SAME;
4178                                 else if (ret != NFSERR_NOTSAME)
4179                                         nd->nd_repstat = ret;
4180                         } else if (ret)
4181                                 nd->nd_repstat = ret;
4182                 }
4183         }
4184         vput(vp);
4185         free(sf, M_STATFS);
4186         NFSEXITCODE2(error, nd);
4187         return (error);
4188 }
4189
4190 /*
4191  * nfs openattr rpc
4192  */
4193 int
4194 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
4195     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
4196     __unused struct nfsexstuff *exp)
4197 {
4198         u_int32_t *tl;
4199         int error = 0, createdir __unused;
4200
4201         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4202         createdir = fxdr_unsigned(int, *tl);
4203         nd->nd_repstat = NFSERR_NOTSUPP;
4204 nfsmout:
4205         vrele(dp);
4206         NFSEXITCODE2(error, nd);
4207         return (error);
4208 }
4209
4210 /*
4211  * nfsv4 release lock owner service
4212  */
4213 int
4214 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4215     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4216 {
4217         u_int32_t *tl;
4218         struct nfsstate *stp = NULL;
4219         int error = 0, len;
4220         nfsquad_t clientid;
4221         struct thread *p = curthread;
4222
4223         if ((nd->nd_flag & ND_NFSV41) != 0) {
4224                 nd->nd_repstat = NFSERR_NOTSUPP;
4225                 goto nfsmout;
4226         }
4227         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4228                 goto nfsmout;
4229         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4230         len = fxdr_unsigned(int, *(tl + 2));
4231         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4232                 nd->nd_repstat = NFSERR_BADXDR;
4233                 goto nfsmout;
4234         }
4235         stp = malloc(sizeof (struct nfsstate) + len,
4236             M_NFSDSTATE, M_WAITOK);
4237         stp->ls_ownerlen = len;
4238         stp->ls_op = NULL;
4239         stp->ls_flags = NFSLCK_RELEASE;
4240         stp->ls_uid = nd->nd_cred->cr_uid;
4241         clientid.lval[0] = *tl++;
4242         clientid.lval[1] = *tl;
4243         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4244                 if ((nd->nd_flag & ND_NFSV41) != 0)
4245                         clientid.qval = nd->nd_clientid.qval;
4246                 else if (nd->nd_clientid.qval != clientid.qval)
4247                         printf("EEK14 multiple clids\n");
4248         } else {
4249                 if ((nd->nd_flag & ND_NFSV41) != 0)
4250                         printf("EEK! no clientid from session\n");
4251                 nd->nd_flag |= ND_IMPLIEDCLID;
4252                 nd->nd_clientid.qval = clientid.qval;
4253         }
4254         error = nfsrv_mtostr(nd, stp->ls_owner, len);
4255         if (error)
4256                 goto nfsmout;
4257         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4258         free(stp, M_NFSDSTATE);
4259
4260         NFSEXITCODE2(0, nd);
4261         return (0);
4262 nfsmout:
4263         if (stp)
4264                 free(stp, M_NFSDSTATE);
4265         NFSEXITCODE2(error, nd);
4266         return (error);
4267 }
4268
4269 /*
4270  * nfsv4 exchange_id service
4271  */
4272 int
4273 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4274     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4275 {
4276         uint32_t *tl;
4277         int error = 0, i, idlen;
4278         struct nfsclient *clp = NULL;
4279         nfsquad_t clientid, confirm;
4280         uint8_t *verf;
4281         uint32_t sp4type, v41flags;
4282         struct timespec verstime;
4283         nfsopbit_t mustops, allowops;
4284 #ifdef INET
4285         struct sockaddr_in *sin, *rin;
4286 #endif
4287 #ifdef INET6
4288         struct sockaddr_in6 *sin6, *rin6;
4289 #endif
4290         struct thread *p = curthread;
4291         char *s;
4292
4293         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4294                 goto nfsmout;
4295         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4296         verf = (uint8_t *)tl;
4297         tl += (NFSX_VERF / NFSX_UNSIGNED);
4298         i = fxdr_unsigned(int, *tl);
4299         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4300                 nd->nd_repstat = NFSERR_BADXDR;
4301                 goto nfsmout;
4302         }
4303         idlen = i;
4304         if (nd->nd_flag & ND_GSS)
4305                 i += nd->nd_princlen;
4306         clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4307             M_ZERO);
4308         clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4309             nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4310         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4311         /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4312         clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4313             M_WAITOK | M_ZERO);
4314         switch (nd->nd_nam->sa_family) {
4315 #ifdef INET
4316         case AF_INET:
4317                 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4318                 sin = (struct sockaddr_in *)nd->nd_nam;
4319                 rin->sin_family = AF_INET;
4320                 rin->sin_len = sizeof(struct sockaddr_in);
4321                 rin->sin_port = 0;
4322                 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4323                 break;
4324 #endif
4325 #ifdef INET6
4326         case AF_INET6:
4327                 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4328                 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4329                 rin6->sin6_family = AF_INET6;
4330                 rin6->sin6_len = sizeof(struct sockaddr_in6);
4331                 rin6->sin6_port = 0;
4332                 rin6->sin6_addr = sin6->sin6_addr;
4333                 break;
4334 #endif
4335         }
4336         clp->lc_req.nr_cred = NULL;
4337         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4338         clp->lc_idlen = idlen;
4339         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4340         if (error != 0)
4341                 goto nfsmout;
4342         if ((nd->nd_flag & ND_GSS) != 0) {
4343                 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4344                 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4345                         clp->lc_flags |= LCL_GSSINTEGRITY;
4346                 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4347                         clp->lc_flags |= LCL_GSSPRIVACY;
4348         } else
4349                 clp->lc_flags = LCL_NFSV41;
4350         if ((nd->nd_flag & ND_NFSV42) != 0)
4351                 clp->lc_flags |= LCL_NFSV42;
4352         if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4353                 clp->lc_flags |= LCL_NAME;
4354                 clp->lc_namelen = nd->nd_princlen;
4355                 clp->lc_name = &clp->lc_id[idlen];
4356                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4357         } else {
4358                 clp->lc_uid = nd->nd_cred->cr_uid;
4359                 clp->lc_gid = nd->nd_cred->cr_gid;
4360         }
4361         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4362         v41flags = fxdr_unsigned(uint32_t, *tl++);
4363         if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4364             NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4365             NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4366                 nd->nd_repstat = NFSERR_INVAL;
4367                 goto nfsmout;
4368         }
4369         if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4370                 confirm.lval[1] = 1;
4371         else
4372                 confirm.lval[1] = 0;
4373         if (nfsrv_devidcnt == 0)
4374                 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4375         else
4376                 v41flags = NFSV4EXCH_USEPNFSMDS;
4377         sp4type = fxdr_unsigned(uint32_t, *tl);
4378         if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4379                 if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
4380                     nd->nd_princlen == 0)
4381                         nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
4382                 if (nd->nd_repstat == 0)
4383                         nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
4384                 if (nd->nd_repstat == 0)
4385                         nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
4386                 if (nd->nd_repstat != 0)
4387                         goto nfsmout;
4388                 NFSOPBIT_CLRNOTMUST(&mustops);
4389                 NFSSET_OPBIT(&clp->lc_mustops, &mustops);
4390                 NFSOPBIT_CLRNOTALLOWED(&allowops);
4391                 NFSSET_OPBIT(&clp->lc_allowops, &allowops);
4392                 clp->lc_flags |= LCL_MACHCRED;
4393         } else if (sp4type != NFSV4EXCH_SP4NONE) {
4394                 nd->nd_repstat = NFSERR_NOTSUPP;
4395                 goto nfsmout;
4396         }
4397
4398         /*
4399          * nfsrv_setclient() does the actual work of adding it to the
4400          * client list. If there is no error, the structure has been
4401          * linked into the client list and clp should no longer be used
4402          * here. When an error is returned, it has not been linked in,
4403          * so it should be free'd.
4404          */
4405         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4406         if (clp != NULL) {
4407                 free(clp->lc_req.nr_nam, M_SONAME);
4408                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4409                 free(clp->lc_stateid, M_NFSDCLIENT);
4410                 free(clp, M_NFSDCLIENT);
4411         }
4412         if (nd->nd_repstat == 0) {
4413                 if (confirm.lval[1] != 0)
4414                         v41flags |= NFSV4EXCH_CONFIRMEDR;
4415                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
4416                 *tl++ = clientid.lval[0];                       /* ClientID */
4417                 *tl++ = clientid.lval[1];
4418                 *tl++ = txdr_unsigned(confirm.lval[0]);         /* SequenceID */
4419                 *tl++ = txdr_unsigned(v41flags);                /* Exch flags */
4420                 *tl = txdr_unsigned(sp4type);                   /* No SSV */
4421                 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4422                         nfsrv_putopbit(nd, &mustops);
4423                         nfsrv_putopbit(nd, &allowops);
4424                 }
4425                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
4426                 txdr_hyper(nfsrv_owner_minor, tl);      /* Owner Minor */
4427                 if (nfsrv_owner_major[0] != 0)
4428                         s = nfsrv_owner_major;
4429                 else
4430                         s = nd->nd_cred->cr_prison->pr_hostuuid;
4431                 nfsm_strtom(nd, s, strlen(s));          /* Owner Major */
4432                 if (nfsrv_scope[0] != 0)
4433                         s = nfsrv_scope;
4434                 else
4435                         s = nd->nd_cred->cr_prison->pr_hostuuid;
4436                 nfsm_strtom(nd, s, strlen(s)    );              /* Scope */
4437                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4438                 *tl = txdr_unsigned(1);
4439                 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4440                 (void)nfsm_strtom(nd, version, strlen(version));
4441                 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4442                 verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
4443                 verstime.tv_nsec = 0;
4444                 txdr_nfsv4time(&verstime, tl);
4445         }
4446         NFSEXITCODE2(0, nd);
4447         return (0);
4448 nfsmout:
4449         if (clp != NULL) {
4450                 free(clp->lc_req.nr_nam, M_SONAME);
4451                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4452                 free(clp->lc_stateid, M_NFSDCLIENT);
4453                 free(clp, M_NFSDCLIENT);
4454         }
4455         NFSEXITCODE2(error, nd);
4456         return (error);
4457 }
4458
4459 /*
4460  * nfsv4 create session service
4461  */
4462 int
4463 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4464     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4465 {
4466         uint32_t *tl;
4467         int error = 0;
4468         nfsquad_t clientid, confirm;
4469         struct nfsdsession *sep = NULL;
4470         uint32_t rdmacnt;
4471         struct thread *p = curthread;
4472         static bool do_printf = true;
4473
4474         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4475                 goto nfsmout;
4476         sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4477             M_NFSDSESSION, M_WAITOK | M_ZERO);
4478         sep->sess_refcnt = 1;
4479         mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4480         NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4481         clientid.lval[0] = *tl++;
4482         clientid.lval[1] = *tl++;
4483         confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4484         sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4485         /* Persistent sessions and RDMA are not supported. */
4486         sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4487
4488         /* Fore channel attributes. */
4489         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4490         tl++;                                   /* Header pad always 0. */
4491         sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4492         if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4493                 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4494                 if (do_printf)
4495                         printf("Consider increasing kern.ipc.maxsockbuf\n");
4496                 do_printf = false;
4497         }
4498         sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4499         if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4500                 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4501                 if (do_printf)
4502                         printf("Consider increasing kern.ipc.maxsockbuf\n");
4503                 do_printf = false;
4504         }
4505         sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4506         sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4507         sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4508         if (sep->sess_maxslots > NFSV4_SLOTS)
4509                 sep->sess_maxslots = NFSV4_SLOTS;
4510         rdmacnt = fxdr_unsigned(uint32_t, *tl);
4511         if (rdmacnt > 1) {
4512                 nd->nd_repstat = NFSERR_BADXDR;
4513                 goto nfsmout;
4514         } else if (rdmacnt == 1)
4515                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4516
4517         /* Back channel attributes. */
4518         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4519         tl++;                                   /* Header pad always 0. */
4520         sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4521         sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4522         sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4523         sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4524         sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4525         rdmacnt = fxdr_unsigned(uint32_t, *tl);
4526         if (rdmacnt > 1) {
4527                 nd->nd_repstat = NFSERR_BADXDR;
4528                 goto nfsmout;
4529         } else if (rdmacnt == 1)
4530                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4531
4532         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4533         sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4534
4535         /*
4536          * nfsrv_getclient() searches the client list for a match and
4537          * returns the appropriate NFSERR status.
4538          */
4539         nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4540             NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4541         if (nd->nd_repstat == 0) {
4542                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4543                 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4544                 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4545                 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4546                 *tl++ = txdr_unsigned(sep->sess_crflags);
4547
4548                 /* Fore channel attributes. */
4549                 *tl++ = 0;
4550                 *tl++ = txdr_unsigned(sep->sess_maxreq);
4551                 *tl++ = txdr_unsigned(sep->sess_maxresp);
4552                 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4553                 *tl++ = txdr_unsigned(sep->sess_maxops);
4554                 *tl++ = txdr_unsigned(sep->sess_maxslots);
4555                 *tl++ = txdr_unsigned(1);
4556                 *tl++ = txdr_unsigned(0);                       /* No RDMA. */
4557
4558                 /* Back channel attributes. */
4559                 *tl++ = 0;
4560                 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4561                 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4562                 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4563                 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4564                 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4565                 *tl++ = txdr_unsigned(1);
4566                 *tl = txdr_unsigned(0);                 /* No RDMA. */
4567         }
4568 nfsmout:
4569         if (nd->nd_repstat != 0 && sep != NULL)
4570                 free(sep, M_NFSDSESSION);
4571         NFSEXITCODE2(error, nd);
4572         return (error);
4573 }
4574
4575 /*
4576  * nfsv4 sequence service
4577  */
4578 int
4579 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4580     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4581 {
4582         uint32_t *tl;
4583         uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4584         int cache_this, error = 0;
4585         struct thread *p = curthread;
4586
4587         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4588                 goto nfsmout;
4589         NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4590         NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4591         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4592         sequenceid = fxdr_unsigned(uint32_t, *tl++);
4593         nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4594         highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4595         if (*tl == newnfs_true)
4596                 cache_this = 1;
4597         else
4598                 cache_this = 0;
4599         nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4600             &target_highest_slotid, cache_this, &sflags, p);
4601         if (nd->nd_repstat != NFSERR_BADSLOT)
4602                 nd->nd_flag |= ND_HASSEQUENCE;
4603         if (nd->nd_repstat == 0) {
4604                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4605                 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4606                 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4607                 *tl++ = txdr_unsigned(sequenceid);
4608                 *tl++ = txdr_unsigned(nd->nd_slotid);
4609                 *tl++ = txdr_unsigned(highest_slotid);
4610                 *tl++ = txdr_unsigned(target_highest_slotid);
4611                 *tl = txdr_unsigned(sflags);
4612         }
4613 nfsmout:
4614         NFSEXITCODE2(error, nd);
4615         return (error);
4616 }
4617
4618 /*
4619  * nfsv4 reclaim complete service
4620  */
4621 int
4622 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4623     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4624 {
4625         uint32_t *tl;
4626         int error = 0, onefs;
4627
4628         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4629         /*
4630          * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4631          * to be used after a file system has been transferred to a different
4632          * file server.  However, RFC5661 is somewhat vague w.r.t. this and
4633          * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4634          * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4635          * Therefore, just ignore the rca_one_fs == TRUE operation and return
4636          * NFS_OK without doing anything.
4637          */
4638         onefs = 0;
4639         if (*tl == newnfs_true)
4640                 onefs = 1;
4641         nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4642 nfsmout:
4643         NFSEXITCODE2(error, nd);
4644         return (error);
4645 }
4646
4647 /*
4648  * nfsv4 destroy clientid service
4649  */
4650 int
4651 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4652     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4653 {
4654         uint32_t *tl;
4655         nfsquad_t clientid;
4656         int error = 0;
4657         struct thread *p = curthread;
4658
4659         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4660                 goto nfsmout;
4661         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4662         clientid.lval[0] = *tl++;
4663         clientid.lval[1] = *tl;
4664         nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
4665 nfsmout:
4666         NFSEXITCODE2(error, nd);
4667         return (error);
4668 }
4669
4670 /*
4671  * nfsv4 bind connection to session service
4672  */
4673 int
4674 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4675     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4676 {
4677         uint32_t *tl;
4678         uint8_t sessid[NFSX_V4SESSIONID];
4679         int error = 0, foreaft;
4680
4681         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4682                 goto nfsmout;
4683         NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4684         NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4685         tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4686         foreaft = fxdr_unsigned(int, *tl++);
4687         if (*tl == newnfs_true) {
4688                 /* RDMA is not supported. */
4689                 nd->nd_repstat = NFSERR_NOTSUPP;
4690                 goto nfsmout;
4691         }
4692
4693         nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4694         if (nd->nd_repstat == 0) {
4695                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4696                     NFSX_UNSIGNED);
4697                 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4698                 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4699                 *tl++ = txdr_unsigned(foreaft);
4700                 *tl = newnfs_false;
4701         }
4702 nfsmout:
4703         NFSEXITCODE2(error, nd);
4704         return (error);
4705 }
4706
4707 /*
4708  * nfsv4 destroy session service
4709  */
4710 int
4711 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4712     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4713 {
4714         uint8_t *cp, sessid[NFSX_V4SESSIONID];
4715         int error = 0;
4716
4717         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4718                 goto nfsmout;
4719         NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4720         NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4721         nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4722 nfsmout:
4723         NFSEXITCODE2(error, nd);
4724         return (error);
4725 }
4726
4727 /*
4728  * nfsv4 free stateid service
4729  */
4730 int
4731 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4732     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4733 {
4734         uint32_t *tl;
4735         nfsv4stateid_t stateid;
4736         int error = 0;
4737         struct thread *p = curthread;
4738
4739         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4740         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4741         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4742
4743         /*
4744          * For the special stateid of other all 0s and seqid == 1, set the
4745          * stateid to the current stateid, if it is set.
4746          */
4747         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4748             stateid.other[1] == 0 && stateid.other[2] == 0) {
4749                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4750                         stateid = nd->nd_curstateid;
4751                         stateid.seqid = 0;
4752                 } else {
4753                         nd->nd_repstat = NFSERR_BADSTATEID;
4754                         goto nfsmout;
4755                 }
4756         }
4757
4758         nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4759
4760         /* If the current stateid has been free'd, unset it. */
4761         if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4762             stateid.other[0] == nd->nd_curstateid.other[0] &&
4763             stateid.other[1] == nd->nd_curstateid.other[1] &&
4764             stateid.other[2] == nd->nd_curstateid.other[2])
4765                 nd->nd_flag &= ~ND_CURSTATEID;
4766 nfsmout:
4767         NFSEXITCODE2(error, nd);
4768         return (error);
4769 }
4770
4771 /*
4772  * nfsv4 layoutget service
4773  */
4774 int
4775 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4776     vnode_t vp, struct nfsexstuff *exp)
4777 {
4778         uint32_t *tl;
4779         nfsv4stateid_t stateid;
4780         int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4781         uint64_t offset, len, minlen;
4782         char *layp;
4783         struct thread *p = curthread;
4784
4785         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4786             NFSX_STATEID);
4787         tl++;           /* Signal layout available. Ignore for now. */
4788         layouttype = fxdr_unsigned(int, *tl++);
4789         iomode = fxdr_unsigned(int, *tl++);
4790         offset = fxdr_hyper(tl); tl += 2;
4791         len = fxdr_hyper(tl); tl += 2;
4792         minlen = fxdr_hyper(tl); tl += 2;
4793         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4794         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4795         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4796         maxcnt = fxdr_unsigned(int, *tl);
4797         NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4798             layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4799             (uintmax_t)minlen);
4800         if (len < minlen ||
4801             (minlen != UINT64_MAX && offset + minlen < offset) ||
4802             (len != UINT64_MAX && offset + len < offset)) {
4803                 nd->nd_repstat = NFSERR_INVAL;
4804                 goto nfsmout;
4805         }
4806
4807         /*
4808          * For the special stateid of other all 0s and seqid == 1, set the
4809          * stateid to the current stateid, if it is set.
4810          */
4811         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4812             stateid.other[1] == 0 && stateid.other[2] == 0) {
4813                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4814                         stateid = nd->nd_curstateid;
4815                         stateid.seqid = 0;
4816                 } else {
4817                         nd->nd_repstat = NFSERR_BADSTATEID;
4818                         goto nfsmout;
4819                 }
4820         }
4821
4822         layp = NULL;
4823         if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4824                 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4825         else if (layouttype == NFSLAYOUT_FLEXFILE)
4826                 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4827                     M_WAITOK);
4828         else
4829                 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4830         if (layp != NULL)
4831                 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4832                     &iomode, &offset, &len, minlen, &stateid, maxcnt,
4833                     &retonclose, &layoutlen, layp, nd->nd_cred, p);
4834         NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4835             layoutlen);
4836         if (nd->nd_repstat == 0) {
4837                 /* For NFSv4.1, set the Current StateID. */
4838                 if ((nd->nd_flag & ND_NFSV41) != 0) {
4839                         nd->nd_curstateid = stateid;
4840                         nd->nd_flag |= ND_CURSTATEID;
4841                 }
4842                 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4843                     2 * NFSX_HYPER);
4844                 *tl++ = txdr_unsigned(retonclose);
4845                 *tl++ = txdr_unsigned(stateid.seqid);
4846                 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4847                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4848                 *tl++ = txdr_unsigned(1);       /* Only returns one layout. */
4849                 txdr_hyper(offset, tl); tl += 2;
4850                 txdr_hyper(len, tl); tl += 2;
4851                 *tl++ = txdr_unsigned(iomode);
4852                 *tl = txdr_unsigned(layouttype);
4853                 nfsm_strtom(nd, layp, layoutlen);
4854         } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4855                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4856                 *tl = newnfs_false;
4857         }
4858         free(layp, M_TEMP);
4859 nfsmout:
4860         vput(vp);
4861         NFSEXITCODE2(error, nd);
4862         return (error);
4863 }
4864
4865 /*
4866  * nfsv4 layoutcommit service
4867  */
4868 int
4869 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4870     vnode_t vp, struct nfsexstuff *exp)
4871 {
4872         uint32_t *tl;
4873         nfsv4stateid_t stateid;
4874         int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4875         int hasnewsize;
4876         uint64_t offset, len, newoff = 0, newsize;
4877         struct timespec newmtime;
4878         char *layp;
4879         struct thread *p = curthread;
4880
4881         layp = NULL;
4882         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4883             NFSX_STATEID);
4884         offset = fxdr_hyper(tl); tl += 2;
4885         len = fxdr_hyper(tl); tl += 2;
4886         reclaim = fxdr_unsigned(int, *tl++);
4887         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4888         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4889         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4890         /*
4891          * For the special stateid of other all 0s and seqid == 1, set the
4892          * stateid to the current stateid, if it is set.
4893          */
4894         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4895             stateid.other[1] == 0 && stateid.other[2] == 0) {
4896                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4897                         stateid = nd->nd_curstateid;
4898                         stateid.seqid = 0;
4899                 } else {
4900                         nd->nd_repstat = NFSERR_BADSTATEID;
4901                         goto nfsmout;
4902                 }
4903         }
4904
4905         hasnewoff = fxdr_unsigned(int, *tl);
4906         if (hasnewoff != 0) {
4907                 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4908                 newoff = fxdr_hyper(tl); tl += 2;
4909         } else
4910                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4911         hasnewmtime = fxdr_unsigned(int, *tl);
4912         if (hasnewmtime != 0) {
4913                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4914                 fxdr_nfsv4time(tl, &newmtime);
4915                 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4916         } else
4917                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4918         layouttype = fxdr_unsigned(int, *tl++);
4919         maxcnt = fxdr_unsigned(int, *tl);
4920         if (maxcnt > 0) {
4921                 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4922                 error = nfsrv_mtostr(nd, layp, maxcnt);
4923                 if (error != 0)
4924                         goto nfsmout;
4925         }
4926         nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4927             newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4928             maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4929         NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4930         if (nd->nd_repstat == 0) {
4931                 if (hasnewsize != 0) {
4932                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4933                         *tl++ = newnfs_true;
4934                         txdr_hyper(newsize, tl);
4935                 } else {
4936                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4937                         *tl = newnfs_false;
4938                 }
4939         }
4940 nfsmout:
4941         free(layp, M_TEMP);
4942         vput(vp);
4943         NFSEXITCODE2(error, nd);
4944         return (error);
4945 }
4946
4947 /*
4948  * nfsv4 layoutreturn service
4949  */
4950 int
4951 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4952     vnode_t vp, struct nfsexstuff *exp)
4953 {
4954         uint32_t *tl, *layp;
4955         nfsv4stateid_t stateid;
4956         int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4957         uint64_t offset, len;
4958         struct thread *p = curthread;
4959
4960         layp = NULL;
4961         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4962         reclaim = *tl++;
4963         layouttype = fxdr_unsigned(int, *tl++);
4964         iomode = fxdr_unsigned(int, *tl++);
4965         kind = fxdr_unsigned(int, *tl);
4966         NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4967             layouttype, iomode, kind);
4968         if (kind == NFSV4LAYOUTRET_FILE) {
4969                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4970                     NFSX_UNSIGNED);
4971                 offset = fxdr_hyper(tl); tl += 2;
4972                 len = fxdr_hyper(tl); tl += 2;
4973                 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4974                 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4975                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4976
4977                 /*
4978                  * For the special stateid of other all 0s and seqid == 1, set
4979                  * the stateid to the current stateid, if it is set.
4980                  */
4981                 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4982                     stateid.other[1] == 0 && stateid.other[2] == 0) {
4983                         if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4984                                 stateid = nd->nd_curstateid;
4985                                 stateid.seqid = 0;
4986                         } else {
4987                                 nd->nd_repstat = NFSERR_BADSTATEID;
4988                                 goto nfsmout;
4989                         }
4990                 }
4991
4992                 maxcnt = fxdr_unsigned(int, *tl);
4993                 /*
4994                  * There is no fixed upper bound defined in the RFCs,
4995                  * but 128Kbytes should be more than sufficient.
4996                  */
4997                 if (maxcnt < 0 || maxcnt > 131072)
4998                         maxcnt = 0;
4999                 if (maxcnt > 0) {
5000                         layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5001                         error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5002                         if (error != 0)
5003                                 goto nfsmout;
5004                 }
5005         } else {
5006                 if (reclaim == newnfs_true) {
5007                         nd->nd_repstat = NFSERR_INVAL;
5008                         goto nfsmout;
5009                 }
5010                 offset = len = 0;
5011                 maxcnt = 0;
5012         }
5013         nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5014             offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5015             nd->nd_cred, p);
5016         NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5017             fnd);
5018         if (nd->nd_repstat == 0) {
5019                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5020                 if (fnd != 0) {
5021                         *tl = newnfs_true;
5022                         NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5023                         *tl++ = txdr_unsigned(stateid.seqid);
5024                         NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5025                 } else
5026                         *tl = newnfs_false;
5027         }
5028 nfsmout:
5029         free(layp, M_TEMP);
5030         vput(vp);
5031         NFSEXITCODE2(error, nd);
5032         return (error);
5033 }
5034
5035 /*
5036  * nfsv4 layout error service
5037  */
5038 int
5039 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5040     vnode_t vp, struct nfsexstuff *exp)
5041 {
5042         uint32_t *tl;
5043         nfsv4stateid_t stateid;
5044         int cnt, error = 0, i, stat;
5045         int opnum __unused;
5046         char devid[NFSX_V4DEVICEID];
5047         uint64_t offset, len;
5048
5049         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5050             NFSX_UNSIGNED);
5051         offset = fxdr_hyper(tl); tl += 2;
5052         len = fxdr_hyper(tl); tl += 2;
5053         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5054         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5055         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5056         cnt = fxdr_unsigned(int, *tl);
5057         NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5058             (uintmax_t)len, cnt);
5059         /*
5060          * For the special stateid of other all 0s and seqid == 1, set
5061          * the stateid to the current stateid, if it is set.
5062          */
5063         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5064             stateid.other[1] == 0 && stateid.other[2] == 0) {
5065                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5066                         stateid = nd->nd_curstateid;
5067                         stateid.seqid = 0;
5068                 } else {
5069                         nd->nd_repstat = NFSERR_BADSTATEID;
5070                         goto nfsmout;
5071                 }
5072         }
5073
5074         /*
5075          * Ignore offset, len and stateid for now.
5076          */
5077         for (i = 0; i < cnt; i++) {
5078                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5079                     NFSX_UNSIGNED);
5080                 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5081                 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5082                 stat = fxdr_unsigned(int, *tl++);
5083                 opnum = fxdr_unsigned(int, *tl);
5084                 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5085                 /*
5086                  * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5087                  * errors, disable the mirror.
5088                  */
5089                 if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5090                     stat != NFSERR_NOSPC)
5091                         nfsrv_delds(devid, curthread);
5092
5093                 /* For NFSERR_NOSPC, mark all deviceids and layouts. */
5094                 if (stat == NFSERR_NOSPC)
5095                         nfsrv_marknospc(devid, true);
5096         }
5097 nfsmout:
5098         vput(vp);
5099         NFSEXITCODE2(error, nd);
5100         return (error);
5101 }
5102
5103 /*
5104  * nfsv4 layout stats service
5105  */
5106 int
5107 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5108     vnode_t vp, struct nfsexstuff *exp)
5109 {
5110         uint32_t *tl;
5111         nfsv4stateid_t stateid;
5112         int cnt, error = 0;
5113         int layouttype __unused;
5114         char devid[NFSX_V4DEVICEID] __unused;
5115         uint64_t offset __unused, len __unused, readcount __unused;
5116         uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5117
5118         NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5119             NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5120         offset = fxdr_hyper(tl); tl += 2;
5121         len = fxdr_hyper(tl); tl += 2;
5122         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5123         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5124         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5125         readcount = fxdr_hyper(tl); tl += 2;
5126         readbytes = fxdr_hyper(tl); tl += 2;
5127         writecount = fxdr_hyper(tl); tl += 2;
5128         writebytes = fxdr_hyper(tl); tl += 2;
5129         NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5130         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5131         layouttype = fxdr_unsigned(int, *tl++);
5132         cnt = fxdr_unsigned(int, *tl);
5133         error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5134         if (error != 0)
5135                 goto nfsmout;
5136         NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5137         /*
5138          * For the special stateid of other all 0s and seqid == 1, set
5139          * the stateid to the current stateid, if it is set.
5140          */
5141         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5142             stateid.other[1] == 0 && stateid.other[2] == 0) {
5143                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5144                         stateid = nd->nd_curstateid;
5145                         stateid.seqid = 0;
5146                 } else {
5147                         nd->nd_repstat = NFSERR_BADSTATEID;
5148                         goto nfsmout;
5149                 }
5150         }
5151
5152         /*
5153          * No use for the stats for now.
5154          */
5155 nfsmout:
5156         vput(vp);
5157         NFSEXITCODE2(error, nd);
5158         return (error);
5159 }
5160
5161 /*
5162  * nfsv4 io_advise service
5163  */
5164 int
5165 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5166     vnode_t vp, struct nfsexstuff *exp)
5167 {
5168         uint32_t *tl;
5169         nfsv4stateid_t stateid;
5170         nfsattrbit_t hints;
5171         int error = 0, ret;
5172         off_t offset, len;
5173
5174         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5175         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5176         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5177         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5178         offset = fxdr_hyper(tl); tl += 2;
5179         len = fxdr_hyper(tl);
5180         error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5181         if (error != 0)
5182                 goto nfsmout;
5183         /*
5184          * For the special stateid of other all 0s and seqid == 1, set
5185          * the stateid to the current stateid, if it is set.
5186          */
5187         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5188             stateid.other[1] == 0 && stateid.other[2] == 0) {
5189                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5190                         stateid = nd->nd_curstateid;
5191                         stateid.seqid = 0;
5192                 } else {
5193                         nd->nd_repstat = NFSERR_BADSTATEID;
5194                         goto nfsmout;
5195                 }
5196         }
5197
5198         if (offset < 0) {
5199                 nd->nd_repstat = NFSERR_INVAL;
5200                 goto nfsmout;
5201         }
5202         if (len < 0)
5203                 len = 0;
5204         if (vp->v_type != VREG) {
5205                 if (vp->v_type == VDIR)
5206                         nd->nd_repstat = NFSERR_ISDIR;
5207                 else
5208                         nd->nd_repstat = NFSERR_WRONGTYPE;
5209                 goto nfsmout;
5210         }
5211
5212         /*
5213          * For now, we can only handle WILLNEED and DONTNEED and don't use
5214          * the stateid.
5215          */
5216         if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5217             !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5218             (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5219             !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5220                 NFSVOPUNLOCK(vp);
5221                 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5222                         ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5223                         NFSZERO_ATTRBIT(&hints);
5224                         if (ret == 0)
5225                                 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5226                         else
5227                                 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5228                 } else {
5229                         ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5230                         NFSZERO_ATTRBIT(&hints);
5231                         if (ret == 0)
5232                                 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5233                         else
5234                                 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5235                 }
5236                 vrele(vp);
5237         } else {
5238                 NFSZERO_ATTRBIT(&hints);
5239                 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5240                 vput(vp);
5241         }
5242         nfsrv_putattrbit(nd, &hints);
5243         NFSEXITCODE2(error, nd);
5244         return (error);
5245 nfsmout:
5246         vput(vp);
5247         NFSEXITCODE2(error, nd);
5248         return (error);
5249 }
5250
5251 /*
5252  * nfsv4 getdeviceinfo service
5253  */
5254 int
5255 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5256     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5257 {
5258         uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5259         int cnt, devaddrlen, error = 0, i, layouttype;
5260         char devid[NFSX_V4DEVICEID], *devaddr;
5261         time_t dev_time;
5262
5263         NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5264         NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5265         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5266         layouttype = fxdr_unsigned(int, *tl++);
5267         maxcnt = fxdr_unsigned(uint32_t, *tl++);
5268         cnt = fxdr_unsigned(int, *tl);
5269         NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5270             maxcnt, cnt);
5271         if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5272                 nd->nd_repstat = NFSERR_INVAL;
5273                 goto nfsmout;
5274         }
5275         if (cnt > 0) {
5276                 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5277                 for (i = 0; i < cnt; i++)
5278                         notify[i] = fxdr_unsigned(uint32_t, *tl++);
5279         }
5280         for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5281                 notify[i] = 0;
5282
5283         /*
5284          * Check that the device id is not stale.  Device ids are recreated
5285          * each time the nfsd threads are restarted.
5286          */
5287         NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5288         if (dev_time != nfsdev_time) {
5289                 nd->nd_repstat = NFSERR_NOENT;
5290                 goto nfsmout;
5291         }
5292
5293         /* Look for the device id. */
5294         nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5295             notify, &devaddrlen, &devaddr);
5296         NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5297         if (nd->nd_repstat == 0) {
5298                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5299                 *tl = txdr_unsigned(layouttype);
5300                 nfsm_strtom(nd, devaddr, devaddrlen);
5301                 cnt = 0;
5302                 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5303                         if (notify[i] != 0)
5304                                 cnt = i + 1;
5305                 }
5306                 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5307                 *tl++ = txdr_unsigned(cnt);
5308                 for (i = 0; i < cnt; i++)
5309                         *tl++ = txdr_unsigned(notify[i]);
5310         } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5311                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5312                 *tl = txdr_unsigned(maxcnt);
5313         }
5314 nfsmout:
5315         NFSEXITCODE2(error, nd);
5316         return (error);
5317 }
5318
5319 /*
5320  * nfsv4 test stateid service
5321  */
5322 int
5323 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5324     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5325 {
5326         uint32_t *tl;
5327         nfsv4stateid_t *stateidp = NULL, *tstateidp;
5328         int cnt, error = 0, i, ret;
5329         struct thread *p = curthread;
5330
5331         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5332         cnt = fxdr_unsigned(int, *tl);
5333         if (cnt <= 0 || cnt > 1024) {
5334                 nd->nd_repstat = NFSERR_BADXDR;
5335                 goto nfsmout;
5336         }
5337         stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5338         tstateidp = stateidp;
5339         for (i = 0; i < cnt; i++) {
5340                 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5341                 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5342                 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5343                 tstateidp++;
5344         }
5345         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5346         *tl = txdr_unsigned(cnt);
5347         tstateidp = stateidp;
5348         for (i = 0; i < cnt; i++) {
5349                 ret = nfsrv_teststateid(nd, tstateidp, p);
5350                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5351                 *tl = txdr_unsigned(ret);
5352                 tstateidp++;
5353         }
5354 nfsmout:
5355         free(stateidp, M_TEMP);
5356         NFSEXITCODE2(error, nd);
5357         return (error);
5358 }
5359
5360 /*
5361  * nfs allocate service
5362  */
5363 int
5364 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5365     vnode_t vp, struct nfsexstuff *exp)
5366 {
5367         uint32_t *tl;
5368         struct nfsvattr forat;
5369         int error = 0, forat_ret = 1, gotproxystateid;
5370         off_t off, len;
5371         struct nfsstate st, *stp = &st;
5372         struct nfslock lo, *lop = &lo;
5373         nfsv4stateid_t stateid;
5374         nfsquad_t clientid;
5375         nfsattrbit_t attrbits;
5376
5377         if (!nfsrv_doallocate) {
5378                 /*
5379                  * If any exported file system, such as a ZFS one, cannot
5380                  * do VOP_ALLOCATE(), this operation cannot be supported
5381                  * for NFSv4.2.  This cannot be done 'per filesystem', but
5382                  * must be for the entire nfsd NFSv4.2 service.
5383                  */
5384                 nd->nd_repstat = NFSERR_NOTSUPP;
5385                 goto nfsmout;
5386         }
5387         gotproxystateid = 0;
5388         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5389         stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5390         lop->lo_flags = NFSLCK_WRITE;
5391         stp->ls_ownerlen = 0;
5392         stp->ls_op = NULL;
5393         stp->ls_uid = nd->nd_cred->cr_uid;
5394         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5395         clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5396         clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5397         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5398                 if ((nd->nd_flag & ND_NFSV41) != 0)
5399                         clientid.qval = nd->nd_clientid.qval;
5400                 else if (nd->nd_clientid.qval != clientid.qval)
5401                         printf("EEK2 multiple clids\n");
5402         } else {
5403                 if ((nd->nd_flag & ND_NFSV41) != 0)
5404                         printf("EEK! no clientid from session\n");
5405                 nd->nd_flag |= ND_IMPLIEDCLID;
5406                 nd->nd_clientid.qval = clientid.qval;
5407         }
5408         stp->ls_stateid.other[2] = *tl++;
5409         /*
5410          * Don't allow this to be done for a DS.
5411          */
5412         if ((nd->nd_flag & ND_DSSERVER) != 0)
5413                 nd->nd_repstat = NFSERR_NOTSUPP;
5414         /* However, allow the proxy stateid. */
5415         if (stp->ls_stateid.seqid == 0xffffffff &&
5416             stp->ls_stateid.other[0] == 0x55555555 &&
5417             stp->ls_stateid.other[1] == 0x55555555 &&
5418             stp->ls_stateid.other[2] == 0x55555555)
5419                 gotproxystateid = 1;
5420         off = fxdr_hyper(tl); tl += 2;
5421         lop->lo_first = off;
5422         len = fxdr_hyper(tl);
5423         lop->lo_end = lop->lo_first + len;
5424         /*
5425          * Sanity check the offset and length.
5426          * off and len are off_t (signed int64_t) whereas
5427          * lo_first and lo_end are uint64_t and, as such,
5428          * if off >= 0 && len > 0, lo_end cannot overflow
5429          * unless off_t is changed to something other than
5430          * int64_t.  Check lo_end < lo_first in case that
5431          * is someday the case.
5432          */
5433         if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5434             OFF_MAX || lop->lo_end < lop->lo_first))
5435                 nd->nd_repstat = NFSERR_INVAL;
5436
5437         if (nd->nd_repstat == 0 && vp->v_type != VREG)
5438                 nd->nd_repstat = NFSERR_WRONGTYPE;
5439         NFSZERO_ATTRBIT(&attrbits);
5440         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5441         forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5442         if (nd->nd_repstat == 0)
5443                 nd->nd_repstat = forat_ret;
5444         if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5445              NFSVNO_EXSTRICTACCESS(exp)))
5446                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5447                     curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5448                     NULL);
5449         if (nd->nd_repstat == 0 && gotproxystateid == 0)
5450                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5451                     &stateid, exp, nd, curthread);
5452
5453         NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5454             (intmax_t)off, (intmax_t)len, nd->nd_repstat);
5455         if (nd->nd_repstat == 0)
5456                 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5457                     curthread);
5458         NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5459             nd->nd_repstat);
5460         vput(vp);
5461         NFSEXITCODE2(0, nd);
5462         return (0);
5463 nfsmout:
5464         vput(vp);
5465         NFSEXITCODE2(error, nd);
5466         return (error);
5467 }
5468
5469 /*
5470  * nfs deallocate service
5471  */
5472 int
5473 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5474     vnode_t vp, struct nfsexstuff *exp)
5475 {
5476         uint32_t *tl;
5477         struct nfsvattr forat;
5478         int error = 0, forat_ret = 1, gotproxystateid;
5479         off_t off, len;
5480         struct nfsstate st, *stp = &st;
5481         struct nfslock lo, *lop = &lo;
5482         nfsv4stateid_t stateid;
5483         nfsquad_t clientid;
5484         nfsattrbit_t attrbits;
5485
5486         gotproxystateid = 0;
5487         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5488         stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5489         lop->lo_flags = NFSLCK_WRITE;
5490         stp->ls_ownerlen = 0;
5491         stp->ls_op = NULL;
5492         stp->ls_uid = nd->nd_cred->cr_uid;
5493         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5494         clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5495         clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5496         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5497                 if ((nd->nd_flag & ND_NFSV41) != 0)
5498                         clientid.qval = nd->nd_clientid.qval;
5499                 else if (nd->nd_clientid.qval != clientid.qval)
5500                         printf("EEK2 multiple clids\n");
5501         } else {
5502                 if ((nd->nd_flag & ND_NFSV41) != 0)
5503                         printf("EEK! no clientid from session\n");
5504                 nd->nd_flag |= ND_IMPLIEDCLID;
5505                 nd->nd_clientid.qval = clientid.qval;
5506         }
5507         stp->ls_stateid.other[2] = *tl++;
5508         /*
5509          * Don't allow this to be done for a DS.
5510          */
5511         if ((nd->nd_flag & ND_DSSERVER) != 0)
5512                 nd->nd_repstat = NFSERR_NOTSUPP;
5513         /* However, allow the proxy stateid. */
5514         if (stp->ls_stateid.seqid == 0xffffffff &&
5515             stp->ls_stateid.other[0] == 0x55555555 &&
5516             stp->ls_stateid.other[1] == 0x55555555 &&
5517             stp->ls_stateid.other[2] == 0x55555555)
5518                 gotproxystateid = 1;
5519         off = fxdr_hyper(tl); tl += 2;
5520         lop->lo_first = off;
5521         len = fxdr_hyper(tl);
5522         if (len < 0)
5523                 len = OFF_MAX;
5524         NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5525             (intmax_t)len);
5526         lop->lo_end = lop->lo_first + len;
5527         /*
5528          * Sanity check the offset and length.
5529          * off and len are off_t (signed int64_t) whereas
5530          * lo_first and lo_end are uint64_t and, as such,
5531          * if off >= 0 && len > 0, lo_end cannot overflow
5532          * unless off_t is changed to something other than
5533          * int64_t.  Check lo_end < lo_first in case that
5534          * is someday the case.
5535          * The error to return is not specified by RFC 7862 so I
5536          * made this compatible with the Linux knfsd.
5537          */
5538         if (nd->nd_repstat == 0) {
5539                 if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5540                         nd->nd_repstat = NFSERR_FBIG;
5541                 else if (len == 0 || lop->lo_end < lop->lo_first)
5542                         nd->nd_repstat = NFSERR_INVAL;
5543         }
5544
5545         if (nd->nd_repstat == 0 && vp->v_type != VREG)
5546                 nd->nd_repstat = NFSERR_WRONGTYPE;
5547         NFSZERO_ATTRBIT(&attrbits);
5548         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5549         forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5550         if (nd->nd_repstat == 0)
5551                 nd->nd_repstat = forat_ret;
5552         if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5553              NFSVNO_EXSTRICTACCESS(exp)))
5554                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5555                     curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5556                     NULL);
5557         if (nd->nd_repstat == 0 && gotproxystateid == 0)
5558                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5559                     &stateid, exp, nd, curthread);
5560
5561         if (nd->nd_repstat == 0)
5562                 nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5563                     curthread);
5564         vput(vp);
5565         NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5566         NFSEXITCODE2(0, nd);
5567         return (0);
5568 nfsmout:
5569         vput(vp);
5570         NFSEXITCODE2(error, nd);
5571         return (error);
5572 }
5573
5574 /*
5575  * nfs copy service
5576  */
5577 int
5578 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5579     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5580 {
5581         uint32_t *tl;
5582         struct nfsvattr at;
5583         int cnt, error = 0, ret;
5584         off_t inoff, outoff;
5585         uint64_t len;
5586         size_t xfer;
5587         struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5588         struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5589         nfsquad_t clientid;
5590         nfsv4stateid_t stateid;
5591         nfsattrbit_t attrbits;
5592         void *rl_rcookie, *rl_wcookie;
5593
5594         rl_rcookie = rl_wcookie = NULL;
5595         if (nfsrv_devidcnt > 0) {
5596                 /*
5597                  * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5598                  * will do the copy via I/O on the DS(s).
5599                  */
5600                 nd->nd_repstat = NFSERR_NOTSUPP;
5601                 goto nfsmout;
5602         }
5603         if (vp == tovp) {
5604                 /* Copying a byte range within the same file is not allowed. */
5605                 nd->nd_repstat = NFSERR_INVAL;
5606                 goto nfsmout;
5607         }
5608         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5609             3 * NFSX_UNSIGNED);
5610         instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5611         inlop->lo_flags = NFSLCK_READ;
5612         instp->ls_ownerlen = 0;
5613         instp->ls_op = NULL;
5614         instp->ls_uid = nd->nd_cred->cr_uid;
5615         instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5616         clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5617         clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5618         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5619                 clientid.qval = nd->nd_clientid.qval;
5620         instp->ls_stateid.other[2] = *tl++;
5621         outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5622         outlop->lo_flags = NFSLCK_WRITE;
5623         outstp->ls_ownerlen = 0;
5624         outstp->ls_op = NULL;
5625         outstp->ls_uid = nd->nd_cred->cr_uid;
5626         outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5627         outstp->ls_stateid.other[0] = *tl++;
5628         outstp->ls_stateid.other[1] = *tl++;
5629         outstp->ls_stateid.other[2] = *tl++;
5630         inoff = fxdr_hyper(tl); tl += 2;
5631         inlop->lo_first = inoff;
5632         outoff = fxdr_hyper(tl); tl += 2;
5633         outlop->lo_first = outoff;
5634         len = fxdr_hyper(tl); tl += 2;
5635         if (len == 0) {
5636                 /* len == 0 means to EOF. */
5637                 inlop->lo_end = OFF_MAX;
5638                 outlop->lo_end = OFF_MAX;
5639         } else {
5640                 inlop->lo_end = inlop->lo_first + len;
5641                 outlop->lo_end = outlop->lo_first + len;
5642         }
5643
5644         /*
5645          * At this time only consecutive, synchronous copy is supported,
5646          * so ca_consecutive and ca_synchronous can be ignored.
5647          */
5648         tl += 2;
5649
5650         cnt = fxdr_unsigned(int, *tl);
5651         if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5652                 nd->nd_repstat = NFSERR_NOTSUPP;
5653         if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5654             inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5655             inlop->lo_end < inlop->lo_first || outlop->lo_end <
5656             outlop->lo_first))
5657                 nd->nd_repstat = NFSERR_INVAL;
5658
5659         if (nd->nd_repstat == 0 && vp->v_type != VREG)
5660                 nd->nd_repstat = NFSERR_WRONGTYPE;
5661
5662         /* Check permissions for the input file. */
5663         NFSZERO_ATTRBIT(&attrbits);
5664         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5665         ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5666         if (nd->nd_repstat == 0)
5667                 nd->nd_repstat = ret;
5668         if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5669              NFSVNO_EXSTRICTACCESS(exp)))
5670                 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5671                     curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5672                     NULL);
5673         if (nd->nd_repstat == 0)
5674                 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5675                     clientid, &stateid, exp, nd, curthread);
5676         NFSVOPUNLOCK(vp);
5677         if (nd->nd_repstat != 0)
5678                 goto out;
5679
5680         error = NFSVOPLOCK(tovp, LK_SHARED);
5681         if (error != 0)
5682                 goto out;
5683         if (tovp->v_type != VREG)
5684                 nd->nd_repstat = NFSERR_WRONGTYPE;
5685
5686         /* For the output file, we only need the Owner attribute. */
5687         ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5688         if (nd->nd_repstat == 0)
5689                 nd->nd_repstat = ret;
5690         if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5691              NFSVNO_EXSTRICTACCESS(exp)))
5692                 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5693                     curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5694                     NULL);
5695         if (nd->nd_repstat == 0)
5696                 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5697                     clientid, &stateid, toexp, nd, curthread);
5698         NFSVOPUNLOCK(tovp);
5699
5700         /* Range lock the byte ranges for both invp and outvp. */
5701         if (nd->nd_repstat == 0) {
5702                 for (;;) {
5703                         if (len == 0) {
5704                                 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5705                                     OFF_MAX);
5706                                 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5707                                     OFF_MAX);
5708                         } else {
5709                                 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5710                                     outoff + len);
5711                                 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5712                                     inoff + len);
5713                         }
5714                         if (rl_rcookie != NULL)
5715                                 break;
5716                         vn_rangelock_unlock(tovp, rl_wcookie);
5717                         if (len == 0)
5718                                 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5719                                     OFF_MAX);
5720                         else
5721                                 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5722                                     inoff + len);
5723                         vn_rangelock_unlock(vp, rl_rcookie);
5724                 }
5725
5726                 error = NFSVOPLOCK(vp, LK_SHARED);
5727                 if (error == 0) {
5728                         ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5729                         if (ret == 0) {
5730                                 /*
5731                                  * Since invp is range locked, na_size should
5732                                  * not change.
5733                                  */
5734                                 if (len == 0 && at.na_size > inoff) {
5735                                         /*
5736                                          * If len == 0, set it based on invp's 
5737                                          * size. If offset is past EOF, just
5738                                          * leave len == 0.
5739                                          */
5740                                         len = at.na_size - inoff;
5741                                 } else if (nfsrv_linux42server == 0 &&
5742                                     inoff + len > at.na_size) {
5743                                         /*
5744                                          * RFC-7862 says that NFSERR_INVAL must
5745                                          * be returned when inoff + len exceeds
5746                                          * the file size, however the NFSv4.2
5747                                          * Linux client likes to do this, so
5748                                          * only check if nfsrv_linux42server
5749                                          * is not set.
5750                                          */
5751                                         nd->nd_repstat = NFSERR_INVAL;
5752                                 }
5753                         }
5754                         NFSVOPUNLOCK(vp);
5755                         if (ret != 0 && nd->nd_repstat == 0)
5756                                 nd->nd_repstat = ret;
5757                 } else if (nd->nd_repstat == 0)
5758                         nd->nd_repstat = error;
5759         }
5760
5761         xfer = len;
5762         if (nd->nd_repstat == 0) {
5763                 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5764                     &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
5765                     NULL);
5766                 if (nd->nd_repstat == 0)
5767                         len = xfer;
5768         }
5769
5770         /* Unlock the ranges. */
5771         if (rl_rcookie != NULL)
5772                 vn_rangelock_unlock(vp, rl_rcookie);
5773         if (rl_wcookie != NULL)
5774                 vn_rangelock_unlock(tovp, rl_wcookie);
5775
5776         if (nd->nd_repstat == 0) {
5777                 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5778                     NFSX_VERF);
5779                 *tl++ = txdr_unsigned(0);       /* No callback ids. */
5780                 txdr_hyper(len, tl); tl += 2;
5781                 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5782                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5783                 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5784                 *tl++ = newnfs_true;
5785                 *tl = newnfs_true;
5786         }
5787 out:
5788         vrele(vp);
5789         vrele(tovp);
5790         NFSEXITCODE2(error, nd);
5791         return (error);
5792 nfsmout:
5793         vput(vp);
5794         vrele(tovp);
5795         NFSEXITCODE2(error, nd);
5796         return (error);
5797 }
5798
5799 /*
5800  * nfs seek service
5801  */
5802 int
5803 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5804     vnode_t vp, struct nfsexstuff *exp)
5805 {
5806         uint32_t *tl;
5807         struct nfsvattr at;
5808         int content, error = 0;
5809         off_t off;
5810         u_long cmd;
5811         nfsattrbit_t attrbits;
5812         bool eof;
5813
5814         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5815         /* Ignore the stateid for now. */
5816         tl += (NFSX_STATEID / NFSX_UNSIGNED);
5817         off = fxdr_hyper(tl); tl += 2;
5818         content = fxdr_unsigned(int, *tl);
5819         if (content == NFSV4CONTENT_DATA)
5820                 cmd = FIOSEEKDATA;
5821         else if (content == NFSV4CONTENT_HOLE)
5822                 cmd = FIOSEEKHOLE;
5823         else
5824                 nd->nd_repstat = NFSERR_BADXDR;
5825         if (nd->nd_repstat == 0 && vp->v_type == VDIR)
5826                 nd->nd_repstat = NFSERR_ISDIR;
5827         if (nd->nd_repstat == 0 && vp->v_type != VREG)
5828                 nd->nd_repstat = NFSERR_WRONGTYPE;
5829         if (nd->nd_repstat == 0 && off < 0)
5830                 nd->nd_repstat = NFSERR_NXIO;
5831         if (nd->nd_repstat == 0) {
5832                 /* Check permissions for the input file. */
5833                 NFSZERO_ATTRBIT(&attrbits);
5834                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5835                 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5836                     &attrbits);
5837         }
5838         if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5839              NFSVNO_EXSTRICTACCESS(exp)))
5840                 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5841                     curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5842                     NULL);
5843         if (nd->nd_repstat != 0)
5844                 goto nfsmout;
5845
5846         /* nfsvno_seek() unlocks and vrele()s the vp. */
5847         nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5848             nd->nd_cred, curthread);
5849         if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5850             nfsrv_linux42server != 0)
5851                 nd->nd_repstat = NFSERR_NXIO;
5852         if (nd->nd_repstat == 0) {
5853                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5854                 if (eof)
5855                         *tl++ = newnfs_true;
5856                 else
5857                         *tl++ = newnfs_false;
5858                 txdr_hyper(off, tl);
5859         }
5860         NFSEXITCODE2(error, nd);
5861         return (error);
5862 nfsmout:
5863         vput(vp);
5864         NFSEXITCODE2(error, nd);
5865         return (error);
5866 }
5867
5868 /*
5869  * nfs get extended attribute service
5870  */
5871 int
5872 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5873     vnode_t vp, __unused struct nfsexstuff *exp)
5874 {
5875         uint32_t *tl;
5876         struct mbuf *mp = NULL, *mpend = NULL;
5877         int error, len;
5878         char *name;
5879         struct thread *p = curthread;
5880         uint16_t off;
5881
5882         error = 0;
5883         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5884         len = fxdr_unsigned(int, *tl);
5885         if (len <= 0) {
5886                 nd->nd_repstat = NFSERR_BADXDR;
5887                 goto nfsmout;
5888         }
5889         if (len > EXTATTR_MAXNAMELEN) {
5890                 nd->nd_repstat = NFSERR_NOXATTR;
5891                 goto nfsmout;
5892         }
5893         name = malloc(len + 1, M_TEMP, M_WAITOK);
5894         nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5895         if (nd->nd_repstat == 0)
5896                 nd->nd_repstat = nfsvno_getxattr(vp, name,
5897                     nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
5898                     nd->nd_maxextsiz, p, &mp, &mpend, &len);
5899         if (nd->nd_repstat == ENOATTR)
5900                 nd->nd_repstat = NFSERR_NOXATTR;
5901         else if (nd->nd_repstat == EOPNOTSUPP)
5902                 nd->nd_repstat = NFSERR_NOTSUPP;
5903         if (nd->nd_repstat == 0) {
5904                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5905                 *tl = txdr_unsigned(len);
5906                 if (len > 0) {
5907                         nd->nd_mb->m_next = mp;
5908                         nd->nd_mb = mpend;
5909                         if ((mpend->m_flags & M_EXTPG) != 0) {
5910                                 nd->nd_flag |= ND_EXTPG;
5911                                 nd->nd_bextpg = mpend->m_epg_npgs - 1;
5912                                 nd->nd_bpos = (char *)(void *)
5913                                    PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
5914                                 off = (nd->nd_bextpg == 0) ?
5915                                     mpend->m_epg_1st_off : 0;
5916                                 nd->nd_bpos += off + mpend->m_epg_last_len;
5917                                 nd->nd_bextpgsiz = PAGE_SIZE -
5918                                     mpend->m_epg_last_len - off;
5919                         } else
5920                                 nd->nd_bpos = mtod(mpend, char *) +
5921                                     mpend->m_len;
5922                 }
5923         }
5924         free(name, M_TEMP);
5925
5926 nfsmout:
5927         if (nd->nd_repstat == 0)
5928                 nd->nd_repstat = error;
5929         vput(vp);
5930         NFSEXITCODE2(0, nd);
5931         return (0);
5932 }
5933
5934 /*
5935  * nfs set extended attribute service
5936  */
5937 int
5938 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5939     vnode_t vp, __unused struct nfsexstuff *exp)
5940 {
5941         uint32_t *tl;
5942         struct nfsvattr ova, nva;
5943         nfsattrbit_t attrbits;
5944         int error, len, opt;
5945         char *name;
5946         size_t siz;
5947         struct thread *p = curthread;
5948
5949         error = 0;
5950         name = NULL;
5951         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5952         opt = fxdr_unsigned(int, *tl++);
5953         len = fxdr_unsigned(int, *tl);
5954         if (len <= 0) {
5955                 nd->nd_repstat = NFSERR_BADXDR;
5956                 goto nfsmout;
5957         }
5958         if (len > EXTATTR_MAXNAMELEN) {
5959                 nd->nd_repstat = NFSERR_NOXATTR;
5960                 goto nfsmout;
5961         }
5962         name = malloc(len + 1, M_TEMP, M_WAITOK);
5963         error = nfsrv_mtostr(nd, name, len);
5964         if (error != 0)
5965                 goto nfsmout;
5966         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5967         len = fxdr_unsigned(int, *tl);
5968         if (len < 0 || len > IOSIZE_MAX) {
5969                 nd->nd_repstat = NFSERR_XATTR2BIG;
5970                 goto nfsmout;
5971         }
5972         switch (opt) {
5973         case NFSV4SXATTR_CREATE:
5974                 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5975                     &siz, nd->nd_cred, p);
5976                 if (error != ENOATTR)
5977                         nd->nd_repstat = NFSERR_EXIST;
5978                 error = 0;
5979                 break;
5980         case NFSV4SXATTR_REPLACE:
5981                 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5982                     &siz, nd->nd_cred, p);
5983                 if (error != 0)
5984                         nd->nd_repstat = NFSERR_NOXATTR;
5985                 break;
5986         case NFSV4SXATTR_EITHER:
5987                 break;
5988         default:
5989                 nd->nd_repstat = NFSERR_BADXDR;
5990         }
5991         if (nd->nd_repstat != 0)
5992                 goto nfsmout;
5993
5994         /* Now, do the Set Extended attribute, with Change before and after. */
5995         NFSZERO_ATTRBIT(&attrbits);
5996         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
5997         nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
5998         if (nd->nd_repstat == 0) {
5999                 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6000                     nd->nd_dpos, nd->nd_cred, p);
6001                 if (nd->nd_repstat == ENXIO)
6002                         nd->nd_repstat = NFSERR_XATTR2BIG;
6003         }
6004         if (nd->nd_repstat == 0 && len > 0)
6005                 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6006         if (nd->nd_repstat == 0)
6007                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6008         if (nd->nd_repstat == 0) {
6009                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6010                 *tl++ = newnfs_true;
6011                 txdr_hyper(ova.na_filerev, tl); tl += 2;
6012                 txdr_hyper(nva.na_filerev, tl);
6013         }
6014
6015 nfsmout:
6016         free(name, M_TEMP);
6017         if (nd->nd_repstat == 0)
6018                 nd->nd_repstat = error;
6019         vput(vp);
6020         NFSEXITCODE2(0, nd);
6021         return (0);
6022 }
6023
6024 /*
6025  * nfs remove extended attribute service
6026  */
6027 int
6028 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6029     vnode_t vp, __unused struct nfsexstuff *exp)
6030 {
6031         uint32_t *tl;
6032         struct nfsvattr ova, nva;
6033         nfsattrbit_t attrbits;
6034         int error, len;
6035         char *name;
6036         struct thread *p = curthread;
6037
6038         error = 0;
6039         name = NULL;
6040         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6041         len = fxdr_unsigned(int, *tl);
6042         if (len <= 0) {
6043                 nd->nd_repstat = NFSERR_BADXDR;
6044                 goto nfsmout;
6045         }
6046         if (len > EXTATTR_MAXNAMELEN) {
6047                 nd->nd_repstat = NFSERR_NOXATTR;
6048                 goto nfsmout;
6049         }
6050         name = malloc(len + 1, M_TEMP, M_WAITOK);
6051         error = nfsrv_mtostr(nd, name, len);
6052         if (error != 0)
6053                 goto nfsmout;
6054
6055         if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6056                 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6057                 error = NFSERR_NOXATTR;
6058                 goto nfsmout;
6059         }
6060         /*
6061          * Now, do the Remove Extended attribute, with Change before and
6062          * after.
6063         */
6064         NFSZERO_ATTRBIT(&attrbits);
6065         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6066         nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6067         if (nd->nd_repstat == 0) {
6068                 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6069                 if (nd->nd_repstat == ENOATTR)
6070                         nd->nd_repstat = NFSERR_NOXATTR;
6071         }
6072         if (nd->nd_repstat == 0)
6073                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6074         if (nd->nd_repstat == 0) {
6075                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6076                 *tl++ = newnfs_true;
6077                 txdr_hyper(ova.na_filerev, tl); tl += 2;
6078                 txdr_hyper(nva.na_filerev, tl);
6079         }
6080
6081 nfsmout:
6082         free(name, M_TEMP);
6083         if (nd->nd_repstat == 0)
6084                 nd->nd_repstat = error;
6085         vput(vp);
6086         NFSEXITCODE2(0, nd);
6087         return (0);
6088 }
6089
6090 /*
6091  * nfs list extended attribute service
6092  */
6093 int
6094 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6095     vnode_t vp, __unused struct nfsexstuff *exp)
6096 {
6097         uint32_t cnt, *tl, len, len2, i, pos, retlen;
6098         int error;
6099         uint64_t cookie, cookie2;
6100         u_char *buf;
6101         bool eof;
6102         struct thread *p = curthread;
6103
6104         error = 0;
6105         buf = NULL;
6106         NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6107         /*
6108          * The cookie doesn't need to be in net byte order, but FreeBSD
6109          * does so to make it more readable in packet traces.
6110          */
6111         cookie = fxdr_hyper(tl); tl += 2;
6112         len = fxdr_unsigned(uint32_t, *tl);
6113         if (len == 0 || cookie >= IOSIZE_MAX) {
6114                 nd->nd_repstat = NFSERR_BADXDR;
6115                 goto nfsmout;
6116         }
6117         if (len > nd->nd_maxresp - NFS_MAXXDR)
6118                 len = nd->nd_maxresp - NFS_MAXXDR;
6119         len2 = len;
6120         nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6121             &len, &eof);
6122         if (nd->nd_repstat == EOPNOTSUPP)
6123                 nd->nd_repstat = NFSERR_NOTSUPP;
6124         if (nd->nd_repstat == 0) {
6125                 cookie2 = cookie + len;
6126                 if (cookie2 < cookie)
6127                         nd->nd_repstat = NFSERR_BADXDR;
6128         }
6129         retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6130         if (nd->nd_repstat == 0 && len2 < retlen)
6131                 nd->nd_repstat = NFSERR_TOOSMALL;
6132         if (nd->nd_repstat == 0) {
6133                 /* Now copy the entries out. */
6134                 if (len == 0) {
6135                         /* The cookie was at eof. */
6136                         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6137                             NFSX_UNSIGNED);
6138                         txdr_hyper(cookie2, tl); tl += 2;
6139                         *tl++ = txdr_unsigned(0);
6140                         *tl = newnfs_true;
6141                         goto nfsmout;
6142                 }
6143
6144                 /* Sanity check the cookie. */
6145                 for (pos = 0; pos < len; pos += (i + 1)) {
6146                         if (pos == cookie)
6147                                 break;
6148                         i = buf[pos];
6149                 }
6150                 if (pos != cookie) {
6151                         nd->nd_repstat = NFSERR_INVAL;
6152                         goto nfsmout;
6153                 }
6154
6155                 /* Loop around copying the entrie(s) out. */
6156                 cnt = 0;
6157                 len -= cookie;
6158                 i = buf[pos];
6159                 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6160                     NFSX_UNSIGNED) {
6161                         if (cnt == 0) {
6162                                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6163                                     NFSX_UNSIGNED);
6164                                 txdr_hyper(cookie2, tl); tl += 2;
6165                         }
6166                         retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6167                         len -= (i + 1);
6168                         pos += (i + 1);
6169                         i = buf[pos];
6170                         cnt++;
6171                 }
6172                 /*
6173                  * eof is set true/false by nfsvno_listxattr(), but if we
6174                  * can't copy all entries returned by nfsvno_listxattr(),
6175                  * we are not at eof.
6176                  */
6177                 if (len > 0)
6178                         eof = false;
6179                 if (cnt > 0) {
6180                         /* *tl is set above. */
6181                         *tl = txdr_unsigned(cnt);
6182                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6183                         if (eof)
6184                                 *tl = newnfs_true;
6185                         else
6186                                 *tl = newnfs_false;
6187                 } else
6188                         nd->nd_repstat = NFSERR_TOOSMALL;
6189         }
6190
6191 nfsmout:
6192         free(buf, M_TEMP);
6193         if (nd->nd_repstat == 0)
6194                 nd->nd_repstat = error;
6195         vput(vp);
6196         NFSEXITCODE2(0, nd);
6197         return (0);
6198 }
6199
6200 /*
6201  * nfsv4 service not supported
6202  */
6203 int
6204 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6205     __unused vnode_t vp, __unused struct nfsexstuff *exp)
6206 {
6207
6208         nd->nd_repstat = NFSERR_NOTSUPP;
6209         NFSEXITCODE2(0, nd);
6210         return (0);
6211 }