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