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