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