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