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