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