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