]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsserver/nfs_nfsdserv.c
Merge ACPICA 20170929.
[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  * 3. 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                         goto nfsmout;
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         u_quad_t tval;
2039
2040         sf = NULL;
2041         if (nd->nd_repstat) {
2042                 nfsrv_postopattr(nd, getret, &at);
2043                 goto out;
2044         }
2045         sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
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         free(sf, M_STATFS);
2082         NFSEXITCODE2(0, nd);
2083         return (0);
2084 }
2085
2086 /*
2087  * nfs fsinfo service
2088  */
2089 APPLESTATIC int
2090 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2091     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2092 {
2093         u_int32_t *tl;
2094         struct nfsfsinfo fs;
2095         int getret = 1;
2096         struct nfsvattr at;
2097
2098         if (nd->nd_repstat) {
2099                 nfsrv_postopattr(nd, getret, &at);
2100                 goto out;
2101         }
2102         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2103         nfsvno_getfs(&fs, isdgram);
2104         vput(vp);
2105         nfsrv_postopattr(nd, getret, &at);
2106         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2107         *tl++ = txdr_unsigned(fs.fs_rtmax);
2108         *tl++ = txdr_unsigned(fs.fs_rtpref);
2109         *tl++ = txdr_unsigned(fs.fs_rtmult);
2110         *tl++ = txdr_unsigned(fs.fs_wtmax);
2111         *tl++ = txdr_unsigned(fs.fs_wtpref);
2112         *tl++ = txdr_unsigned(fs.fs_wtmult);
2113         *tl++ = txdr_unsigned(fs.fs_dtpref);
2114         txdr_hyper(fs.fs_maxfilesize, tl);
2115         tl += 2;
2116         txdr_nfsv3time(&fs.fs_timedelta, tl);
2117         tl += 2;
2118         *tl = txdr_unsigned(fs.fs_properties);
2119
2120 out:
2121         NFSEXITCODE2(0, nd);
2122         return (0);
2123 }
2124
2125 /*
2126  * nfs pathconf service
2127  */
2128 APPLESTATIC int
2129 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2130     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2131 {
2132         struct nfsv3_pathconf *pc;
2133         int getret = 1;
2134         register_t linkmax, namemax, chownres, notrunc;
2135         struct nfsvattr at;
2136
2137         if (nd->nd_repstat) {
2138                 nfsrv_postopattr(nd, getret, &at);
2139                 goto out;
2140         }
2141         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2142             nd->nd_cred, p);
2143         if (!nd->nd_repstat)
2144                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2145                     nd->nd_cred, p);
2146         if (!nd->nd_repstat)
2147                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2148                     &chownres, nd->nd_cred, p);
2149         if (!nd->nd_repstat)
2150                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2151                     nd->nd_cred, p);
2152         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2153         vput(vp);
2154         nfsrv_postopattr(nd, getret, &at);
2155         if (!nd->nd_repstat) {
2156                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2157                 pc->pc_linkmax = txdr_unsigned(linkmax);
2158                 pc->pc_namemax = txdr_unsigned(namemax);
2159                 pc->pc_notrunc = txdr_unsigned(notrunc);
2160                 pc->pc_chownrestricted = txdr_unsigned(chownres);
2161
2162                 /*
2163                  * These should probably be supported by VOP_PATHCONF(), but
2164                  * until msdosfs is exportable (why would you want to?), the
2165                  * Unix defaults should be ok.
2166                  */
2167                 pc->pc_caseinsensitive = newnfs_false;
2168                 pc->pc_casepreserving = newnfs_true;
2169         }
2170
2171 out:
2172         NFSEXITCODE2(0, nd);
2173         return (0);
2174 }
2175
2176 /*
2177  * nfsv4 lock service
2178  */
2179 APPLESTATIC int
2180 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2181     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2182 {
2183         u_int32_t *tl;
2184         int i;
2185         struct nfsstate *stp = NULL;
2186         struct nfslock *lop;
2187         struct nfslockconflict cf;
2188         int error = 0;
2189         u_short flags = NFSLCK_LOCK, lflags;
2190         u_int64_t offset, len;
2191         nfsv4stateid_t stateid;
2192         nfsquad_t clientid;
2193
2194         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2195         i = fxdr_unsigned(int, *tl++);
2196         switch (i) {
2197         case NFSV4LOCKT_READW:
2198                 flags |= NFSLCK_BLOCKING;
2199         case NFSV4LOCKT_READ:
2200                 lflags = NFSLCK_READ;
2201                 break;
2202         case NFSV4LOCKT_WRITEW:
2203                 flags |= NFSLCK_BLOCKING;
2204         case NFSV4LOCKT_WRITE:
2205                 lflags = NFSLCK_WRITE;
2206                 break;
2207         default:
2208                 nd->nd_repstat = NFSERR_BADXDR;
2209                 goto nfsmout;
2210         }
2211         if (*tl++ == newnfs_true)
2212                 flags |= NFSLCK_RECLAIM;
2213         offset = fxdr_hyper(tl);
2214         tl += 2;
2215         len = fxdr_hyper(tl);
2216         tl += 2;
2217         if (*tl == newnfs_true)
2218                 flags |= NFSLCK_OPENTOLOCK;
2219         if (flags & NFSLCK_OPENTOLOCK) {
2220                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2221                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2222                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2223                         nd->nd_repstat = NFSERR_BADXDR;
2224                         goto nfsmout;
2225                 }
2226                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2227                         M_NFSDSTATE, M_WAITOK);
2228                 stp->ls_ownerlen = i;
2229                 stp->ls_op = nd->nd_rp;
2230                 stp->ls_seq = fxdr_unsigned(int, *tl++);
2231                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2232                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2233                         NFSX_STATEIDOTHER);
2234                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2235                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2236                 clientid.lval[0] = *tl++;
2237                 clientid.lval[1] = *tl++;
2238                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2239                         if ((nd->nd_flag & ND_NFSV41) != 0)
2240                                 clientid.qval = nd->nd_clientid.qval;
2241                         else if (nd->nd_clientid.qval != clientid.qval)
2242                                 printf("EEK3 multiple clids\n");
2243                 } else {
2244                         if ((nd->nd_flag & ND_NFSV41) != 0)
2245                                 printf("EEK! no clientid from session\n");
2246                         nd->nd_flag |= ND_IMPLIEDCLID;
2247                         nd->nd_clientid.qval = clientid.qval;
2248                 }
2249                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2250                 if (error)
2251                         goto nfsmout;
2252         } else {
2253                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2254                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2255                         M_NFSDSTATE, M_WAITOK);
2256                 stp->ls_ownerlen = 0;
2257                 stp->ls_op = nd->nd_rp;
2258                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2259                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2260                         NFSX_STATEIDOTHER);
2261                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2262                 stp->ls_seq = fxdr_unsigned(int, *tl);
2263                 clientid.lval[0] = stp->ls_stateid.other[0];
2264                 clientid.lval[1] = stp->ls_stateid.other[1];
2265                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2266                         if ((nd->nd_flag & ND_NFSV41) != 0)
2267                                 clientid.qval = nd->nd_clientid.qval;
2268                         else if (nd->nd_clientid.qval != clientid.qval)
2269                                 printf("EEK4 multiple clids\n");
2270                 } else {
2271                         if ((nd->nd_flag & ND_NFSV41) != 0)
2272                                 printf("EEK! no clientid from session\n");
2273                         nd->nd_flag |= ND_IMPLIEDCLID;
2274                         nd->nd_clientid.qval = clientid.qval;
2275                 }
2276         }
2277         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2278                 M_NFSDLOCK, M_WAITOK);
2279         lop->lo_first = offset;
2280         if (len == NFS64BITSSET) {
2281                 lop->lo_end = NFS64BITSSET;
2282         } else {
2283                 lop->lo_end = offset + len;
2284                 if (lop->lo_end <= lop->lo_first)
2285                         nd->nd_repstat = NFSERR_INVAL;
2286         }
2287         lop->lo_flags = lflags;
2288         stp->ls_flags = flags;
2289         stp->ls_uid = nd->nd_cred->cr_uid;
2290
2291         /*
2292          * Do basic access checking.
2293          */
2294         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2295             if (vnode_vtype(vp) == VDIR)
2296                 nd->nd_repstat = NFSERR_ISDIR;
2297             else
2298                 nd->nd_repstat = NFSERR_INVAL;
2299         }
2300         if (!nd->nd_repstat) {
2301             if (lflags & NFSLCK_WRITE) {
2302                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2303                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2304                     NFSACCCHK_VPISLOCKED, NULL);
2305             } else {
2306                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2307                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2308                     NFSACCCHK_VPISLOCKED, NULL);
2309                 if (nd->nd_repstat)
2310                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2311                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2312                         NFSACCCHK_VPISLOCKED, NULL);
2313             }
2314         }
2315
2316         /*
2317          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2318          * seqid# gets updated. nfsrv_lockctrl() will return the value
2319          * of nd_repstat, if it gets that far.
2320          */
2321         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
2322                 &stateid, exp, nd, p);
2323         if (lop)
2324                 FREE((caddr_t)lop, M_NFSDLOCK);
2325         if (stp)
2326                 FREE((caddr_t)stp, M_NFSDSTATE);
2327         if (!nd->nd_repstat) {
2328                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2329                 *tl++ = txdr_unsigned(stateid.seqid);
2330                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2331         } else if (nd->nd_repstat == NFSERR_DENIED) {
2332                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2333                 txdr_hyper(cf.cl_first, tl);
2334                 tl += 2;
2335                 if (cf.cl_end == NFS64BITSSET)
2336                         len = NFS64BITSSET;
2337                 else
2338                         len = cf.cl_end - cf.cl_first;
2339                 txdr_hyper(len, tl);
2340                 tl += 2;
2341                 if (cf.cl_flags == NFSLCK_WRITE)
2342                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2343                 else
2344                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2345                 *tl++ = stateid.other[0];
2346                 *tl = stateid.other[1];
2347                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2348         }
2349         vput(vp);
2350         NFSEXITCODE2(0, nd);
2351         return (0);
2352 nfsmout:
2353         vput(vp);
2354         if (stp)
2355                 free((caddr_t)stp, M_NFSDSTATE);
2356         NFSEXITCODE2(error, nd);
2357         return (error);
2358 }
2359
2360 /*
2361  * nfsv4 lock test service
2362  */
2363 APPLESTATIC int
2364 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2365     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2366 {
2367         u_int32_t *tl;
2368         int i;
2369         struct nfsstate *stp = NULL;
2370         struct nfslock lo, *lop = &lo;
2371         struct nfslockconflict cf;
2372         int error = 0;
2373         nfsv4stateid_t stateid;
2374         nfsquad_t clientid;
2375         u_int64_t len;
2376
2377         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2378         i = fxdr_unsigned(int, *(tl + 7));
2379         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2380                 nd->nd_repstat = NFSERR_BADXDR;
2381                 goto nfsmout;
2382         }
2383         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2384             M_NFSDSTATE, M_WAITOK);
2385         stp->ls_ownerlen = i;
2386         stp->ls_op = NULL;
2387         stp->ls_flags = NFSLCK_TEST;
2388         stp->ls_uid = nd->nd_cred->cr_uid;
2389         i = fxdr_unsigned(int, *tl++);
2390         switch (i) {
2391         case NFSV4LOCKT_READW:
2392                 stp->ls_flags |= NFSLCK_BLOCKING;
2393         case NFSV4LOCKT_READ:
2394                 lo.lo_flags = NFSLCK_READ;
2395                 break;
2396         case NFSV4LOCKT_WRITEW:
2397                 stp->ls_flags |= NFSLCK_BLOCKING;
2398         case NFSV4LOCKT_WRITE:
2399                 lo.lo_flags = NFSLCK_WRITE;
2400                 break;
2401         default:
2402                 nd->nd_repstat = NFSERR_BADXDR;
2403                 goto nfsmout;
2404         }
2405         lo.lo_first = fxdr_hyper(tl);
2406         tl += 2;
2407         len = fxdr_hyper(tl);
2408         if (len == NFS64BITSSET) {
2409                 lo.lo_end = NFS64BITSSET;
2410         } else {
2411                 lo.lo_end = lo.lo_first + len;
2412                 if (lo.lo_end <= lo.lo_first)
2413                         nd->nd_repstat = NFSERR_INVAL;
2414         }
2415         tl += 2;
2416         clientid.lval[0] = *tl++;
2417         clientid.lval[1] = *tl;
2418         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2419                 if ((nd->nd_flag & ND_NFSV41) != 0)
2420                         clientid.qval = nd->nd_clientid.qval;
2421                 else if (nd->nd_clientid.qval != clientid.qval)
2422                         printf("EEK5 multiple clids\n");
2423         } else {
2424                 if ((nd->nd_flag & ND_NFSV41) != 0)
2425                         printf("EEK! no clientid from session\n");
2426                 nd->nd_flag |= ND_IMPLIEDCLID;
2427                 nd->nd_clientid.qval = clientid.qval;
2428         }
2429         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2430         if (error)
2431                 goto nfsmout;
2432         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2433             if (vnode_vtype(vp) == VDIR)
2434                 nd->nd_repstat = NFSERR_ISDIR;
2435             else
2436                 nd->nd_repstat = NFSERR_INVAL;
2437         }
2438         if (!nd->nd_repstat)
2439           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2440             &stateid, exp, nd, p);
2441         if (nd->nd_repstat) {
2442             if (nd->nd_repstat == NFSERR_DENIED) {
2443                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2444                 txdr_hyper(cf.cl_first, tl);
2445                 tl += 2;
2446                 if (cf.cl_end == NFS64BITSSET)
2447                         len = NFS64BITSSET;
2448                 else
2449                         len = cf.cl_end - cf.cl_first;
2450                 txdr_hyper(len, tl);
2451                 tl += 2;
2452                 if (cf.cl_flags == NFSLCK_WRITE)
2453                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2454                 else
2455                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2456                 *tl++ = stp->ls_stateid.other[0];
2457                 *tl = stp->ls_stateid.other[1];
2458                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2459             }
2460         }
2461         vput(vp);
2462         if (stp)
2463                 FREE((caddr_t)stp, M_NFSDSTATE);
2464         NFSEXITCODE2(0, nd);
2465         return (0);
2466 nfsmout:
2467         vput(vp);
2468         if (stp)
2469                 free((caddr_t)stp, M_NFSDSTATE);
2470         NFSEXITCODE2(error, nd);
2471         return (error);
2472 }
2473
2474 /*
2475  * nfsv4 unlock service
2476  */
2477 APPLESTATIC int
2478 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2479     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2480 {
2481         u_int32_t *tl;
2482         int i;
2483         struct nfsstate *stp;
2484         struct nfslock *lop;
2485         int error = 0;
2486         nfsv4stateid_t stateid;
2487         nfsquad_t clientid;
2488         u_int64_t len;
2489
2490         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2491         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2492             M_NFSDSTATE, M_WAITOK);
2493         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2494             M_NFSDLOCK, M_WAITOK);
2495         stp->ls_flags = NFSLCK_UNLOCK;
2496         lop->lo_flags = NFSLCK_UNLOCK;
2497         stp->ls_op = nd->nd_rp;
2498         i = fxdr_unsigned(int, *tl++);
2499         switch (i) {
2500         case NFSV4LOCKT_READW:
2501                 stp->ls_flags |= NFSLCK_BLOCKING;
2502         case NFSV4LOCKT_READ:
2503                 break;
2504         case NFSV4LOCKT_WRITEW:
2505                 stp->ls_flags |= NFSLCK_BLOCKING;
2506         case NFSV4LOCKT_WRITE:
2507                 break;
2508         default:
2509                 nd->nd_repstat = NFSERR_BADXDR;
2510                 free(stp, M_NFSDSTATE);
2511                 free(lop, M_NFSDLOCK);
2512                 goto nfsmout;
2513         }
2514         stp->ls_ownerlen = 0;
2515         stp->ls_uid = nd->nd_cred->cr_uid;
2516         stp->ls_seq = fxdr_unsigned(int, *tl++);
2517         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2518         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2519             NFSX_STATEIDOTHER);
2520         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2521         lop->lo_first = fxdr_hyper(tl);
2522         tl += 2;
2523         len = fxdr_hyper(tl);
2524         if (len == NFS64BITSSET) {
2525                 lop->lo_end = NFS64BITSSET;
2526         } else {
2527                 lop->lo_end = lop->lo_first + len;
2528                 if (lop->lo_end <= lop->lo_first)
2529                         nd->nd_repstat = NFSERR_INVAL;
2530         }
2531         clientid.lval[0] = stp->ls_stateid.other[0];
2532         clientid.lval[1] = stp->ls_stateid.other[1];
2533         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2534                 if ((nd->nd_flag & ND_NFSV41) != 0)
2535                         clientid.qval = nd->nd_clientid.qval;
2536                 else if (nd->nd_clientid.qval != clientid.qval)
2537                         printf("EEK6 multiple clids\n");
2538         } else {
2539                 if ((nd->nd_flag & ND_NFSV41) != 0)
2540                         printf("EEK! no clientid from session\n");
2541                 nd->nd_flag |= ND_IMPLIEDCLID;
2542                 nd->nd_clientid.qval = clientid.qval;
2543         }
2544         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2545             if (vnode_vtype(vp) == VDIR)
2546                 nd->nd_repstat = NFSERR_ISDIR;
2547             else
2548                 nd->nd_repstat = NFSERR_INVAL;
2549         }
2550         /*
2551          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2552          * seqid# gets incremented. nfsrv_lockctrl() will return the
2553          * value of nd_repstat, if it gets that far.
2554          */
2555         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2556             &stateid, exp, nd, p);
2557         if (stp)
2558                 FREE((caddr_t)stp, M_NFSDSTATE);
2559         if (lop)
2560                 free((caddr_t)lop, M_NFSDLOCK);
2561         if (!nd->nd_repstat) {
2562                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2563                 *tl++ = txdr_unsigned(stateid.seqid);
2564                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2565         }
2566 nfsmout:
2567         vput(vp);
2568         NFSEXITCODE2(error, nd);
2569         return (error);
2570 }
2571
2572 /*
2573  * nfsv4 open service
2574  */
2575 APPLESTATIC int
2576 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2577     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2578     struct nfsexstuff *exp)
2579 {
2580         u_int32_t *tl;
2581         int i, retext;
2582         struct nfsstate *stp = NULL;
2583         int error = 0, create, claim, exclusive_flag = 0;
2584         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2585         int how = NFSCREATE_UNCHECKED;
2586         int32_t cverf[2], tverf[2] = { 0, 0 };
2587         vnode_t vp = NULL, dirp = NULL;
2588         struct nfsvattr nva, dirfor, diraft;
2589         struct nameidata named;
2590         nfsv4stateid_t stateid, delegstateid;
2591         nfsattrbit_t attrbits;
2592         nfsquad_t clientid;
2593         char *bufp = NULL;
2594         u_long *hashp;
2595         NFSACL_T *aclp = NULL;
2596
2597 #ifdef NFS4_ACL_EXTATTR_NAME
2598         aclp = acl_alloc(M_WAITOK);
2599         aclp->acl_cnt = 0;
2600 #endif
2601         NFSZERO_ATTRBIT(&attrbits);
2602         named.ni_startdir = NULL;
2603         named.ni_cnd.cn_nameiop = 0;
2604         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2605         i = fxdr_unsigned(int, *(tl + 5));
2606         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2607                 nd->nd_repstat = NFSERR_BADXDR;
2608                 goto nfsmout;
2609         }
2610         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2611             M_NFSDSTATE, M_WAITOK);
2612         stp->ls_ownerlen = i;
2613         stp->ls_op = nd->nd_rp;
2614         stp->ls_flags = NFSLCK_OPEN;
2615         stp->ls_uid = nd->nd_cred->cr_uid;
2616         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2617         i = fxdr_unsigned(int, *tl++);
2618         retext = 0;
2619         if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2620             NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2621                 retext = 1;
2622                 /* For now, ignore these. */
2623                 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2624                 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2625                 case NFSV4OPEN_WANTANYDELEG:
2626                         stp->ls_flags |= (NFSLCK_WANTRDELEG |
2627                             NFSLCK_WANTWDELEG);
2628                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2629                         break;
2630                 case NFSV4OPEN_WANTREADDELEG:
2631                         stp->ls_flags |= NFSLCK_WANTRDELEG;
2632                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2633                         break;
2634                 case NFSV4OPEN_WANTWRITEDELEG:
2635                         stp->ls_flags |= NFSLCK_WANTWDELEG;
2636                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2637                         break;
2638                 case NFSV4OPEN_WANTNODELEG:
2639                         stp->ls_flags |= NFSLCK_WANTNODELEG;
2640                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2641                         break;
2642                 case NFSV4OPEN_WANTCANCEL:
2643                         printf("NFSv4: ignore Open WantCancel\n");
2644                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2645                         break;
2646                 default:
2647                         /* nd_repstat will be set to NFSERR_INVAL below. */
2648                         break;
2649                 }
2650         }
2651         switch (i) {
2652         case NFSV4OPEN_ACCESSREAD:
2653                 stp->ls_flags |= NFSLCK_READACCESS;
2654                 break;
2655         case NFSV4OPEN_ACCESSWRITE:
2656                 stp->ls_flags |= NFSLCK_WRITEACCESS;
2657                 break;
2658         case NFSV4OPEN_ACCESSBOTH:
2659                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2660                 break;
2661         default:
2662                 nd->nd_repstat = NFSERR_INVAL;
2663         }
2664         i = fxdr_unsigned(int, *tl++);
2665         switch (i) {
2666         case NFSV4OPEN_DENYNONE:
2667                 break;
2668         case NFSV4OPEN_DENYREAD:
2669                 stp->ls_flags |= NFSLCK_READDENY;
2670                 break;
2671         case NFSV4OPEN_DENYWRITE:
2672                 stp->ls_flags |= NFSLCK_WRITEDENY;
2673                 break;
2674         case NFSV4OPEN_DENYBOTH:
2675                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2676                 break;
2677         default:
2678                 nd->nd_repstat = NFSERR_INVAL;
2679         }
2680         clientid.lval[0] = *tl++;
2681         clientid.lval[1] = *tl;
2682         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2683                 if ((nd->nd_flag & ND_NFSV41) != 0)
2684                         clientid.qval = nd->nd_clientid.qval;
2685                 else if (nd->nd_clientid.qval != clientid.qval)
2686                         printf("EEK7 multiple clids\n");
2687         } else {
2688                 if ((nd->nd_flag & ND_NFSV41) != 0)
2689                         printf("EEK! no clientid from session\n");
2690                 nd->nd_flag |= ND_IMPLIEDCLID;
2691                 nd->nd_clientid.qval = clientid.qval;
2692         }
2693         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2694         if (error)
2695                 goto nfsmout;
2696         NFSVNO_ATTRINIT(&nva);
2697         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2698         create = fxdr_unsigned(int, *tl);
2699         if (!nd->nd_repstat)
2700                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2701         if (create == NFSV4OPEN_CREATE) {
2702                 nva.na_type = VREG;
2703                 nva.na_mode = 0;
2704                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2705                 how = fxdr_unsigned(int, *tl);
2706                 switch (how) {
2707                 case NFSCREATE_UNCHECKED:
2708                 case NFSCREATE_GUARDED:
2709                         error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2710                         if (error)
2711                                 goto nfsmout;
2712                         /*
2713                          * If the na_gid being set is the same as that of
2714                          * the directory it is going in, clear it, since
2715                          * that is what will be set by default. This allows
2716                          * a user that isn't in that group to do the create.
2717                          */
2718                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2719                             nva.na_gid == dirfor.na_gid)
2720                                 NFSVNO_UNSET(&nva, gid);
2721                         if (!nd->nd_repstat)
2722                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2723                         break;
2724                 case NFSCREATE_EXCLUSIVE:
2725                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2726                         cverf[0] = *tl++;
2727                         cverf[1] = *tl;
2728                         break;
2729                 case NFSCREATE_EXCLUSIVE41:
2730                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2731                         cverf[0] = *tl++;
2732                         cverf[1] = *tl;
2733                         error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
2734                         if (error != 0)
2735                                 goto nfsmout;
2736                         if (NFSISSET_ATTRBIT(&attrbits,
2737                             NFSATTRBIT_TIMEACCESSSET))
2738                                 nd->nd_repstat = NFSERR_INVAL;
2739                         /*
2740                          * If the na_gid being set is the same as that of
2741                          * the directory it is going in, clear it, since
2742                          * that is what will be set by default. This allows
2743                          * a user that isn't in that group to do the create.
2744                          */
2745                         if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2746                             nva.na_gid == dirfor.na_gid)
2747                                 NFSVNO_UNSET(&nva, gid);
2748                         if (nd->nd_repstat == 0)
2749                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2750                         break;
2751                 default:
2752                         nd->nd_repstat = NFSERR_BADXDR;
2753                         goto nfsmout;
2754                 }
2755         } else if (create != NFSV4OPEN_NOCREATE) {
2756                 nd->nd_repstat = NFSERR_BADXDR;
2757                 goto nfsmout;
2758         }
2759
2760         /*
2761          * Now, handle the claim, which usually includes looking up a
2762          * name in the directory referenced by dp. The exception is
2763          * NFSV4OPEN_CLAIMPREVIOUS.
2764          */
2765         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2766         claim = fxdr_unsigned(int, *tl);
2767         if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2768                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2769                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2770                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2771                 stp->ls_flags |= NFSLCK_DELEGCUR;
2772         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2773                 stp->ls_flags |= NFSLCK_DELEGPREV;
2774         }
2775         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2776             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2777                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2778                     claim != NFSV4OPEN_CLAIMNULL)
2779                         nd->nd_repstat = NFSERR_INVAL;
2780                 if (nd->nd_repstat) {
2781                         nd->nd_repstat = nfsrv_opencheck(clientid,
2782                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
2783                         goto nfsmout;
2784                 }
2785                 if (create == NFSV4OPEN_CREATE)
2786                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2787                         LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2788                 else
2789                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2790                         LOCKLEAF | SAVESTART);
2791                 nfsvno_setpathbuf(&named, &bufp, &hashp);
2792                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2793                 if (error) {
2794                         vrele(dp);
2795 #ifdef NFS4_ACL_EXTATTR_NAME
2796                         acl_free(aclp);
2797 #endif
2798                         FREE((caddr_t)stp, M_NFSDSTATE);
2799                         nfsvno_relpathbuf(&named);
2800                         NFSEXITCODE2(error, nd);
2801                         return (error);
2802                 }
2803                 if (!nd->nd_repstat) {
2804                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2805                             p, &dirp);
2806                 } else {
2807                         vrele(dp);
2808                         nfsvno_relpathbuf(&named);
2809                 }
2810                 if (create == NFSV4OPEN_CREATE) {
2811                     switch (how) {
2812                     case NFSCREATE_UNCHECKED:
2813                         if (named.ni_vp) {
2814                                 /*
2815                                  * Clear the setable attribute bits, except
2816                                  * for Size, if it is being truncated.
2817                                  */
2818                                 NFSZERO_ATTRBIT(&attrbits);
2819                                 if (NFSVNO_ISSETSIZE(&nva))
2820                                         NFSSETBIT_ATTRBIT(&attrbits,
2821                                             NFSATTRBIT_SIZE);
2822                         }
2823                         break;
2824                     case NFSCREATE_GUARDED:
2825                         if (named.ni_vp && !nd->nd_repstat)
2826                                 nd->nd_repstat = EEXIST;
2827                         break;
2828                     case NFSCREATE_EXCLUSIVE:
2829                         exclusive_flag = 1;
2830                         if (!named.ni_vp)
2831                                 nva.na_mode = 0;
2832                         break;
2833                     case NFSCREATE_EXCLUSIVE41:
2834                         exclusive_flag = 1;
2835                         break;
2836                     }
2837                 }
2838                 nfsvno_open(nd, &named, clientid, &stateid, stp,
2839                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2840                     nd->nd_cred, p, exp, &vp);
2841         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2842             NFSV4OPEN_CLAIMFH) {
2843                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2844                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2845                         i = fxdr_unsigned(int, *tl);
2846                         switch (i) {
2847                         case NFSV4OPEN_DELEGATEREAD:
2848                                 stp->ls_flags |= NFSLCK_DELEGREAD;
2849                                 break;
2850                         case NFSV4OPEN_DELEGATEWRITE:
2851                                 stp->ls_flags |= NFSLCK_DELEGWRITE;
2852                         case NFSV4OPEN_DELEGATENONE:
2853                                 break;
2854                         default:
2855                                 nd->nd_repstat = NFSERR_BADXDR;
2856                                 goto nfsmout;
2857                         }
2858                         stp->ls_flags |= NFSLCK_RECLAIM;
2859                 } else {
2860                         /* CLAIM_NULL_FH */
2861                         if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
2862                                 nd->nd_repstat = NFSERR_INVAL;
2863                 }
2864                 vp = dp;
2865                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2866                 if ((vp->v_iflag & VI_DOOMED) == 0)
2867                         nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2868                             stp, vp, nd, p, nd->nd_repstat);
2869                 else
2870                         nd->nd_repstat = NFSERR_PERM;
2871         } else {
2872                 nd->nd_repstat = NFSERR_BADXDR;
2873                 goto nfsmout;
2874         }
2875
2876         /*
2877          * Do basic access checking.
2878          */
2879         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2880                 /*
2881                  * The IETF working group decided that this is the correct
2882                  * error return for all non-regular files.
2883                  */
2884                 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
2885         }
2886         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2887             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2888                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2889         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2890             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2891                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2892             if (nd->nd_repstat)
2893                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2894                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2895                     NFSACCCHK_VPISLOCKED, NULL);
2896         }
2897
2898         if (!nd->nd_repstat) {
2899                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2900                 if (!nd->nd_repstat) {
2901                         tverf[0] = nva.na_atime.tv_sec;
2902                         tverf[1] = nva.na_atime.tv_nsec;
2903                 }
2904         }
2905         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2906             cverf[1] != tverf[1]))
2907                 nd->nd_repstat = EEXIST;
2908         /*
2909          * Do the open locking/delegation stuff.
2910          */
2911         if (!nd->nd_repstat)
2912             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2913                 &delegstateid, &rflags, exp, p, nva.na_filerev);
2914
2915         /*
2916          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2917          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2918          * (ie: Leave the NFSVOPUNLOCK() about here.)
2919          */
2920         if (vp)
2921                 NFSVOPUNLOCK(vp, 0);
2922         if (stp)
2923                 FREE((caddr_t)stp, M_NFSDSTATE);
2924         if (!nd->nd_repstat && dirp)
2925                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2926                     0);
2927         if (!nd->nd_repstat) {
2928                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2929                 *tl++ = txdr_unsigned(stateid.seqid);
2930                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2931                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2932                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2933                         *tl++ = newnfs_true;
2934                         *tl++ = 0;
2935                         *tl++ = 0;
2936                         *tl++ = 0;
2937                         *tl++ = 0;
2938                 } else {
2939                         *tl++ = newnfs_false;   /* Since dirp is not locked */
2940                         txdr_hyper(dirfor.na_filerev, tl);
2941                         tl += 2;
2942                         txdr_hyper(diraft.na_filerev, tl);
2943                         tl += 2;
2944                 }
2945                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2946                 (void) nfsrv_putattrbit(nd, &attrbits);
2947                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2948                 if (rflags & NFSV4OPEN_READDELEGATE)
2949                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2950                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2951                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2952                 else if (retext != 0) {
2953                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
2954                         if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
2955                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2956                                 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
2957                                 *tl = newnfs_false;
2958                         } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
2959                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2960                                 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
2961                                 *tl = newnfs_false;
2962                         } else {
2963                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2964                                 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
2965                         }
2966                 } else
2967                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2968                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2969                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2970                         *tl++ = txdr_unsigned(delegstateid.seqid);
2971                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2972                             NFSX_STATEIDOTHER);
2973                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2974                         if (rflags & NFSV4OPEN_RECALL)
2975                                 *tl = newnfs_true;
2976                         else
2977                                 *tl = newnfs_false;
2978                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2979                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2980                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2981                                 txdr_hyper(nva.na_size, tl);
2982                         }
2983                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2984                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2985                         *tl++ = txdr_unsigned(0x0);
2986                         acemask = NFSV4ACE_ALLFILESMASK;
2987                         if (nva.na_mode & S_IRUSR)
2988                             acemask |= NFSV4ACE_READMASK;
2989                         if (nva.na_mode & S_IWUSR)
2990                             acemask |= NFSV4ACE_WRITEMASK;
2991                         if (nva.na_mode & S_IXUSR)
2992                             acemask |= NFSV4ACE_EXECUTEMASK;
2993                         *tl = txdr_unsigned(acemask);
2994                         (void) nfsm_strtom(nd, "OWNER@", 6);
2995                 }
2996                 *vpp = vp;
2997         } else if (vp) {
2998                 vrele(vp);
2999         }
3000         if (dirp)
3001                 vrele(dirp);
3002 #ifdef NFS4_ACL_EXTATTR_NAME
3003         acl_free(aclp);
3004 #endif
3005         NFSEXITCODE2(0, nd);
3006         return (0);
3007 nfsmout:
3008         vrele(dp);
3009 #ifdef NFS4_ACL_EXTATTR_NAME
3010         acl_free(aclp);
3011 #endif
3012         if (stp)
3013                 FREE((caddr_t)stp, M_NFSDSTATE);
3014         NFSEXITCODE2(error, nd);
3015         return (error);
3016 }
3017
3018 /*
3019  * nfsv4 close service
3020  */
3021 APPLESTATIC int
3022 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3023     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3024 {
3025         u_int32_t *tl;
3026         struct nfsstate st, *stp = &st;
3027         int error = 0;
3028         nfsv4stateid_t stateid;
3029         nfsquad_t clientid;
3030
3031         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3032         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3033         stp->ls_ownerlen = 0;
3034         stp->ls_op = nd->nd_rp;
3035         stp->ls_uid = nd->nd_cred->cr_uid;
3036         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3037         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3038             NFSX_STATEIDOTHER);
3039         stp->ls_flags = NFSLCK_CLOSE;
3040         clientid.lval[0] = stp->ls_stateid.other[0];
3041         clientid.lval[1] = stp->ls_stateid.other[1];
3042         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3043                 if ((nd->nd_flag & ND_NFSV41) != 0)
3044                         clientid.qval = nd->nd_clientid.qval;
3045                 else if (nd->nd_clientid.qval != clientid.qval)
3046                         printf("EEK8 multiple clids\n");
3047         } else {
3048                 if ((nd->nd_flag & ND_NFSV41) != 0)
3049                         printf("EEK! no clientid from session\n");
3050                 nd->nd_flag |= ND_IMPLIEDCLID;
3051                 nd->nd_clientid.qval = clientid.qval;
3052         }
3053         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3054         vput(vp);
3055         if (!nd->nd_repstat) {
3056                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3057                 *tl++ = txdr_unsigned(stateid.seqid);
3058                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3059         }
3060         NFSEXITCODE2(0, nd);
3061         return (0);
3062 nfsmout:
3063         vput(vp);
3064         NFSEXITCODE2(error, nd);
3065         return (error);
3066 }
3067
3068 /*
3069  * nfsv4 delegpurge service
3070  */
3071 APPLESTATIC int
3072 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3073     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3074 {
3075         u_int32_t *tl;
3076         int error = 0;
3077         nfsquad_t clientid;
3078
3079         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3080                 nd->nd_repstat = NFSERR_WRONGSEC;
3081                 goto nfsmout;
3082         }
3083         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3084         clientid.lval[0] = *tl++;
3085         clientid.lval[1] = *tl;
3086         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3087                 if ((nd->nd_flag & ND_NFSV41) != 0)
3088                         clientid.qval = nd->nd_clientid.qval;
3089                 else if (nd->nd_clientid.qval != clientid.qval)
3090                         printf("EEK9 multiple clids\n");
3091         } else {
3092                 if ((nd->nd_flag & ND_NFSV41) != 0)
3093                         printf("EEK! no clientid from session\n");
3094                 nd->nd_flag |= ND_IMPLIEDCLID;
3095                 nd->nd_clientid.qval = clientid.qval;
3096         }
3097         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3098             NFSV4OP_DELEGPURGE, nd->nd_cred, p);
3099 nfsmout:
3100         NFSEXITCODE2(error, nd);
3101         return (error);
3102 }
3103
3104 /*
3105  * nfsv4 delegreturn service
3106  */
3107 APPLESTATIC int
3108 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3109     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3110 {
3111         u_int32_t *tl;
3112         int error = 0;
3113         nfsv4stateid_t stateid;
3114         nfsquad_t clientid;
3115
3116         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3117         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3118         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3119         clientid.lval[0] = stateid.other[0];
3120         clientid.lval[1] = stateid.other[1];
3121         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3122                 if ((nd->nd_flag & ND_NFSV41) != 0)
3123                         clientid.qval = nd->nd_clientid.qval;
3124                 else if (nd->nd_clientid.qval != clientid.qval)
3125                         printf("EEK10 multiple clids\n");
3126         } else {
3127                 if ((nd->nd_flag & ND_NFSV41) != 0)
3128                         printf("EEK! no clientid from session\n");
3129                 nd->nd_flag |= ND_IMPLIEDCLID;
3130                 nd->nd_clientid.qval = clientid.qval;
3131         }
3132         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3133             NFSV4OP_DELEGRETURN, nd->nd_cred, p);
3134 nfsmout:
3135         vput(vp);
3136         NFSEXITCODE2(error, nd);
3137         return (error);
3138 }
3139
3140 /*
3141  * nfsv4 get file handle service
3142  */
3143 APPLESTATIC int
3144 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3145     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3146 {
3147         fhandle_t fh;
3148
3149         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3150         vput(vp);
3151         if (!nd->nd_repstat)
3152                 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3153         NFSEXITCODE2(0, nd);
3154         return (0);
3155 }
3156
3157 /*
3158  * nfsv4 open confirm service
3159  */
3160 APPLESTATIC int
3161 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3162     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3163 {
3164         u_int32_t *tl;
3165         struct nfsstate st, *stp = &st;
3166         int error = 0;
3167         nfsv4stateid_t stateid;
3168         nfsquad_t clientid;
3169
3170         if ((nd->nd_flag & ND_NFSV41) != 0) {
3171                 nd->nd_repstat = NFSERR_NOTSUPP;
3172                 goto nfsmout;
3173         }
3174         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3175         stp->ls_ownerlen = 0;
3176         stp->ls_op = nd->nd_rp;
3177         stp->ls_uid = nd->nd_cred->cr_uid;
3178         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3179         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3180             NFSX_STATEIDOTHER);
3181         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3182         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3183         stp->ls_flags = NFSLCK_CONFIRM;
3184         clientid.lval[0] = stp->ls_stateid.other[0];
3185         clientid.lval[1] = stp->ls_stateid.other[1];
3186         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3187                 if ((nd->nd_flag & ND_NFSV41) != 0)
3188                         clientid.qval = nd->nd_clientid.qval;
3189                 else if (nd->nd_clientid.qval != clientid.qval)
3190                         printf("EEK11 multiple clids\n");
3191         } else {
3192                 if ((nd->nd_flag & ND_NFSV41) != 0)
3193                         printf("EEK! no clientid from session\n");
3194                 nd->nd_flag |= ND_IMPLIEDCLID;
3195                 nd->nd_clientid.qval = clientid.qval;
3196         }
3197         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3198         if (!nd->nd_repstat) {
3199                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3200                 *tl++ = txdr_unsigned(stateid.seqid);
3201                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3202         }
3203 nfsmout:
3204         vput(vp);
3205         NFSEXITCODE2(error, nd);
3206         return (error);
3207 }
3208
3209 /*
3210  * nfsv4 open downgrade service
3211  */
3212 APPLESTATIC int
3213 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3214     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3215 {
3216         u_int32_t *tl;
3217         int i;
3218         struct nfsstate st, *stp = &st;
3219         int error = 0;
3220         nfsv4stateid_t stateid;
3221         nfsquad_t clientid;
3222
3223         /* opendowngrade can only work on a file object.*/
3224         if (vp->v_type != VREG) {
3225                 error = NFSERR_INVAL;
3226                 goto nfsmout;
3227         }
3228         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3229         stp->ls_ownerlen = 0;
3230         stp->ls_op = nd->nd_rp;
3231         stp->ls_uid = nd->nd_cred->cr_uid;
3232         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3233         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3234             NFSX_STATEIDOTHER);
3235         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3236         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3237         i = fxdr_unsigned(int, *tl++);
3238         switch (i) {
3239         case NFSV4OPEN_ACCESSREAD:
3240                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3241                 break;
3242         case NFSV4OPEN_ACCESSWRITE:
3243                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3244                 break;
3245         case NFSV4OPEN_ACCESSBOTH:
3246                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3247                     NFSLCK_DOWNGRADE);
3248                 break;
3249         default:
3250                 nd->nd_repstat = NFSERR_BADXDR;
3251         }
3252         i = fxdr_unsigned(int, *tl);
3253         switch (i) {
3254         case NFSV4OPEN_DENYNONE:
3255                 break;
3256         case NFSV4OPEN_DENYREAD:
3257                 stp->ls_flags |= NFSLCK_READDENY;
3258                 break;
3259         case NFSV4OPEN_DENYWRITE:
3260                 stp->ls_flags |= NFSLCK_WRITEDENY;
3261                 break;
3262         case NFSV4OPEN_DENYBOTH:
3263                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3264                 break;
3265         default:
3266                 nd->nd_repstat = NFSERR_BADXDR;
3267         }
3268
3269         clientid.lval[0] = stp->ls_stateid.other[0];
3270         clientid.lval[1] = stp->ls_stateid.other[1];
3271         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3272                 if ((nd->nd_flag & ND_NFSV41) != 0)
3273                         clientid.qval = nd->nd_clientid.qval;
3274                 else if (nd->nd_clientid.qval != clientid.qval)
3275                         printf("EEK12 multiple clids\n");
3276         } else {
3277                 if ((nd->nd_flag & ND_NFSV41) != 0)
3278                         printf("EEK! no clientid from session\n");
3279                 nd->nd_flag |= ND_IMPLIEDCLID;
3280                 nd->nd_clientid.qval = clientid.qval;
3281         }
3282         if (!nd->nd_repstat)
3283                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3284                     nd, p);
3285         if (!nd->nd_repstat) {
3286                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3287                 *tl++ = txdr_unsigned(stateid.seqid);
3288                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3289         }
3290 nfsmout:
3291         vput(vp);
3292         NFSEXITCODE2(error, nd);
3293         return (error);
3294 }
3295
3296 /*
3297  * nfsv4 renew lease service
3298  */
3299 APPLESTATIC int
3300 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3301     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3302 {
3303         u_int32_t *tl;
3304         int error = 0;
3305         nfsquad_t clientid;
3306
3307         if ((nd->nd_flag & ND_NFSV41) != 0) {
3308                 nd->nd_repstat = NFSERR_NOTSUPP;
3309                 goto nfsmout;
3310         }
3311         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3312                 nd->nd_repstat = NFSERR_WRONGSEC;
3313                 goto nfsmout;
3314         }
3315         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3316         clientid.lval[0] = *tl++;
3317         clientid.lval[1] = *tl;
3318         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3319                 if ((nd->nd_flag & ND_NFSV41) != 0)
3320                         clientid.qval = nd->nd_clientid.qval;
3321                 else if (nd->nd_clientid.qval != clientid.qval)
3322                         printf("EEK13 multiple clids\n");
3323         } else {
3324                 if ((nd->nd_flag & ND_NFSV41) != 0)
3325                         printf("EEK! no clientid from session\n");
3326                 nd->nd_flag |= ND_IMPLIEDCLID;
3327                 nd->nd_clientid.qval = clientid.qval;
3328         }
3329         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3330             NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3331 nfsmout:
3332         NFSEXITCODE2(error, nd);
3333         return (error);
3334 }
3335
3336 /*
3337  * nfsv4 security info service
3338  */
3339 APPLESTATIC int
3340 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3341     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3342 {
3343         u_int32_t *tl;
3344         int len;
3345         struct nameidata named;
3346         vnode_t dirp = NULL, vp;
3347         struct nfsrvfh fh;
3348         struct nfsexstuff retnes;
3349         u_int32_t *sizp;
3350         int error = 0, savflag, i;
3351         char *bufp;
3352         u_long *hashp;
3353
3354         /*
3355          * All this just to get the export flags for the name.
3356          */
3357         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3358             LOCKLEAF | SAVESTART);
3359         nfsvno_setpathbuf(&named, &bufp, &hashp);
3360         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3361         if (error) {
3362                 vput(dp);
3363                 nfsvno_relpathbuf(&named);
3364                 goto out;
3365         }
3366         if (!nd->nd_repstat) {
3367                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3368         } else {
3369                 vput(dp);
3370                 nfsvno_relpathbuf(&named);
3371         }
3372         if (dirp)
3373                 vrele(dirp);
3374         if (nd->nd_repstat)
3375                 goto out;
3376         vrele(named.ni_startdir);
3377         nfsvno_relpathbuf(&named);
3378         fh.nfsrvfh_len = NFSX_MYFH;
3379         vp = named.ni_vp;
3380         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3381         vput(vp);
3382         savflag = nd->nd_flag;
3383         if (!nd->nd_repstat) {
3384                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3385                 if (vp)
3386                         vput(vp);
3387         }
3388         nd->nd_flag = savflag;
3389         if (nd->nd_repstat)
3390                 goto out;
3391
3392         /*
3393          * Finally have the export flags for name, so we can create
3394          * the security info.
3395          */
3396         len = 0;
3397         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3398         for (i = 0; i < retnes.nes_numsecflavor; i++) {
3399                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3400                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3401                         *tl = txdr_unsigned(RPCAUTH_UNIX);
3402                         len++;
3403                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3404                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3405                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3406                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3407                             nfsgss_mechlist[KERBV_MECH].len);
3408                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3409                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3410                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3411                         len++;
3412                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3413                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3414                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3415                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3416                             nfsgss_mechlist[KERBV_MECH].len);
3417                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3418                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3419                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3420                         len++;
3421                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3422                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3423                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3424                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3425                             nfsgss_mechlist[KERBV_MECH].len);
3426                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3427                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3428                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3429                         len++;
3430                 }
3431         }
3432         *sizp = txdr_unsigned(len);
3433
3434 out:
3435         NFSEXITCODE2(error, nd);
3436         return (error);
3437 }
3438
3439 /*
3440  * nfsv4 set client id service
3441  */
3442 APPLESTATIC int
3443 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3444     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3445 {
3446         u_int32_t *tl;
3447         int i;
3448         int error = 0, idlen;
3449         struct nfsclient *clp = NULL;
3450         struct sockaddr_in *rad;
3451         u_char *verf, *ucp, *ucp2, addrbuf[24];
3452         nfsquad_t clientid, confirm;
3453
3454         if ((nd->nd_flag & ND_NFSV41) != 0) {
3455                 nd->nd_repstat = NFSERR_NOTSUPP;
3456                 goto nfsmout;
3457         }
3458         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3459                 nd->nd_repstat = NFSERR_WRONGSEC;
3460                 goto out;
3461         }
3462         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3463         verf = (u_char *)tl;
3464         tl += (NFSX_VERF / NFSX_UNSIGNED);
3465         i = fxdr_unsigned(int, *tl);
3466         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3467                 nd->nd_repstat = NFSERR_BADXDR;
3468                 goto nfsmout;
3469         }
3470         idlen = i;
3471         if (nd->nd_flag & ND_GSS)
3472                 i += nd->nd_princlen;
3473         clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3474             M_ZERO);
3475         clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3476             nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3477         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3478         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3479         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3480         clp->lc_req.nr_cred = NULL;
3481         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3482         clp->lc_idlen = idlen;
3483         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3484         if (error)
3485                 goto nfsmout;
3486         if (nd->nd_flag & ND_GSS) {
3487                 clp->lc_flags = LCL_GSS;
3488                 if (nd->nd_flag & ND_GSSINTEGRITY)
3489                         clp->lc_flags |= LCL_GSSINTEGRITY;
3490                 else if (nd->nd_flag & ND_GSSPRIVACY)
3491                         clp->lc_flags |= LCL_GSSPRIVACY;
3492         } else {
3493                 clp->lc_flags = 0;
3494         }
3495         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3496                 clp->lc_flags |= LCL_NAME;
3497                 clp->lc_namelen = nd->nd_princlen;
3498                 clp->lc_name = &clp->lc_id[idlen];
3499                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3500         } else {
3501                 clp->lc_uid = nd->nd_cred->cr_uid;
3502                 clp->lc_gid = nd->nd_cred->cr_gid;
3503         }
3504         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3505         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3506         error = nfsrv_getclientipaddr(nd, clp);
3507         if (error)
3508                 goto nfsmout;
3509         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3510         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3511
3512         /*
3513          * nfsrv_setclient() does the actual work of adding it to the
3514          * client list. If there is no error, the structure has been
3515          * linked into the client list and clp should no longer be used
3516          * here. When an error is returned, it has not been linked in,
3517          * so it should be free'd.
3518          */
3519         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3520         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3521                 if (clp->lc_flags & LCL_TCPCALLBACK)
3522                         (void) nfsm_strtom(nd, "tcp", 3);
3523                 else 
3524                         (void) nfsm_strtom(nd, "udp", 3);
3525                 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3526                 ucp = (u_char *)&rad->sin_addr.s_addr;
3527                 ucp2 = (u_char *)&rad->sin_port;
3528                 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3529                     ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3530                     ucp2[0] & 0xff, ucp2[1] & 0xff);
3531                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3532         }
3533         if (clp) {
3534                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3535                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3536                 free(clp->lc_stateid, M_NFSDCLIENT);
3537                 free(clp, M_NFSDCLIENT);
3538         }
3539         if (!nd->nd_repstat) {
3540                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3541                 *tl++ = clientid.lval[0];
3542                 *tl++ = clientid.lval[1];
3543                 *tl++ = confirm.lval[0];
3544                 *tl = confirm.lval[1];
3545         }
3546
3547 out:
3548         NFSEXITCODE2(0, nd);
3549         return (0);
3550 nfsmout:
3551         if (clp) {
3552                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3553                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3554                 free(clp->lc_stateid, M_NFSDCLIENT);
3555                 free(clp, M_NFSDCLIENT);
3556         }
3557         NFSEXITCODE2(error, nd);
3558         return (error);
3559 }
3560
3561 /*
3562  * nfsv4 set client id confirm service
3563  */
3564 APPLESTATIC int
3565 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3566     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3567     __unused struct nfsexstuff *exp)
3568 {
3569         u_int32_t *tl;
3570         int error = 0;
3571         nfsquad_t clientid, confirm;
3572
3573         if ((nd->nd_flag & ND_NFSV41) != 0) {
3574                 nd->nd_repstat = NFSERR_NOTSUPP;
3575                 goto nfsmout;
3576         }
3577         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3578                 nd->nd_repstat = NFSERR_WRONGSEC;
3579                 goto nfsmout;
3580         }
3581         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3582         clientid.lval[0] = *tl++;
3583         clientid.lval[1] = *tl++;
3584         confirm.lval[0] = *tl++;
3585         confirm.lval[1] = *tl;
3586
3587         /*
3588          * nfsrv_getclient() searches the client list for a match and
3589          * returns the appropriate NFSERR status.
3590          */
3591         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3592             NULL, NULL, confirm, 0, nd, p);
3593 nfsmout:
3594         NFSEXITCODE2(error, nd);
3595         return (error);
3596 }
3597
3598 /*
3599  * nfsv4 verify service
3600  */
3601 APPLESTATIC int
3602 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3603     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3604 {
3605         int error = 0, ret, fhsize = NFSX_MYFH;
3606         struct nfsvattr nva;
3607         struct statfs *sf;
3608         struct nfsfsinfo fs;
3609         fhandle_t fh;
3610
3611         sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
3612         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3613         if (!nd->nd_repstat)
3614                 nd->nd_repstat = nfsvno_statfs(vp, sf);
3615         if (!nd->nd_repstat)
3616                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3617         if (!nd->nd_repstat) {
3618                 nfsvno_getfs(&fs, isdgram);
3619                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3620                     sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3621                 if (!error) {
3622                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3623                                 if (ret == 0)
3624                                         nd->nd_repstat = NFSERR_SAME;
3625                                 else if (ret != NFSERR_NOTSAME)
3626                                         nd->nd_repstat = ret;
3627                         } else if (ret)
3628                                 nd->nd_repstat = ret;
3629                 }
3630         }
3631         vput(vp);
3632         free(sf, M_STATFS);
3633         NFSEXITCODE2(error, nd);
3634         return (error);
3635 }
3636
3637 /*
3638  * nfs openattr rpc
3639  */
3640 APPLESTATIC int
3641 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3642     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3643     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3644 {
3645         u_int32_t *tl;
3646         int error = 0, createdir;
3647
3648         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3649         createdir = fxdr_unsigned(int, *tl);
3650         nd->nd_repstat = NFSERR_NOTSUPP;
3651 nfsmout:
3652         vrele(dp);
3653         NFSEXITCODE2(error, nd);
3654         return (error);
3655 }
3656
3657 /*
3658  * nfsv4 release lock owner service
3659  */
3660 APPLESTATIC int
3661 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3662     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3663 {
3664         u_int32_t *tl;
3665         struct nfsstate *stp = NULL;
3666         int error = 0, len;
3667         nfsquad_t clientid;
3668
3669         if ((nd->nd_flag & ND_NFSV41) != 0) {
3670                 nd->nd_repstat = NFSERR_NOTSUPP;
3671                 goto nfsmout;
3672         }
3673         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3674                 nd->nd_repstat = NFSERR_WRONGSEC;
3675                 goto nfsmout;
3676         }
3677         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3678         len = fxdr_unsigned(int, *(tl + 2));
3679         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3680                 nd->nd_repstat = NFSERR_BADXDR;
3681                 goto nfsmout;
3682         }
3683         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3684             M_NFSDSTATE, M_WAITOK);
3685         stp->ls_ownerlen = len;
3686         stp->ls_op = NULL;
3687         stp->ls_flags = NFSLCK_RELEASE;
3688         stp->ls_uid = nd->nd_cred->cr_uid;
3689         clientid.lval[0] = *tl++;
3690         clientid.lval[1] = *tl;
3691         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3692                 if ((nd->nd_flag & ND_NFSV41) != 0)
3693                         clientid.qval = nd->nd_clientid.qval;
3694                 else if (nd->nd_clientid.qval != clientid.qval)
3695                         printf("EEK14 multiple clids\n");
3696         } else {
3697                 if ((nd->nd_flag & ND_NFSV41) != 0)
3698                         printf("EEK! no clientid from session\n");
3699                 nd->nd_flag |= ND_IMPLIEDCLID;
3700                 nd->nd_clientid.qval = clientid.qval;
3701         }
3702         error = nfsrv_mtostr(nd, stp->ls_owner, len);
3703         if (error)
3704                 goto nfsmout;
3705         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3706         FREE((caddr_t)stp, M_NFSDSTATE);
3707
3708         NFSEXITCODE2(0, nd);
3709         return (0);
3710 nfsmout:
3711         if (stp)
3712                 free((caddr_t)stp, M_NFSDSTATE);
3713         NFSEXITCODE2(error, nd);
3714         return (error);
3715 }
3716
3717 /*
3718  * nfsv4 exchange_id service
3719  */
3720 APPLESTATIC int
3721 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3722     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3723 {
3724         uint32_t *tl;
3725         int error = 0, i, idlen;
3726         struct nfsclient *clp = NULL;
3727         nfsquad_t clientid, confirm;
3728         uint8_t *verf;
3729         uint32_t sp4type, v41flags;
3730         uint64_t owner_minor;
3731         struct timespec verstime;
3732
3733         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3734                 nd->nd_repstat = NFSERR_WRONGSEC;
3735                 goto nfsmout;
3736         }
3737         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3738         verf = (uint8_t *)tl;
3739         tl += (NFSX_VERF / NFSX_UNSIGNED);
3740         i = fxdr_unsigned(int, *tl);
3741         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3742                 nd->nd_repstat = NFSERR_BADXDR;
3743                 goto nfsmout;
3744         }
3745         idlen = i;
3746         if (nd->nd_flag & ND_GSS)
3747                 i += nd->nd_princlen;
3748         clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
3749             M_ZERO);
3750         clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
3751             nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3752         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3753         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3754         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3755         clp->lc_req.nr_cred = NULL;
3756         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3757         clp->lc_idlen = idlen;
3758         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3759         if (error != 0)
3760                 goto nfsmout;
3761         if ((nd->nd_flag & ND_GSS) != 0) {
3762                 clp->lc_flags = LCL_GSS | LCL_NFSV41;
3763                 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
3764                         clp->lc_flags |= LCL_GSSINTEGRITY;
3765                 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
3766                         clp->lc_flags |= LCL_GSSPRIVACY;
3767         } else
3768                 clp->lc_flags = LCL_NFSV41;
3769         if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
3770                 clp->lc_flags |= LCL_NAME;
3771                 clp->lc_namelen = nd->nd_princlen;
3772                 clp->lc_name = &clp->lc_id[idlen];
3773                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3774         } else {
3775                 clp->lc_uid = nd->nd_cred->cr_uid;
3776                 clp->lc_gid = nd->nd_cred->cr_gid;
3777         }
3778         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3779         v41flags = fxdr_unsigned(uint32_t, *tl++);
3780         if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
3781             NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
3782             NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
3783                 nd->nd_repstat = NFSERR_INVAL;
3784                 goto nfsmout;
3785         }
3786         if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
3787                 confirm.lval[1] = 1;
3788         else
3789                 confirm.lval[1] = 0;
3790         v41flags = NFSV4EXCH_USENONPNFS;
3791         sp4type = fxdr_unsigned(uint32_t, *tl);
3792         if (sp4type != NFSV4EXCH_SP4NONE) {
3793                 nd->nd_repstat = NFSERR_NOTSUPP;
3794                 goto nfsmout;
3795         }
3796
3797         /*
3798          * nfsrv_setclient() does the actual work of adding it to the
3799          * client list. If there is no error, the structure has been
3800          * linked into the client list and clp should no longer be used
3801          * here. When an error is returned, it has not been linked in,
3802          * so it should be free'd.
3803          */
3804         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3805         if (clp != NULL) {
3806                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3807                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3808                 free(clp->lc_stateid, M_NFSDCLIENT);
3809                 free(clp, M_NFSDCLIENT);
3810         }
3811         if (nd->nd_repstat == 0) {
3812                 if (confirm.lval[1] != 0)
3813                         v41flags |= NFSV4EXCH_CONFIRMEDR;
3814                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
3815                 *tl++ = clientid.lval[0];                       /* ClientID */
3816                 *tl++ = clientid.lval[1];
3817                 *tl++ = txdr_unsigned(confirm.lval[0]);         /* SequenceID */
3818                 *tl++ = txdr_unsigned(v41flags);                /* Exch flags */
3819                 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);       /* No SSV */
3820                 owner_minor = 0;                                /* Owner */
3821                 txdr_hyper(owner_minor, tl);                    /* Minor */
3822                 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
3823                     strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
3824                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3825                 *tl++ = txdr_unsigned(NFSX_UNSIGNED);
3826                 *tl++ = time_uptime;            /* Make scope a unique value. */
3827                 *tl = txdr_unsigned(1);
3828                 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
3829                 (void)nfsm_strtom(nd, version, strlen(version));
3830                 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
3831                 verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
3832                 verstime.tv_nsec = 0;
3833                 txdr_nfsv4time(&verstime, tl);
3834         }
3835         NFSEXITCODE2(0, nd);
3836         return (0);
3837 nfsmout:
3838         if (clp != NULL) {
3839                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3840                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3841                 free(clp->lc_stateid, M_NFSDCLIENT);
3842                 free(clp, M_NFSDCLIENT);
3843         }
3844         NFSEXITCODE2(error, nd);
3845         return (error);
3846 }
3847
3848 /*
3849  * nfsv4 create session service
3850  */
3851 APPLESTATIC int
3852 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
3853     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3854 {
3855         uint32_t *tl;
3856         int error = 0;
3857         nfsquad_t clientid, confirm;
3858         struct nfsdsession *sep = NULL;
3859         uint32_t rdmacnt;
3860
3861         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3862                 nd->nd_repstat = NFSERR_WRONGSEC;
3863                 goto nfsmout;
3864         }
3865         sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
3866             M_NFSDSESSION, M_WAITOK | M_ZERO);
3867         sep->sess_refcnt = 1;
3868         mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
3869         NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
3870         clientid.lval[0] = *tl++;
3871         clientid.lval[1] = *tl++;
3872         confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
3873         sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
3874         /* Persistent sessions and RDMA are not supported. */
3875         sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
3876
3877         /* Fore channel attributes. */
3878         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3879         tl++;                                   /* Header pad always 0. */
3880         sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
3881         sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
3882         sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
3883         sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
3884         sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
3885         if (sep->sess_maxslots > NFSV4_SLOTS)
3886                 sep->sess_maxslots = NFSV4_SLOTS;
3887         rdmacnt = fxdr_unsigned(uint32_t, *tl);
3888         if (rdmacnt > 1) {
3889                 nd->nd_repstat = NFSERR_BADXDR;
3890                 goto nfsmout;
3891         } else if (rdmacnt == 1)
3892                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3893
3894         /* Back channel attributes. */
3895         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3896         tl++;                                   /* Header pad always 0. */
3897         sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
3898         sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
3899         sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
3900         sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
3901         sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
3902         rdmacnt = fxdr_unsigned(uint32_t, *tl);
3903         if (rdmacnt > 1) {
3904                 nd->nd_repstat = NFSERR_BADXDR;
3905                 goto nfsmout;
3906         } else if (rdmacnt == 1)
3907                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3908
3909         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3910         sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
3911
3912         /*
3913          * nfsrv_getclient() searches the client list for a match and
3914          * returns the appropriate NFSERR status.
3915          */
3916         nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
3917             NULL, sep, confirm, sep->sess_cbprogram, nd, p);
3918         if (nd->nd_repstat == 0) {
3919                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3920                 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
3921                 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
3922                 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
3923                 *tl++ = txdr_unsigned(sep->sess_crflags);
3924
3925                 /* Fore channel attributes. */
3926                 *tl++ = 0;
3927                 *tl++ = txdr_unsigned(sep->sess_maxreq);
3928                 *tl++ = txdr_unsigned(sep->sess_maxresp);
3929                 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
3930                 *tl++ = txdr_unsigned(sep->sess_maxops);
3931                 *tl++ = txdr_unsigned(sep->sess_maxslots);
3932                 *tl++ = txdr_unsigned(1);
3933                 *tl++ = txdr_unsigned(0);                       /* No RDMA. */
3934
3935                 /* Back channel attributes. */
3936                 *tl++ = 0;
3937                 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
3938                 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
3939                 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
3940                 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
3941                 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
3942                 *tl++ = txdr_unsigned(1);
3943                 *tl = txdr_unsigned(0);                 /* No RDMA. */
3944         }
3945 nfsmout:
3946         if (nd->nd_repstat != 0 && sep != NULL)
3947                 free(sep, M_NFSDSESSION);
3948         NFSEXITCODE2(error, nd);
3949         return (error);
3950 }
3951
3952 /*
3953  * nfsv4 sequence service
3954  */
3955 APPLESTATIC int
3956 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
3957     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3958 {
3959         uint32_t *tl;
3960         uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
3961         int cache_this, error = 0;
3962
3963         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3964                 nd->nd_repstat = NFSERR_WRONGSEC;
3965                 goto nfsmout;
3966         }
3967         NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
3968         NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
3969         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
3970         sequenceid = fxdr_unsigned(uint32_t, *tl++);
3971         nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
3972         highest_slotid = fxdr_unsigned(uint32_t, *tl++);
3973         if (*tl == newnfs_true)
3974                 cache_this = 1;
3975         else
3976                 cache_this = 0;
3977         nd->nd_flag |= ND_HASSEQUENCE;
3978         nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
3979             &target_highest_slotid, cache_this, &sflags, p);
3980         if (nd->nd_repstat == 0) {
3981                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3982                 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
3983                 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
3984                 *tl++ = txdr_unsigned(sequenceid);
3985                 *tl++ = txdr_unsigned(nd->nd_slotid);
3986                 *tl++ = txdr_unsigned(highest_slotid);
3987                 *tl++ = txdr_unsigned(target_highest_slotid);
3988                 *tl = txdr_unsigned(sflags);
3989         }
3990 nfsmout:
3991         NFSEXITCODE2(error, nd);
3992         return (error);
3993 }
3994
3995 /*
3996  * nfsv4 reclaim complete service
3997  */
3998 APPLESTATIC int
3999 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4000     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4001 {
4002         uint32_t *tl;
4003         int error = 0;
4004
4005         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4006                 nd->nd_repstat = NFSERR_WRONGSEC;
4007                 goto nfsmout;
4008         }
4009         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4010         if (*tl == newnfs_true)
4011                 nd->nd_repstat = NFSERR_NOTSUPP;
4012         else
4013                 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
4014 nfsmout:
4015         NFSEXITCODE2(error, nd);
4016         return (error);
4017 }
4018
4019 /*
4020  * nfsv4 destroy clientid service
4021  */
4022 APPLESTATIC int
4023 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4024     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4025 {
4026         uint32_t *tl;
4027         nfsquad_t clientid;
4028         int error = 0;
4029
4030         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4031                 nd->nd_repstat = NFSERR_WRONGSEC;
4032                 goto nfsmout;
4033         }
4034         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4035         clientid.lval[0] = *tl++;
4036         clientid.lval[1] = *tl;
4037         nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4038 nfsmout:
4039         NFSEXITCODE2(error, nd);
4040         return (error);
4041 }
4042
4043 /*
4044  * nfsv4 destroy session service
4045  */
4046 APPLESTATIC int
4047 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4048     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4049 {
4050         uint8_t *cp, sessid[NFSX_V4SESSIONID];
4051         int error = 0;
4052
4053         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4054                 nd->nd_repstat = NFSERR_WRONGSEC;
4055                 goto nfsmout;
4056         }
4057         NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4058         NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4059         nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4060 nfsmout:
4061         NFSEXITCODE2(error, nd);
4062         return (error);
4063 }
4064
4065 /*
4066  * nfsv4 free stateid service
4067  */
4068 APPLESTATIC int
4069 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4070     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4071 {
4072         uint32_t *tl;
4073         nfsv4stateid_t stateid;
4074         int error = 0;
4075
4076         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4077                 nd->nd_repstat = NFSERR_WRONGSEC;
4078                 goto nfsmout;
4079         }
4080         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4081         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4082         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4083         nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4084 nfsmout:
4085         NFSEXITCODE2(error, nd);
4086         return (error);
4087 }
4088
4089 /*
4090  * nfsv4 service not supported
4091  */
4092 APPLESTATIC int
4093 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4094     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4095 {
4096
4097         nd->nd_repstat = NFSERR_NOTSUPP;
4098         NFSEXITCODE2(0, nd);
4099         return (0);
4100 }
4101