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