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