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