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