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