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