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