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