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