]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfsserver/nfs_nfsdserv.c
Modify the experimental NFS server so that it uses LK_SHARED
[FreeBSD/FreeBSD.git] / sys / fs / nfsserver / nfs_nfsdserv.c
1 /*-
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
38  * nfs version 2, 3 and 4 server calls to vnode ops
39  * - these routines generally have 3 phases
40  *   1 - break down and validate rpc request in mbuf list
41  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
42  *       function in nfsd_port.c
43  *   3 - build the rpc reply in an mbuf list
44  * For nfsv4, these functions are called for each Op within the Compound RPC.
45  */
46
47 #ifndef APPLEKEXT
48 #include <fs/nfs/nfsport.h>
49
50 /* Global vars */
51 extern u_int32_t newnfs_false, newnfs_true;
52 extern enum vtype nv34tov_type[8];
53 extern struct timeval nfsboottime;
54 extern int nfs_rootfhset, 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, 1);
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, 1);
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, 1);
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, 1);
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, 0);
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, 1);
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, 0);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 1);
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, 0);
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, 1);
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, 0);
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, 0);
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, 0);
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, 0);
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, 1);
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, 0);
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, 0);
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, 0);
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, 1);
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, 0);
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, LK_EXCLUSIVE, &tdp, &tnes, &mp, 0, p);
1396                 if (tdp) {
1397                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1398                             p, 1);
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                     0);
1468         if (tdirp)
1469                 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1470                     0);
1471         if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1472             !(nd->nd_flag & ND_NFSV4))
1473                 nfsvno_unlockvfs(mp);
1474         if (fdirp)
1475                 vrele(fdirp);
1476         if (tdirp)
1477                 vrele(tdirp);
1478         if (nd->nd_flag & ND_NFSV3) {
1479                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1480                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1481         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1482                 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1483                 *tl++ = newnfs_false;
1484                 txdr_hyper(fdirfor.na_filerev, tl);
1485                 tl += 2;
1486                 txdr_hyper(fdiraft.na_filerev, tl);
1487                 tl += 2;
1488                 *tl++ = newnfs_false;
1489                 txdr_hyper(tdirfor.na_filerev, tl);
1490                 tl += 2;
1491                 txdr_hyper(tdiraft.na_filerev, tl);
1492         }
1493         return (0);
1494 }
1495
1496 /*
1497  * nfs link service
1498  */
1499 APPLESTATIC int
1500 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1501     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1502     struct nfsexstuff *toexp)
1503 {
1504         struct nameidata named;
1505         u_int32_t *tl;
1506         int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1507         vnode_t dirp = NULL, dp = NULL;
1508         struct nfsvattr dirfor, diraft, at;
1509         struct nfsexstuff tnes;
1510         struct nfsrvfh dfh;
1511         mount_t mp = NULL;
1512         char *bufp;
1513         u_long *hashp;
1514
1515         if (nd->nd_repstat) {
1516                 nfsrv_postopattr(nd, getret, &at);
1517                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1518                 return (0);
1519         }
1520         NFSVOPUNLOCK(vp, 0, p);
1521         if (vnode_vtype(vp) == VDIR) {
1522                 if (nd->nd_flag & ND_NFSV4)
1523                         nd->nd_repstat = NFSERR_ISDIR;
1524                 else
1525                         nd->nd_repstat = NFSERR_INVAL;
1526                 if (tovp)
1527                         vrele(tovp);
1528         } else if (vnode_vtype(vp) == VLNK) {
1529                 if (nd->nd_flag & ND_NFSV2)
1530                         nd->nd_repstat = NFSERR_INVAL;
1531                 else
1532                         nd->nd_repstat = NFSERR_NOTSUPP;
1533                 if (tovp)
1534                         vrele(tovp);
1535         }
1536         if (!nd->nd_repstat) {
1537                 if (nd->nd_flag & ND_NFSV4) {
1538                         dp = tovp;
1539                         tnes = *toexp;
1540                 } else {
1541                         error = nfsrv_mtofh(nd, &dfh);
1542                         if (error) {
1543                                 vrele(vp);
1544                                 /* tovp is always NULL unless NFSv4 */
1545                                 return (error);
1546                         }
1547                         /* Won't lock vfs if already locked, mp == NULL */
1548                         tnes.nes_vfslocked = exp->nes_vfslocked;
1549                         nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, &mp, 0,
1550                             p);
1551                         if (dp)
1552                                 NFSVOPUNLOCK(dp, 0, p);
1553                 }
1554         }
1555         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1556             LOCKPARENT | SAVENAME);
1557         if (!nd->nd_repstat) {
1558                 nfsvno_setpathbuf(&named, &bufp, &hashp);
1559                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1560                 if (error) {
1561                         vrele(vp);
1562                         if (dp) {
1563                                 if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1564                                     !(nd->nd_flag & ND_NFSV4))
1565                                         nfsvno_unlockvfs(mp);
1566                                 vrele(dp);
1567                         }
1568                         nfsvno_relpathbuf(&named);
1569                         return (error);
1570                 }
1571                 if (!nd->nd_repstat) {
1572                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1573                             p, &dirp);
1574                 } else {
1575                         if (dp)
1576                                 vrele(dp);
1577                         nfsvno_relpathbuf(&named);
1578                 }
1579         }
1580         if (dirp) {
1581                 if (nd->nd_flag & ND_NFSV2) {
1582                         vrele(dirp);
1583                         dirp = NULL;
1584                 } else {
1585                         dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1586                             nd->nd_cred, p, 0);
1587                 }
1588         }
1589         if (!nd->nd_repstat)
1590                 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1591         if (nd->nd_flag & ND_NFSV3)
1592                 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1593         if (dirp) {
1594                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1595                 vrele(dirp);
1596         }
1597         if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
1598             !(nd->nd_flag & ND_NFSV4))
1599                 nfsvno_unlockvfs(mp);
1600         vrele(vp);
1601         if (nd->nd_flag & ND_NFSV3) {
1602                 nfsrv_postopattr(nd, getret, &at);
1603                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1604         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1605                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1606                 *tl++ = newnfs_false;
1607                 txdr_hyper(dirfor.na_filerev, tl);
1608                 tl += 2;
1609                 txdr_hyper(diraft.na_filerev, tl);
1610         }
1611         return (0);
1612 }
1613
1614 /*
1615  * nfs symbolic link service
1616  */
1617 APPLESTATIC int
1618 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1619     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1620     struct nfsexstuff *exp)
1621 {
1622         struct nfsvattr nva, dirfor, diraft;
1623         struct nameidata named;
1624         int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
1625         vnode_t dirp = NULL;
1626         char *bufp, *pathcp = NULL;
1627         u_long *hashp;
1628
1629         if (nd->nd_repstat) {
1630                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1631                 return (0);
1632         }
1633         if (vpp)
1634                 *vpp = NULL;
1635         NFSVNO_ATTRINIT(&nva);
1636         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1637             LOCKPARENT | SAVESTART);
1638         nfsvno_setpathbuf(&named, &bufp, &hashp);
1639         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1640         if (!error && !nd->nd_repstat)
1641                 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1642         if (error) {
1643                 vrele(dp);
1644                 nfsvno_relpathbuf(&named);
1645                 return (error);
1646         }
1647         if (!nd->nd_repstat) {
1648                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1649         } else {
1650                 vrele(dp);
1651                 nfsvno_relpathbuf(&named);
1652         }
1653         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1654                 vrele(dirp);
1655                 dirp = NULL;
1656         }
1657
1658         /*
1659          * And call nfsrvd_symlinksub() to do the common code. It will
1660          * return EBADRPC upon a parsing error, 0 otherwise.
1661          */
1662         if (!nd->nd_repstat) {
1663                 if (dirp != NULL)
1664                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1665                             p, 0);
1666                 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1667                     &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1668                     pathcp, pathlen);
1669         } else if (dirp != NULL) {
1670                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1671                 vrele(dirp);
1672         }
1673         if (pathcp)
1674                 FREE(pathcp, M_TEMP);
1675
1676         if (nd->nd_flag & ND_NFSV3) {
1677                 if (!nd->nd_repstat) {
1678                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1679                         nfsrv_postopattr(nd, 0, &nva);
1680                 }
1681                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1682         }
1683         return (0);
1684 }
1685
1686 /*
1687  * Common code for creating a symbolic link.
1688  */
1689 static void
1690 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1691     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1692     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1693     int *diraft_retp, nfsattrbit_t *attrbitp,
1694     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1695     int pathlen)
1696 {
1697         u_int32_t *tl;
1698
1699         nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1700             !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1701         if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1702                 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1703                 if (nd->nd_flag & ND_NFSV3) {
1704                         nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1705                         if (!nd->nd_repstat)
1706                                 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1707                                     nvap, nd->nd_cred, p, 1);
1708                 }
1709                 if (vpp) {
1710                         NFSVOPUNLOCK(ndp->ni_vp, 0, p);
1711                         *vpp = ndp->ni_vp;
1712                 } else {
1713                         vput(ndp->ni_vp);
1714                 }
1715         }
1716         if (dirp) {
1717                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1718                 vrele(dirp);
1719         }
1720         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1721                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1722                 *tl++ = newnfs_false;
1723                 txdr_hyper(dirforp->na_filerev, tl);
1724                 tl += 2;
1725                 txdr_hyper(diraftp->na_filerev, tl);
1726                 (void) nfsrv_putattrbit(nd, attrbitp);
1727         }
1728 }
1729
1730 /*
1731  * nfs mkdir service
1732  */
1733 APPLESTATIC int
1734 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1735     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1736     struct nfsexstuff *exp)
1737 {
1738         struct nfsvattr nva, dirfor, diraft;
1739         struct nameidata named;
1740         u_int32_t *tl;
1741         int error, dirfor_ret = 1, diraft_ret = 1;
1742         vnode_t dirp = NULL;
1743         char *bufp;
1744         u_long *hashp;
1745
1746         if (nd->nd_repstat) {
1747                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1748                 return (0);
1749         }
1750         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1751             LOCKPARENT | SAVENAME);
1752         nfsvno_setpathbuf(&named, &bufp, &hashp);
1753         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1754         if (error) {
1755                 vrele(dp);
1756                 nfsvno_relpathbuf(&named);
1757                 return (error);
1758         }
1759         if (!nd->nd_repstat) {
1760                 NFSVNO_ATTRINIT(&nva);
1761                 if (nd->nd_flag & ND_NFSV3) {
1762                         error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1763                         if (error) {
1764                                 vrele(dp);
1765                                 nfsvno_relpathbuf(&named);
1766                                 return (error);
1767                         }
1768                 } else {
1769                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1770                         nva.na_mode = nfstov_mode(*tl++);
1771                 }
1772         }
1773         if (!nd->nd_repstat) {
1774                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1775         } else {
1776                 vrele(dp);
1777                 nfsvno_relpathbuf(&named);
1778         }
1779         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1780                 vrele(dirp);
1781                 dirp = NULL;
1782         }
1783         if (nd->nd_repstat) {
1784                 if (dirp != NULL) {
1785                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1786                             p, 0);
1787                         vrele(dirp);
1788                 }
1789                 if (nd->nd_flag & ND_NFSV3)
1790                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1791                             &diraft);
1792                 return (0);
1793         }
1794         if (dirp != NULL)
1795                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1796
1797         /*
1798          * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1799          */
1800         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1801             &diraft_ret, NULL, NULL, p, exp);
1802
1803         if (nd->nd_flag & ND_NFSV3) {
1804                 if (!nd->nd_repstat) {
1805                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1806                         nfsrv_postopattr(nd, 0, &nva);
1807                 }
1808                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1809         } else if (!nd->nd_repstat) {
1810                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1811                 nfsrv_fillattr(nd, &nva);
1812         }
1813         return (0);
1814 nfsmout:
1815         vrele(dp);
1816         nfsvno_relpathbuf(&named);
1817         return (error);
1818 }
1819
1820 /*
1821  * Code common to mkdir for V2,3 and 4.
1822  */
1823 static void
1824 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1825     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1826     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1827     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1828     NFSPROC_T *p, struct nfsexstuff *exp)
1829 {
1830         vnode_t vp;
1831         u_int32_t *tl;
1832
1833         NFSVNO_SETATTRVAL(nvap, type, VDIR);
1834         nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1835             nd->nd_cred, p, exp);
1836         if (!nd->nd_repstat) {
1837                 vp = ndp->ni_vp;
1838                 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1839                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1840                 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1841                         nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1842                             p, 1);
1843                 if (vpp && !nd->nd_repstat) {
1844                         NFSVOPUNLOCK(vp, 0, p);
1845                         *vpp = vp;
1846                 } else {
1847                         vput(vp);
1848                 }
1849         }
1850         if (dirp) {
1851                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1852                 vrele(dirp);
1853         }
1854         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1855                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1856                 *tl++ = newnfs_false;
1857                 txdr_hyper(dirforp->na_filerev, tl);
1858                 tl += 2;
1859                 txdr_hyper(diraftp->na_filerev, tl);
1860                 (void) nfsrv_putattrbit(nd, attrbitp);
1861         }
1862 }
1863
1864 /*
1865  * nfs commit service
1866  */
1867 APPLESTATIC int
1868 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1869     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1870 {
1871         struct nfsvattr bfor, aft;
1872         u_int32_t *tl;
1873         int error = 0, for_ret = 1, aft_ret = 1, cnt;
1874         u_int64_t off;
1875
1876         if (nd->nd_repstat) {
1877                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1878                 return (0);
1879         }
1880         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1881         /*
1882          * XXX At this time VOP_FSYNC() does not accept offset and byte
1883          * count parameters, so these arguments are useless (someday maybe).
1884          */
1885         off = fxdr_hyper(tl);
1886         tl += 2;
1887         cnt = fxdr_unsigned(int, *tl);
1888         if (nd->nd_flag & ND_NFSV3)
1889                 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1890         nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1891         if (nd->nd_flag & ND_NFSV3) {
1892                 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1893                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1894         }
1895         vput(vp);
1896         if (!nd->nd_repstat) {
1897                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1898                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1899                 *tl = txdr_unsigned(nfsboottime.tv_usec);
1900         }
1901         return (0);
1902 nfsmout:
1903         vput(vp);
1904         return (error);
1905 }
1906
1907 /*
1908  * nfs statfs service
1909  */
1910 APPLESTATIC int
1911 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1912     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1913 {
1914         struct statfs *sf;
1915         u_int32_t *tl;
1916         int getret = 1;
1917         struct nfsvattr at;
1918         struct statfs sfs;
1919         u_quad_t tval;
1920
1921         if (nd->nd_repstat) {
1922                 nfsrv_postopattr(nd, getret, &at);
1923                 return (0);
1924         }
1925         sf = &sfs;
1926         nd->nd_repstat = nfsvno_statfs(vp, sf);
1927         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1928         vput(vp);
1929         if (nd->nd_flag & ND_NFSV3)
1930                 nfsrv_postopattr(nd, getret, &at);
1931         if (nd->nd_repstat)
1932                 return (0);
1933         if (nd->nd_flag & ND_NFSV2) {
1934                 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
1935                 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
1936                 *tl++ = txdr_unsigned(sf->f_bsize);
1937                 *tl++ = txdr_unsigned(sf->f_blocks);
1938                 *tl++ = txdr_unsigned(sf->f_bfree);
1939                 *tl = txdr_unsigned(sf->f_bavail);
1940         } else {
1941                 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
1942                 tval = (u_quad_t)sf->f_blocks;
1943                 tval *= (u_quad_t)sf->f_bsize;
1944                 txdr_hyper(tval, tl); tl += 2;
1945                 tval = (u_quad_t)sf->f_bfree;
1946                 tval *= (u_quad_t)sf->f_bsize;
1947                 txdr_hyper(tval, tl); tl += 2;
1948                 tval = (u_quad_t)sf->f_bavail;
1949                 tval *= (u_quad_t)sf->f_bsize;
1950                 txdr_hyper(tval, tl); tl += 2;
1951                 tval = (u_quad_t)sf->f_files;
1952                 txdr_hyper(tval, tl); tl += 2;
1953                 tval = (u_quad_t)sf->f_ffree;
1954                 txdr_hyper(tval, tl); tl += 2;
1955                 tval = (u_quad_t)sf->f_ffree;
1956                 txdr_hyper(tval, tl); tl += 2;
1957                 *tl = 0;
1958         }
1959         return (0);
1960 }
1961
1962 /*
1963  * nfs fsinfo service
1964  */
1965 APPLESTATIC int
1966 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
1967     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1968 {
1969         u_int32_t *tl;
1970         struct nfsfsinfo fs;
1971         int getret = 1;
1972         struct nfsvattr at;
1973
1974         if (nd->nd_repstat) {
1975                 nfsrv_postopattr(nd, getret, &at);
1976                 return (0);
1977         }
1978         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
1979         nfsvno_getfs(&fs, isdgram);
1980         vput(vp);
1981         nfsrv_postopattr(nd, getret, &at);
1982         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
1983         *tl++ = txdr_unsigned(fs.fs_rtmax);
1984         *tl++ = txdr_unsigned(fs.fs_rtpref);
1985         *tl++ = txdr_unsigned(fs.fs_rtmult);
1986         *tl++ = txdr_unsigned(fs.fs_wtmax);
1987         *tl++ = txdr_unsigned(fs.fs_wtpref);
1988         *tl++ = txdr_unsigned(fs.fs_wtmult);
1989         *tl++ = txdr_unsigned(fs.fs_dtpref);
1990         txdr_hyper(fs.fs_maxfilesize, tl);
1991         tl += 2;
1992         txdr_nfsv3time(&fs.fs_timedelta, tl);
1993         tl += 2;
1994         *tl = txdr_unsigned(fs.fs_properties);
1995         return (0);
1996 }
1997
1998 /*
1999  * nfs pathconf service
2000  */
2001 APPLESTATIC int
2002 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2003     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2004 {
2005         struct nfsv3_pathconf *pc;
2006         int getret = 1;
2007         register_t linkmax, namemax, chownres, notrunc;
2008         struct nfsvattr at;
2009
2010         if (nd->nd_repstat) {
2011                 nfsrv_postopattr(nd, getret, &at);
2012                 return (0);
2013         }
2014         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2015             nd->nd_cred, p);
2016         if (!nd->nd_repstat)
2017                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2018                     nd->nd_cred, p);
2019         if (!nd->nd_repstat)
2020                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2021                     &chownres, nd->nd_cred, p);
2022         if (!nd->nd_repstat)
2023                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2024                     nd->nd_cred, p);
2025         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2026         vput(vp);
2027         nfsrv_postopattr(nd, getret, &at);
2028         if (!nd->nd_repstat) {
2029                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2030                 pc->pc_linkmax = txdr_unsigned(linkmax);
2031                 pc->pc_namemax = txdr_unsigned(namemax);
2032                 pc->pc_notrunc = txdr_unsigned(notrunc);
2033                 pc->pc_chownrestricted = txdr_unsigned(chownres);
2034
2035                 /*
2036                  * These should probably be supported by VOP_PATHCONF(), but
2037                  * until msdosfs is exportable (why would you want to?), the
2038                  * Unix defaults should be ok.
2039                  */
2040                 pc->pc_caseinsensitive = newnfs_false;
2041                 pc->pc_casepreserving = newnfs_true;
2042         }
2043         return (0);
2044 }
2045
2046 /*
2047  * nfsv4 lock service
2048  */
2049 APPLESTATIC int
2050 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2051     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2052 {
2053         u_int32_t *tl;
2054         int i;
2055         struct nfsstate *stp = NULL;
2056         struct nfslock *lop;
2057         struct nfslockconflict cf;
2058         int error = 0;
2059         u_short flags = NFSLCK_LOCK, lflags;
2060         u_int64_t offset, len;
2061         nfsv4stateid_t stateid;
2062         nfsquad_t clientid;
2063
2064         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2065         i = fxdr_unsigned(int, *tl++);
2066         switch (i) {
2067         case NFSV4LOCKT_READW:
2068                 flags |= NFSLCK_BLOCKING;
2069         case NFSV4LOCKT_READ:
2070                 lflags = NFSLCK_READ;
2071                 break;
2072         case NFSV4LOCKT_WRITEW:
2073                 flags |= NFSLCK_BLOCKING;
2074         case NFSV4LOCKT_WRITE:
2075                 lflags = NFSLCK_WRITE;
2076                 break;
2077         default:
2078                 nd->nd_repstat = NFSERR_BADXDR;
2079                 goto nfsmout;
2080         };
2081         if (*tl++ == newnfs_true)
2082                 flags |= NFSLCK_RECLAIM;
2083         offset = fxdr_hyper(tl);
2084         tl += 2;
2085         len = fxdr_hyper(tl);
2086         tl += 2;
2087         if (*tl == newnfs_true)
2088                 flags |= NFSLCK_OPENTOLOCK;
2089         if (flags & NFSLCK_OPENTOLOCK) {
2090                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2091                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2092                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2093                         nd->nd_repstat = NFSERR_BADXDR;
2094                         goto nfsmout;
2095                 }
2096                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2097                         M_NFSDSTATE, M_WAITOK);
2098                 stp->ls_ownerlen = i;
2099                 stp->ls_op = nd->nd_rp;
2100                 stp->ls_seq = fxdr_unsigned(int, *tl++);
2101                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2102                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2103                         NFSX_STATEIDOTHER);
2104                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2105                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2106                 clientid.lval[0] = *tl++;
2107                 clientid.lval[1] = *tl++;
2108                 if (nd->nd_flag & ND_IMPLIEDCLID) {
2109                         if (nd->nd_clientid.qval != clientid.qval)
2110                                 printf("EEK! multiple clids\n");
2111                 } else {
2112                         nd->nd_flag |= ND_IMPLIEDCLID;
2113                         nd->nd_clientid.qval = clientid.qval;
2114                 }
2115                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2116                 if (error)
2117                         goto nfsmout;
2118         } else {
2119                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2120                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2121                         M_NFSDSTATE, M_WAITOK);
2122                 stp->ls_ownerlen = 0;
2123                 stp->ls_op = nd->nd_rp;
2124                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2125                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2126                         NFSX_STATEIDOTHER);
2127                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2128                 stp->ls_seq = fxdr_unsigned(int, *tl);
2129                 clientid.lval[0] = stp->ls_stateid.other[0];
2130                 clientid.lval[1] = stp->ls_stateid.other[1];
2131                 if (nd->nd_flag & ND_IMPLIEDCLID) {
2132                         if (nd->nd_clientid.qval != clientid.qval)
2133                                 printf("EEK! multiple clids\n");
2134                 } else {
2135                         nd->nd_flag |= ND_IMPLIEDCLID;
2136                         nd->nd_clientid.qval = clientid.qval;
2137                 }
2138         }
2139         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2140                 M_NFSDLOCK, M_WAITOK);
2141         lop->lo_first = offset;
2142         if (len == NFS64BITSSET) {
2143                 lop->lo_end = NFS64BITSSET;
2144         } else {
2145                 lop->lo_end = offset + len;
2146                 if (lop->lo_end <= lop->lo_first)
2147                         nd->nd_repstat = NFSERR_INVAL;
2148         }
2149         lop->lo_flags = lflags;
2150         stp->ls_flags = flags;
2151         stp->ls_uid = nd->nd_cred->cr_uid;
2152
2153         /*
2154          * Do basic access checking.
2155          */
2156         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2157             if (vnode_vtype(vp) == VDIR)
2158                 nd->nd_repstat = NFSERR_ISDIR;
2159             else
2160                 nd->nd_repstat = NFSERR_INVAL;
2161         }
2162         if (!nd->nd_repstat) {
2163             if (lflags & NFSLCK_WRITE) {
2164                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2165                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2166                     NFSACCCHK_VPISLOCKED, NULL);
2167             } else {
2168                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2169                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2170                     NFSACCCHK_VPISLOCKED, NULL);
2171                 if (nd->nd_repstat)
2172                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2173                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2174                         NFSACCCHK_VPISLOCKED, NULL);
2175             }
2176         }
2177
2178         /*
2179          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2180          * seqid# gets updated. nfsrv_lockctrl() will return the value
2181          * of nd_repstat, if it gets that far.
2182          */
2183         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
2184                 &stateid, exp, nd, p);
2185         if (lop)
2186                 FREE((caddr_t)lop, M_NFSDLOCK);
2187         if (stp)
2188                 FREE((caddr_t)stp, M_NFSDSTATE);
2189         if (!nd->nd_repstat) {
2190                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2191                 *tl++ = txdr_unsigned(stateid.seqid);
2192                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2193         } else if (nd->nd_repstat == NFSERR_DENIED) {
2194                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2195                 txdr_hyper(cf.cl_first, tl);
2196                 tl += 2;
2197                 if (cf.cl_end == NFS64BITSSET)
2198                         len = NFS64BITSSET;
2199                 else
2200                         len = cf.cl_end - cf.cl_first;
2201                 txdr_hyper(len, tl);
2202                 tl += 2;
2203                 if (cf.cl_flags == NFSLCK_WRITE)
2204                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2205                 else
2206                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2207                 *tl++ = stateid.other[0];
2208                 *tl = stateid.other[1];
2209                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2210         }
2211         vput(vp);
2212         return (0);
2213 nfsmout:
2214         vput(vp);
2215         if (stp)
2216                 free((caddr_t)stp, M_NFSDSTATE);
2217         return (error);
2218 }
2219
2220 /*
2221  * nfsv4 lock test service
2222  */
2223 APPLESTATIC int
2224 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2225     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2226 {
2227         u_int32_t *tl;
2228         int i;
2229         struct nfsstate *stp = NULL;
2230         struct nfslock lo, *lop = &lo;
2231         struct nfslockconflict cf;
2232         int error = 0;
2233         nfsv4stateid_t stateid;
2234         nfsquad_t clientid;
2235         u_int64_t len;
2236
2237         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2238         i = fxdr_unsigned(int, *(tl + 7));
2239         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2240                 nd->nd_repstat = NFSERR_BADXDR;
2241                 goto nfsmout;
2242         }
2243         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2244             M_NFSDSTATE, M_WAITOK);
2245         stp->ls_ownerlen = i;
2246         stp->ls_op = NULL;
2247         stp->ls_flags = NFSLCK_TEST;
2248         stp->ls_uid = nd->nd_cred->cr_uid;
2249         i = fxdr_unsigned(int, *tl++);
2250         switch (i) {
2251         case NFSV4LOCKT_READW:
2252                 stp->ls_flags |= NFSLCK_BLOCKING;
2253         case NFSV4LOCKT_READ:
2254                 lo.lo_flags = NFSLCK_READ;
2255                 break;
2256         case NFSV4LOCKT_WRITEW:
2257                 stp->ls_flags |= NFSLCK_BLOCKING;
2258         case NFSV4LOCKT_WRITE:
2259                 lo.lo_flags = NFSLCK_WRITE;
2260                 break;
2261         default:
2262                 nd->nd_repstat = NFSERR_BADXDR;
2263                 goto nfsmout;
2264         };
2265         lo.lo_first = fxdr_hyper(tl);
2266         tl += 2;
2267         len = fxdr_hyper(tl);
2268         if (len == NFS64BITSSET) {
2269                 lo.lo_end = NFS64BITSSET;
2270         } else {
2271                 lo.lo_end = lo.lo_first + len;
2272                 if (lo.lo_end <= lo.lo_first)
2273                         nd->nd_repstat = NFSERR_INVAL;
2274         }
2275         tl += 2;
2276         clientid.lval[0] = *tl++;
2277         clientid.lval[1] = *tl;
2278         if (nd->nd_flag & ND_IMPLIEDCLID) {
2279                 if (nd->nd_clientid.qval != clientid.qval)
2280                         printf("EEK! multiple clids\n");
2281         } else {
2282                 nd->nd_flag |= ND_IMPLIEDCLID;
2283                 nd->nd_clientid.qval = clientid.qval;
2284         }
2285         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2286         if (error)
2287                 goto nfsmout;
2288         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2289             if (vnode_vtype(vp) == VDIR)
2290                 nd->nd_repstat = NFSERR_ISDIR;
2291             else
2292                 nd->nd_repstat = NFSERR_INVAL;
2293         }
2294         if (!nd->nd_repstat)
2295           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2296             &stateid, exp, nd, p);
2297         if (stp)
2298                 FREE((caddr_t)stp, M_NFSDSTATE);
2299         if (nd->nd_repstat) {
2300             if (nd->nd_repstat == NFSERR_DENIED) {
2301                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2302                 txdr_hyper(cf.cl_first, tl);
2303                 tl += 2;
2304                 if (cf.cl_end == NFS64BITSSET)
2305                         len = NFS64BITSSET;
2306                 else
2307                         len = cf.cl_end - cf.cl_first;
2308                 txdr_hyper(len, tl);
2309                 tl += 2;
2310                 if (cf.cl_flags == NFSLCK_WRITE)
2311                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2312                 else
2313                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2314                 *tl++ = stp->ls_stateid.other[0];
2315                 *tl = stp->ls_stateid.other[1];
2316                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2317             }
2318         }
2319         vput(vp);
2320         return (0);
2321 nfsmout:
2322         vput(vp);
2323         if (stp)
2324                 free((caddr_t)stp, M_NFSDSTATE);
2325         return (error);
2326 }
2327
2328 /*
2329  * nfsv4 unlock service
2330  */
2331 APPLESTATIC int
2332 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2333     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2334 {
2335         u_int32_t *tl;
2336         int i;
2337         struct nfsstate *stp;
2338         struct nfslock *lop;
2339         int error = 0;
2340         nfsv4stateid_t stateid;
2341         nfsquad_t clientid;
2342         u_int64_t len;
2343
2344         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2345         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2346             M_NFSDSTATE, M_WAITOK);
2347         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2348             M_NFSDLOCK, M_WAITOK);
2349         stp->ls_flags = NFSLCK_UNLOCK;
2350         lop->lo_flags = NFSLCK_UNLOCK;
2351         stp->ls_op = nd->nd_rp;
2352         i = fxdr_unsigned(int, *tl++);
2353         switch (i) {
2354         case NFSV4LOCKT_READW:
2355                 stp->ls_flags |= NFSLCK_BLOCKING;
2356         case NFSV4LOCKT_READ:
2357                 break;
2358         case NFSV4LOCKT_WRITEW:
2359                 stp->ls_flags |= NFSLCK_BLOCKING;
2360         case NFSV4LOCKT_WRITE:
2361                 break;
2362         default:
2363                 nd->nd_repstat = NFSERR_BADXDR;
2364                 free(stp, M_NFSDSTATE);
2365                 free(lop, M_NFSDLOCK);
2366                 goto nfsmout;
2367         };
2368         stp->ls_ownerlen = 0;
2369         stp->ls_uid = nd->nd_cred->cr_uid;
2370         stp->ls_seq = fxdr_unsigned(int, *tl++);
2371         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2372         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2373             NFSX_STATEIDOTHER);
2374         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2375         lop->lo_first = fxdr_hyper(tl);
2376         tl += 2;
2377         len = fxdr_hyper(tl);
2378         if (len == NFS64BITSSET) {
2379                 lop->lo_end = NFS64BITSSET;
2380         } else {
2381                 lop->lo_end = lop->lo_first + len;
2382                 if (lop->lo_end <= lop->lo_first)
2383                         nd->nd_repstat = NFSERR_INVAL;
2384         }
2385         clientid.lval[0] = stp->ls_stateid.other[0];
2386         clientid.lval[1] = stp->ls_stateid.other[1];
2387         if (nd->nd_flag & ND_IMPLIEDCLID) {
2388                 if (nd->nd_clientid.qval != clientid.qval)
2389                         printf("EEK! multiple clids\n");
2390         } else {
2391                 nd->nd_flag |= ND_IMPLIEDCLID;
2392                 nd->nd_clientid.qval = clientid.qval;
2393         }
2394         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2395             if (vnode_vtype(vp) == VDIR)
2396                 nd->nd_repstat = NFSERR_ISDIR;
2397             else
2398                 nd->nd_repstat = NFSERR_INVAL;
2399         }
2400         /*
2401          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2402          * seqid# gets incremented. nfsrv_lockctrl() will return the
2403          * value of nd_repstat, if it gets that far.
2404          */
2405         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2406             &stateid, exp, nd, p);
2407         if (stp)
2408                 FREE((caddr_t)stp, M_NFSDSTATE);
2409         if (lop)
2410                 free((caddr_t)lop, M_NFSDLOCK);
2411         if (!nd->nd_repstat) {
2412                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2413                 *tl++ = txdr_unsigned(stateid.seqid);
2414                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2415         }
2416 nfsmout:
2417         vput(vp);
2418         return (error);
2419 }
2420
2421 /*
2422  * nfsv4 open service
2423  */
2424 APPLESTATIC int
2425 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2426     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2427     struct nfsexstuff *exp)
2428 {
2429         u_int32_t *tl;
2430         int i;
2431         struct nfsstate *stp = NULL;
2432         int error = 0, create, claim, exclusive_flag = 0;
2433         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2434         int how = NFSCREATE_UNCHECKED;
2435         int32_t cverf[2], tverf[2] = { 0, 0 };
2436         vnode_t vp = NULL, dirp = NULL;
2437         struct nfsvattr nva, dirfor, diraft;
2438         struct nameidata named;
2439         nfsv4stateid_t stateid, delegstateid;
2440         nfsattrbit_t attrbits;
2441         nfsquad_t clientid;
2442         char *bufp = NULL;
2443         u_long *hashp;
2444         NFSACL_T *aclp = NULL;
2445
2446 #ifdef NFS4_ACL_EXTATTR_NAME
2447         aclp = acl_alloc(M_WAITOK);
2448         aclp->acl_cnt = 0;
2449 #endif
2450         NFSZERO_ATTRBIT(&attrbits);
2451         named.ni_startdir = NULL;
2452         named.ni_cnd.cn_nameiop = 0;
2453         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2454         i = fxdr_unsigned(int, *(tl + 5));
2455         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2456                 nd->nd_repstat = NFSERR_BADXDR;
2457                 vrele(dp);
2458 #ifdef NFS4_ACL_EXTATTR_NAME
2459                 acl_free(aclp);
2460 #endif
2461                 return (0);
2462         }
2463         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2464             M_NFSDSTATE, M_WAITOK);
2465         stp->ls_ownerlen = i;
2466         stp->ls_op = nd->nd_rp;
2467         stp->ls_flags = NFSLCK_OPEN;
2468         stp->ls_uid = nd->nd_cred->cr_uid;
2469         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2470         i = fxdr_unsigned(int, *tl++);
2471         switch (i) {
2472         case NFSV4OPEN_ACCESSREAD:
2473                 stp->ls_flags |= NFSLCK_READACCESS;
2474                 break;
2475         case NFSV4OPEN_ACCESSWRITE:
2476                 stp->ls_flags |= NFSLCK_WRITEACCESS;
2477                 break;
2478         case NFSV4OPEN_ACCESSBOTH:
2479                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2480                 break;
2481         default:
2482                 nd->nd_repstat = NFSERR_INVAL;
2483         };
2484         i = fxdr_unsigned(int, *tl++);
2485         switch (i) {
2486         case NFSV4OPEN_DENYNONE:
2487                 break;
2488         case NFSV4OPEN_DENYREAD:
2489                 stp->ls_flags |= NFSLCK_READDENY;
2490                 break;
2491         case NFSV4OPEN_DENYWRITE:
2492                 stp->ls_flags |= NFSLCK_WRITEDENY;
2493                 break;
2494         case NFSV4OPEN_DENYBOTH:
2495                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2496                 break;
2497         default:
2498                 nd->nd_repstat = NFSERR_INVAL;
2499         };
2500         clientid.lval[0] = *tl++;
2501         clientid.lval[1] = *tl;
2502         if (nd->nd_flag & ND_IMPLIEDCLID) {
2503                 if (nd->nd_clientid.qval != clientid.qval)
2504                         printf("EEK! multiple clids\n");
2505         } else {
2506                 nd->nd_flag |= ND_IMPLIEDCLID;
2507                 nd->nd_clientid.qval = clientid.qval;
2508         }
2509         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2510         if (error) {
2511                 vrele(dp);
2512 #ifdef NFS4_ACL_EXTATTR_NAME
2513                 acl_free(aclp);
2514 #endif
2515                 FREE((caddr_t)stp, M_NFSDSTATE);
2516                 return (error);
2517         }
2518         NFSVNO_ATTRINIT(&nva);
2519         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2520         create = fxdr_unsigned(int, *tl);
2521         if (!nd->nd_repstat)
2522                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2523         if (create == NFSV4OPEN_CREATE) {
2524                 nva.na_type = VREG;
2525                 nva.na_mode = 0;
2526                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2527                 how = fxdr_unsigned(int, *tl);
2528                 switch (how) {
2529                 case NFSCREATE_UNCHECKED:
2530                 case NFSCREATE_GUARDED:
2531                         error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2532                         if (error) {
2533                                 vrele(dp);
2534 #ifdef NFS4_ACL_EXTATTR_NAME
2535                                 acl_free(aclp);
2536 #endif
2537                                 FREE((caddr_t)stp, M_NFSDSTATE);
2538                                 return (error);
2539                         }
2540                         /*
2541                          * If the na_gid being set is the same as that of
2542                          * the directory it is going in, clear it, since
2543                          * that is what will be set by default. This allows
2544                          * a user that isn't in that group to do the create.
2545                          */
2546                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2547                             nva.na_gid == dirfor.na_gid)
2548                                 NFSVNO_UNSET(&nva, gid);
2549                         if (!nd->nd_repstat)
2550                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2551                         break;
2552                 case NFSCREATE_EXCLUSIVE:
2553                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2554                         cverf[0] = *tl++;
2555                         cverf[1] = *tl;
2556                         break;
2557                 default:
2558                         nd->nd_repstat = NFSERR_BADXDR;
2559                         vrele(dp);
2560 #ifdef NFS4_ACL_EXTATTR_NAME
2561                         acl_free(aclp);
2562 #endif
2563                         FREE((caddr_t)stp, M_NFSDSTATE);
2564                         return (0);
2565                 };
2566         } else if (create != NFSV4OPEN_NOCREATE) {
2567                 nd->nd_repstat = NFSERR_BADXDR;
2568                 vrele(dp);
2569 #ifdef NFS4_ACL_EXTATTR_NAME
2570                 acl_free(aclp);
2571 #endif
2572                 FREE((caddr_t)stp, M_NFSDSTATE);
2573                 return (0);
2574         }
2575
2576         /*
2577          * Now, handle the claim, which usually includes looking up a
2578          * name in the directory referenced by dp. The exception is
2579          * NFSV4OPEN_CLAIMPREVIOUS.
2580          */
2581         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2582         claim = fxdr_unsigned(int, *tl);
2583         if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2584                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2585                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2586                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2587                 stp->ls_flags |= NFSLCK_DELEGCUR;
2588         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2589                 stp->ls_flags |= NFSLCK_DELEGPREV;
2590         }
2591         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2592             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2593                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2594                     claim != NFSV4OPEN_CLAIMNULL)
2595                         nd->nd_repstat = NFSERR_INVAL;
2596                 if (nd->nd_repstat) {
2597                         nd->nd_repstat = nfsrv_opencheck(clientid,
2598                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
2599                         vrele(dp);
2600 #ifdef NFS4_ACL_EXTATTR_NAME
2601                         acl_free(aclp);
2602 #endif
2603                         FREE((caddr_t)stp, M_NFSDSTATE);
2604                         return (0);
2605                 }
2606                 if (create == NFSV4OPEN_CREATE)
2607                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2608                         LOCKPARENT | LOCKLEAF | SAVESTART);
2609                 else
2610                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2611                         LOCKLEAF | SAVESTART);
2612                 nfsvno_setpathbuf(&named, &bufp, &hashp);
2613                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2614                 if (error) {
2615                         vrele(dp);
2616 #ifdef NFS4_ACL_EXTATTR_NAME
2617                         acl_free(aclp);
2618 #endif
2619                         FREE((caddr_t)stp, M_NFSDSTATE);
2620                         nfsvno_relpathbuf(&named);
2621                         return (error);
2622                 }
2623                 if (!nd->nd_repstat) {
2624                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2625                             p, &dirp);
2626                 } else {
2627                         vrele(dp);
2628                         nfsvno_relpathbuf(&named);
2629                 }
2630                 if (create == NFSV4OPEN_CREATE) {
2631                     switch (how) {
2632                     case NFSCREATE_UNCHECKED:
2633                         if (named.ni_vp) {
2634                                 /*
2635                                  * Clear the setable attribute bits, except
2636                                  * for Size, if it is being truncated.
2637                                  */
2638                                 NFSZERO_ATTRBIT(&attrbits);
2639                                 if (NFSVNO_ISSETSIZE(&nva))
2640                                         NFSSETBIT_ATTRBIT(&attrbits,
2641                                             NFSATTRBIT_SIZE);
2642                         }
2643                         break;
2644                     case NFSCREATE_GUARDED:
2645                         if (named.ni_vp && !nd->nd_repstat)
2646                                 nd->nd_repstat = EEXIST;
2647                         break;
2648                     case NFSCREATE_EXCLUSIVE:
2649                         exclusive_flag = 1;
2650                         if (!named.ni_vp)
2651                                 nva.na_mode = 0;
2652                     };
2653                 }
2654                 nfsvno_open(nd, &named, clientid, &stateid, stp,
2655                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2656                     nd->nd_cred, p, exp, &vp);
2657         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2658                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2659                 i = fxdr_unsigned(int, *tl);
2660                 switch (i) {
2661                 case NFSV4OPEN_DELEGATEREAD:
2662                         stp->ls_flags |= NFSLCK_DELEGREAD;
2663                         break;
2664                 case NFSV4OPEN_DELEGATEWRITE:
2665                         stp->ls_flags |= NFSLCK_DELEGWRITE;
2666                 case NFSV4OPEN_DELEGATENONE:
2667                         break;
2668                 default:
2669                         nd->nd_repstat = NFSERR_BADXDR;
2670                         vrele(dp);
2671 #ifdef NFS4_ACL_EXTATTR_NAME
2672                         acl_free(aclp);
2673 #endif
2674                         FREE((caddr_t)stp, M_NFSDSTATE);
2675                         return (0);
2676                 };
2677                 stp->ls_flags |= NFSLCK_RECLAIM;
2678                 vp = dp;
2679                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
2680                 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp,
2681                     nd, p, nd->nd_repstat);
2682         } else {
2683                 nd->nd_repstat = NFSERR_BADXDR;
2684                 vrele(dp);
2685 #ifdef NFS4_ACL_EXTATTR_NAME
2686                 acl_free(aclp);
2687 #endif
2688                 FREE((caddr_t)stp, M_NFSDSTATE);
2689                 return (0);
2690         }
2691
2692         /*
2693          * Do basic access checking.
2694          */
2695         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2696             if (vnode_vtype(vp) == VDIR)
2697                 nd->nd_repstat = NFSERR_ISDIR;
2698             else if (vnode_vtype(vp) == VLNK)
2699                 nd->nd_repstat = NFSERR_SYMLINK;
2700             else
2701                 nd->nd_repstat = NFSERR_INVAL;
2702         }
2703         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2704             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2705                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2706         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2707             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2708                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2709             if (nd->nd_repstat)
2710                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2711                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2712                     NFSACCCHK_VPISLOCKED, NULL);
2713         }
2714
2715         if (!nd->nd_repstat) {
2716                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2717                 if (!nd->nd_repstat) {
2718                         tverf[0] = nva.na_atime.tv_sec;
2719                         tverf[1] = nva.na_atime.tv_nsec;
2720                 }
2721         }
2722         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2723             cverf[1] != tverf[1]))
2724                 nd->nd_repstat = EEXIST;
2725         /*
2726          * Do the open locking/delegation stuff.
2727          */
2728         if (!nd->nd_repstat)
2729             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2730                 &delegstateid, &rflags, exp, p, nva.na_filerev);
2731
2732         /*
2733          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2734          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2735          * (ie: Leave the NFSVOPUNLOCK() about here.)
2736          */
2737         if (vp)
2738                 NFSVOPUNLOCK(vp, 0, p);
2739         if (stp)
2740                 FREE((caddr_t)stp, M_NFSDSTATE);
2741         if (!nd->nd_repstat && dirp)
2742                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2743                     0);
2744         if (!nd->nd_repstat) {
2745                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2746                 *tl++ = txdr_unsigned(stateid.seqid);
2747                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2748                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2749                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2750                         *tl++ = newnfs_true;
2751                         *tl++ = 0;
2752                         *tl++ = 0;
2753                         *tl++ = 0;
2754                         *tl++ = 0;
2755                 } else {
2756                         *tl++ = newnfs_false;   /* Since dirp is not locked */
2757                         txdr_hyper(dirfor.na_filerev, tl);
2758                         tl += 2;
2759                         txdr_hyper(diraft.na_filerev, tl);
2760                         tl += 2;
2761                 }
2762                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2763                 (void) nfsrv_putattrbit(nd, &attrbits);
2764                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2765                 if (rflags & NFSV4OPEN_READDELEGATE)
2766                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2767                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2768                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2769                 else
2770                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2771                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2772                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2773                         *tl++ = txdr_unsigned(delegstateid.seqid);
2774                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2775                             NFSX_STATEIDOTHER);
2776                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2777                         if (rflags & NFSV4OPEN_RECALL)
2778                                 *tl = newnfs_true;
2779                         else
2780                                 *tl = newnfs_false;
2781                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2782                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2783                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2784                                 txdr_hyper(nva.na_size, tl);
2785                         }
2786                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2787                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2788                         *tl++ = txdr_unsigned(0x0);
2789                         acemask = NFSV4ACE_ALLFILESMASK;
2790                         if (nva.na_mode & S_IRUSR)
2791                             acemask |= NFSV4ACE_READMASK;
2792                         if (nva.na_mode & S_IWUSR)
2793                             acemask |= NFSV4ACE_WRITEMASK;
2794                         if (nva.na_mode & S_IXUSR)
2795                             acemask |= NFSV4ACE_EXECUTEMASK;
2796                         *tl = txdr_unsigned(acemask);
2797                         (void) nfsm_strtom(nd, "OWNER@", 6);
2798                 }
2799                 *vpp = vp;
2800         } else if (vp) {
2801                 vrele(vp);
2802         }
2803         if (dirp)
2804                 vrele(dirp);
2805 #ifdef NFS4_ACL_EXTATTR_NAME
2806         acl_free(aclp);
2807 #endif
2808         return (0);
2809 nfsmout:
2810         vrele(dp);
2811 #ifdef NFS4_ACL_EXTATTR_NAME
2812         acl_free(aclp);
2813 #endif
2814         if (stp)
2815                 FREE((caddr_t)stp, M_NFSDSTATE);
2816         return (error);
2817 }
2818
2819 /*
2820  * nfsv4 close service
2821  */
2822 APPLESTATIC int
2823 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2824     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2825 {
2826         u_int32_t *tl;
2827         struct nfsstate st, *stp = &st;
2828         int error = 0;
2829         nfsv4stateid_t stateid;
2830         nfsquad_t clientid;
2831
2832         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2833         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2834         stp->ls_ownerlen = 0;
2835         stp->ls_op = nd->nd_rp;
2836         stp->ls_uid = nd->nd_cred->cr_uid;
2837         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2838         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2839             NFSX_STATEIDOTHER);
2840         stp->ls_flags = NFSLCK_CLOSE;
2841         clientid.lval[0] = stp->ls_stateid.other[0];
2842         clientid.lval[1] = stp->ls_stateid.other[1];
2843         if (nd->nd_flag & ND_IMPLIEDCLID) {
2844                 if (nd->nd_clientid.qval != clientid.qval)
2845                         printf("EEK! multiple clids\n");
2846         } else {
2847                 nd->nd_flag |= ND_IMPLIEDCLID;
2848                 nd->nd_clientid.qval = clientid.qval;
2849         }
2850         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2851         vput(vp);
2852         if (!nd->nd_repstat) {
2853                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2854                 *tl++ = txdr_unsigned(stateid.seqid);
2855                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2856         }
2857         return (0);
2858 nfsmout:
2859         vput(vp);
2860         return (error);
2861 }
2862
2863 /*
2864  * nfsv4 delegpurge service
2865  */
2866 APPLESTATIC int
2867 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2868     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2869 {
2870         u_int32_t *tl;
2871         int error = 0;
2872         nfsquad_t clientid;
2873
2874         if ((!nfs_rootfhset && !nfsv4root_set) ||
2875             nfsd_checkrootexp(nd)) {
2876                 nd->nd_repstat = NFSERR_WRONGSEC;
2877                 return (0);
2878         }
2879         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2880         clientid.lval[0] = *tl++;
2881         clientid.lval[1] = *tl;
2882         if (nd->nd_flag & ND_IMPLIEDCLID) {
2883                 if (nd->nd_clientid.qval != clientid.qval)
2884                         printf("EEK! multiple clids\n");
2885         } else {
2886                 nd->nd_flag |= ND_IMPLIEDCLID;
2887                 nd->nd_clientid.qval = clientid.qval;
2888         }
2889         nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2890             NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2891 nfsmout:
2892         return (error);
2893 }
2894
2895 /*
2896  * nfsv4 delegreturn service
2897  */
2898 APPLESTATIC int
2899 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2900     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2901 {
2902         u_int32_t *tl;
2903         int error = 0;
2904         nfsv4stateid_t stateid;
2905         nfsquad_t clientid;
2906
2907         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2908         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2909         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2910         clientid.lval[0] = stateid.other[0];
2911         clientid.lval[1] = stateid.other[1];
2912         if (nd->nd_flag & ND_IMPLIEDCLID) {
2913                 if (nd->nd_clientid.qval != clientid.qval)
2914                         printf("EEK! multiple clids\n");
2915         } else {
2916                 nd->nd_flag |= ND_IMPLIEDCLID;
2917                 nd->nd_clientid.qval = clientid.qval;
2918         }
2919         nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2920             NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2921 nfsmout:
2922         vput(vp);
2923         return (error);
2924 }
2925
2926 /*
2927  * nfsv4 get file handle service
2928  */
2929 APPLESTATIC int
2930 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2931     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2932 {
2933         fhandle_t fh;
2934
2935         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2936         vput(vp);
2937         if (!nd->nd_repstat)
2938                 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
2939         return (0);
2940 }
2941
2942 /*
2943  * nfsv4 open confirm service
2944  */
2945 APPLESTATIC int
2946 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
2947     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2948 {
2949         u_int32_t *tl;
2950         struct nfsstate st, *stp = &st;
2951         int error = 0;
2952         nfsv4stateid_t stateid;
2953         nfsquad_t clientid;
2954
2955         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2956         stp->ls_ownerlen = 0;
2957         stp->ls_op = nd->nd_rp;
2958         stp->ls_uid = nd->nd_cred->cr_uid;
2959         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2960         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2961             NFSX_STATEIDOTHER);
2962         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2963         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
2964         stp->ls_flags = NFSLCK_CONFIRM;
2965         clientid.lval[0] = stp->ls_stateid.other[0];
2966         clientid.lval[1] = stp->ls_stateid.other[1];
2967         if (nd->nd_flag & ND_IMPLIEDCLID) {
2968                 if (nd->nd_clientid.qval != clientid.qval)
2969                         printf("EEK! multiple clids\n");
2970         } else {
2971                 nd->nd_flag |= ND_IMPLIEDCLID;
2972                 nd->nd_clientid.qval = clientid.qval;
2973         }
2974         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2975         if (!nd->nd_repstat) {
2976                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2977                 *tl++ = txdr_unsigned(stateid.seqid);
2978                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2979         }
2980 nfsmout:
2981         vput(vp);
2982         return (error);
2983 }
2984
2985 /*
2986  * nfsv4 open downgrade service
2987  */
2988 APPLESTATIC int
2989 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
2990     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2991 {
2992         u_int32_t *tl;
2993         int i;
2994         struct nfsstate st, *stp = &st;
2995         int error = 0;
2996         nfsv4stateid_t stateid;
2997         nfsquad_t clientid;
2998
2999         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3000         stp->ls_ownerlen = 0;
3001         stp->ls_op = nd->nd_rp;
3002         stp->ls_uid = nd->nd_cred->cr_uid;
3003         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3004         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3005             NFSX_STATEIDOTHER);
3006         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3007         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3008         i = fxdr_unsigned(int, *tl++);
3009         switch (i) {
3010         case NFSV4OPEN_ACCESSREAD:
3011                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3012                 break;
3013         case NFSV4OPEN_ACCESSWRITE:
3014                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3015                 break;
3016         case NFSV4OPEN_ACCESSBOTH:
3017                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3018                     NFSLCK_DOWNGRADE);
3019                 break;
3020         default:
3021                 nd->nd_repstat = NFSERR_BADXDR;
3022         };
3023         i = fxdr_unsigned(int, *tl);
3024         switch (i) {
3025         case NFSV4OPEN_DENYNONE:
3026                 break;
3027         case NFSV4OPEN_DENYREAD:
3028                 stp->ls_flags |= NFSLCK_READDENY;
3029                 break;
3030         case NFSV4OPEN_DENYWRITE:
3031                 stp->ls_flags |= NFSLCK_WRITEDENY;
3032                 break;
3033         case NFSV4OPEN_DENYBOTH:
3034                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3035                 break;
3036         default:
3037                 nd->nd_repstat = NFSERR_BADXDR;
3038         };
3039
3040         clientid.lval[0] = stp->ls_stateid.other[0];
3041         clientid.lval[1] = stp->ls_stateid.other[1];
3042         if (nd->nd_flag & ND_IMPLIEDCLID) {
3043                 if (nd->nd_clientid.qval != clientid.qval)
3044                         printf("EEK! multiple clids\n");
3045         } else {
3046                 nd->nd_flag |= ND_IMPLIEDCLID;
3047                 nd->nd_clientid.qval = clientid.qval;
3048         }
3049         if (!nd->nd_repstat)
3050                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3051                     nd, p);
3052         if (!nd->nd_repstat) {
3053                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3054                 *tl++ = txdr_unsigned(stateid.seqid);
3055                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3056         }
3057 nfsmout:
3058         vput(vp);
3059         return (error);
3060 }
3061
3062 /*
3063  * nfsv4 renew lease service
3064  */
3065 APPLESTATIC int
3066 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3067     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3068 {
3069         u_int32_t *tl;
3070         int error = 0;
3071         nfsquad_t clientid;
3072
3073         if ((!nfs_rootfhset && !nfsv4root_set) ||
3074             nfsd_checkrootexp(nd)) {
3075                 nd->nd_repstat = NFSERR_WRONGSEC;
3076                 return (0);
3077         }
3078         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3079         clientid.lval[0] = *tl++;
3080         clientid.lval[1] = *tl;
3081         if (nd->nd_flag & ND_IMPLIEDCLID) {
3082                 if (nd->nd_clientid.qval != clientid.qval)
3083                         printf("EEK! multiple clids\n");
3084         } else {
3085                 nd->nd_flag |= ND_IMPLIEDCLID;
3086                 nd->nd_clientid.qval = clientid.qval;
3087         }
3088         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3089             NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3090 nfsmout:
3091         return (error);
3092 }
3093
3094 /*
3095  * nfsv4 security info service
3096  */
3097 APPLESTATIC int
3098 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3099     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3100 {
3101         u_int32_t *tl;
3102         int len;
3103         struct nameidata named;
3104         vnode_t dirp = NULL, vp;
3105         struct nfsrvfh fh;
3106         struct nfsexstuff retnes;
3107         mount_t mp;
3108         u_int32_t *sizp;
3109         int error, savflag, i;
3110         char *bufp;
3111         u_long *hashp;
3112
3113         /*
3114          * All this just to get the export flags for the name.
3115          */
3116         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3117             LOCKLEAF | SAVESTART);
3118         nfsvno_setpathbuf(&named, &bufp, &hashp);
3119         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3120         if (error) {
3121                 vput(dp);
3122                 nfsvno_relpathbuf(&named);
3123                 return (error);
3124         }
3125         if (!nd->nd_repstat) {
3126                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3127         } else {
3128                 vput(dp);
3129                 nfsvno_relpathbuf(&named);
3130         }
3131         if (dirp)
3132                 vrele(dirp);
3133         if (nd->nd_repstat)
3134                 return (0);
3135         vrele(named.ni_startdir);
3136         nfsvno_relpathbuf(&named);
3137         fh.nfsrvfh_len = NFSX_MYFH;
3138         vp = named.ni_vp;
3139         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3140         mp = vnode_mount(vp);   /* so it won't try to re-lock filesys */
3141         retnes.nes_vfslocked = exp->nes_vfslocked;
3142         vput(vp);
3143         savflag = nd->nd_flag;
3144         if (!nd->nd_repstat) {
3145                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, &mp, 0, p);
3146                 if (vp)
3147                         vput(vp);
3148         }
3149         nd->nd_flag = savflag;
3150         if (nd->nd_repstat)
3151                 return (0);
3152
3153         /*
3154          * Finally have the export flags for name, so we can create
3155          * the security info.
3156          */
3157         len = 0;
3158         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3159         for (i = 0; i < retnes.nes_numsecflavor; i++) {
3160                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3161                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3162                         *tl = txdr_unsigned(RPCAUTH_UNIX);
3163                         len++;
3164                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3165                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3166                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3167                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3168                             nfsgss_mechlist[KERBV_MECH].len);
3169                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3170                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3171                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3172                         len++;
3173                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3174                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3175                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3176                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3177                             nfsgss_mechlist[KERBV_MECH].len);
3178                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3179                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3180                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3181                         len++;
3182                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3183                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3184                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3185                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3186                             nfsgss_mechlist[KERBV_MECH].len);
3187                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3188                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3189                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3190                         len++;
3191                 }
3192         }
3193         *sizp = txdr_unsigned(len);
3194         return (0);
3195 }
3196
3197 /*
3198  * nfsv4 set client id service
3199  */
3200 APPLESTATIC int
3201 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3202     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3203 {
3204         u_int32_t *tl;
3205         int i;
3206         int error = 0, idlen;
3207         struct nfsclient *clp = NULL;
3208         struct sockaddr_in *rad;
3209         u_char *verf, *ucp, *ucp2, addrbuf[24];
3210         nfsquad_t clientid, confirm;
3211
3212         if ((!nfs_rootfhset && !nfsv4root_set) ||
3213             nfsd_checkrootexp(nd)) {
3214                 nd->nd_repstat = NFSERR_WRONGSEC;
3215                 return (0);
3216         }
3217         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3218         verf = (u_char *)tl;
3219         tl += (NFSX_VERF / NFSX_UNSIGNED);
3220         i = fxdr_unsigned(int, *tl);
3221         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3222                 nd->nd_repstat = NFSERR_BADXDR;
3223                 return (error);
3224         }
3225         idlen = i;
3226         if (nd->nd_flag & ND_GSS)
3227                 i += nd->nd_princlen;
3228         MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3229             M_NFSDCLIENT, M_WAITOK);
3230         NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3231         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3232         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3233         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3234         clp->lc_req.nr_cred = NULL;
3235         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3236         clp->lc_idlen = idlen;
3237         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3238         if (error)
3239                 goto nfsmout;
3240         if (nd->nd_flag & ND_GSS) {
3241                 clp->lc_flags = LCL_GSS;
3242                 if (nd->nd_flag & ND_GSSINTEGRITY)
3243                         clp->lc_flags |= LCL_GSSINTEGRITY;
3244                 else if (nd->nd_flag & ND_GSSPRIVACY)
3245                         clp->lc_flags |= LCL_GSSPRIVACY;
3246         } else {
3247                 clp->lc_flags = 0;
3248         }
3249         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3250                 clp->lc_flags |= LCL_NAME;
3251                 clp->lc_namelen = nd->nd_princlen;
3252                 clp->lc_name = &clp->lc_id[idlen];
3253                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3254         } else {
3255                 clp->lc_uid = nd->nd_cred->cr_uid;
3256                 clp->lc_gid = nd->nd_cred->cr_gid;
3257         }
3258         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3259         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3260         error = nfsrv_getclientipaddr(nd, clp);
3261         if (error)
3262                 goto nfsmout;
3263         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3264         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3265
3266         /*
3267          * nfsrv_setclient() does the actual work of adding it to the
3268          * client list. If there is no error, the structure has been
3269          * linked into the client list and clp should no longer be used
3270          * here. When an error is returned, it has not been linked in,
3271          * so it should be free'd.
3272          */
3273         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3274         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3275                 if (clp->lc_flags & LCL_TCPCALLBACK)
3276                         (void) nfsm_strtom(nd, "tcp", 3);
3277                 else 
3278                         (void) nfsm_strtom(nd, "udp", 3);
3279                 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3280                 ucp = (u_char *)&rad->sin_addr.s_addr;
3281                 ucp2 = (u_char *)&rad->sin_port;
3282                 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3283                     ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3284                     ucp2[0] & 0xff, ucp2[1] & 0xff);
3285                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3286         }
3287         if (clp) {
3288                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3289                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3290                 free((caddr_t)clp, M_NFSDCLIENT);
3291         }
3292         if (!nd->nd_repstat) {
3293                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3294                 *tl++ = clientid.lval[0];
3295                 *tl++ = clientid.lval[1];
3296                 *tl++ = confirm.lval[0];
3297                 *tl = confirm.lval[1];
3298         }
3299         return (0);
3300 nfsmout:
3301         if (clp) {
3302                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3303                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3304                 free((caddr_t)clp, M_NFSDCLIENT);
3305         }
3306         return (error);
3307 }
3308
3309 /*
3310  * nfsv4 set client id confirm service
3311  */
3312 APPLESTATIC int
3313 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3314     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3315     __unused struct nfsexstuff *exp)
3316 {
3317         u_int32_t *tl;
3318         int error = 0;
3319         nfsquad_t clientid, confirm;
3320
3321         if ((!nfs_rootfhset && !nfsv4root_set) ||
3322             nfsd_checkrootexp(nd)) {
3323                 nd->nd_repstat = NFSERR_WRONGSEC;
3324                 return (0);
3325         }
3326         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3327         clientid.lval[0] = *tl++;
3328         clientid.lval[1] = *tl++;
3329         confirm.lval[0] = *tl++;
3330         confirm.lval[1] = *tl;
3331
3332         /*
3333          * nfsrv_getclient() searches the client list for a match and
3334          * returns the appropriate NFSERR status.
3335          */
3336         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3337             NULL, confirm, nd, p);
3338 nfsmout:
3339         return (error);
3340 }
3341
3342 /*
3343  * nfsv4 verify service
3344  */
3345 APPLESTATIC int
3346 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3347     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3348 {
3349         int error = 0, ret, fhsize = NFSX_MYFH;
3350         struct nfsvattr nva;
3351         struct statfs sf;
3352         struct nfsfsinfo fs;
3353         fhandle_t fh;
3354
3355         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3356         if (!nd->nd_repstat)
3357                 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3358         if (!nd->nd_repstat)
3359                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3360         if (!nd->nd_repstat) {
3361                 nfsvno_getfs(&fs, isdgram);
3362                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3363                     &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3364                 if (!error) {
3365                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3366                                 if (ret == 0)
3367                                         nd->nd_repstat = NFSERR_SAME;
3368                                 else if (ret != NFSERR_NOTSAME)
3369                                         nd->nd_repstat = ret;
3370                         } else if (ret)
3371                                 nd->nd_repstat = ret;
3372                 }
3373         }
3374         vput(vp);
3375         return (error);
3376 }
3377
3378 /*
3379  * nfs openattr rpc
3380  */
3381 APPLESTATIC int
3382 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3383     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3384     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3385 {
3386         u_int32_t *tl;
3387         int error = 0, createdir;
3388
3389         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3390         createdir = fxdr_unsigned(int, *tl);
3391         nd->nd_repstat = NFSERR_NOTSUPP;
3392 nfsmout:
3393         vrele(dp);
3394         return (error);
3395 }
3396
3397 /*
3398  * nfsv4 release lock owner service
3399  */
3400 APPLESTATIC int
3401 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3402     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3403 {
3404         u_int32_t *tl;
3405         struct nfsstate *stp = NULL;
3406         int error = 0, len;
3407         nfsquad_t clientid;
3408
3409         if ((!nfs_rootfhset && !nfsv4root_set) ||
3410             nfsd_checkrootexp(nd)) {
3411                 nd->nd_repstat = NFSERR_WRONGSEC;
3412                 return (0);
3413         }
3414         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3415         len = fxdr_unsigned(int, *(tl + 2));
3416         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3417                 nd->nd_repstat = NFSERR_BADXDR;
3418                 return (0);
3419         }
3420         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3421             M_NFSDSTATE, M_WAITOK);
3422         stp->ls_ownerlen = len;
3423         stp->ls_op = NULL;
3424         stp->ls_flags = NFSLCK_RELEASE;
3425         stp->ls_uid = nd->nd_cred->cr_uid;
3426         clientid.lval[0] = *tl++;
3427         clientid.lval[1] = *tl;
3428         if (nd->nd_flag & ND_IMPLIEDCLID) {
3429                 if (nd->nd_clientid.qval != clientid.qval)
3430                         printf("EEK! multiple clids\n");
3431         } else {
3432                 nd->nd_flag |= ND_IMPLIEDCLID;
3433                 nd->nd_clientid.qval = clientid.qval;
3434         }
3435         error = nfsrv_mtostr(nd, stp->ls_owner, len);
3436         if (error)
3437                 goto nfsmout;
3438         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3439         FREE((caddr_t)stp, M_NFSDSTATE);
3440         return (0);
3441 nfsmout:
3442         if (stp)
3443                 free((caddr_t)stp, M_NFSDSTATE);
3444         return (error);
3445 }