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