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