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