]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/fs/nfsserver/nfs_nfsdserv.c
MFC r275897:
[FreeBSD/stable/10.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) != 0) {
670                         if ((nd->nd_flag & ND_NFSV41) != 0)
671                                 clientid.qval = nd->nd_clientid.qval;
672                         else if (nd->nd_clientid.qval != clientid.qval)
673                                 printf("EEK1 multiple clids\n");
674                 } else {
675                         if ((nd->nd_flag & ND_NFSV41) != 0)
676                                 printf("EEK! no clientid from session\n");
677                         nd->nd_flag |= ND_IMPLIEDCLID;
678                         nd->nd_clientid.qval = clientid.qval;
679                 }
680                 stp->ls_stateid.other[2] = *tl++;
681                 off = fxdr_hyper(tl);
682                 lop->lo_first = off;
683                 tl += 2;
684                 lop->lo_end = off + reqlen;
685                 /*
686                  * Paranoia, just in case it wraps around.
687                  */
688                 if (lop->lo_end < off)
689                         lop->lo_end = NFS64BITSSET;
690         }
691         if (vnode_vtype(vp) != VREG) {
692                 if (nd->nd_flag & ND_NFSV3)
693                         nd->nd_repstat = EINVAL;
694                 else
695                         nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
696                             EINVAL;
697         }
698         getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
699         if (!nd->nd_repstat)
700                 nd->nd_repstat = getret;
701         if (!nd->nd_repstat &&
702             (nva.na_uid != nd->nd_cred->cr_uid ||
703              NFSVNO_EXSTRICTACCESS(exp))) {
704                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
705                     nd->nd_cred, exp, p,
706                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
707                 if (nd->nd_repstat)
708                         nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
709                             nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
710                             NFSACCCHK_VPISLOCKED, NULL);
711         }
712         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
713                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
714                     &stateid, exp, nd, p);
715         if (nd->nd_repstat) {
716                 vput(vp);
717                 if (nd->nd_flag & ND_NFSV3)
718                         nfsrv_postopattr(nd, getret, &nva);
719                 goto out;
720         }
721         if (off >= nva.na_size) {
722                 cnt = 0;
723                 eof = 1;
724         } else if (reqlen == 0)
725                 cnt = 0;
726         else if ((off + reqlen) >= nva.na_size) {
727                 cnt = nva.na_size - off;
728                 eof = 1;
729         } else
730                 cnt = reqlen;
731         m3 = NULL;
732         if (cnt > 0) {
733                 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
734                     &m3, &m2);
735                 if (!(nd->nd_flag & ND_NFSV4)) {
736                         getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
737                         if (!nd->nd_repstat)
738                                 nd->nd_repstat = getret;
739                 }
740                 if (nd->nd_repstat) {
741                         vput(vp);
742                         if (m3)
743                                 mbuf_freem(m3);
744                         if (nd->nd_flag & ND_NFSV3)
745                                 nfsrv_postopattr(nd, getret, &nva);
746                         goto out;
747                 }
748         }
749         vput(vp);
750         if (nd->nd_flag & ND_NFSV2) {
751                 nfsrv_fillattr(nd, &nva);
752                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
753         } else {
754                 if (nd->nd_flag & ND_NFSV3) {
755                         nfsrv_postopattr(nd, getret, &nva);
756                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
757                         *tl++ = txdr_unsigned(cnt);
758                 } else
759                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
760                 if (eof)
761                         *tl++ = newnfs_true;
762                 else
763                         *tl++ = newnfs_false;
764         }
765         *tl = txdr_unsigned(cnt);
766         if (m3) {
767                 mbuf_setnext(nd->nd_mb, m3);
768                 nd->nd_mb = m2;
769                 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
770         }
771
772 out:
773         NFSEXITCODE2(0, nd);
774         return (0);
775 nfsmout:
776         vput(vp);
777         NFSEXITCODE2(error, nd);
778         return (error);
779 }
780
781 /*
782  * nfs write service
783  */
784 APPLESTATIC int
785 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
786     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
787 {
788         int i, cnt;
789         u_int32_t *tl;
790         mbuf_t mp;
791         struct nfsvattr nva, forat;
792         int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
793         int stable = NFSWRITE_FILESYNC;
794         off_t off;
795         struct nfsstate st, *stp = &st;
796         struct nfslock lo, *lop = &lo;
797         nfsv4stateid_t stateid;
798         nfsquad_t clientid;
799
800         if (nd->nd_repstat) {
801                 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
802                 goto out;
803         }
804         if (nd->nd_flag & ND_NFSV2) {
805                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
806                 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
807                 tl += 2;
808                 retlen = len = fxdr_unsigned(int32_t, *tl);
809         } else if (nd->nd_flag & ND_NFSV3) {
810                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
811                 off = fxdr_hyper(tl);
812                 tl += 3;
813                 stable = fxdr_unsigned(int, *tl++);
814                 retlen = len = fxdr_unsigned(int32_t, *tl);
815         } else {
816                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
817                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
818                 lop->lo_flags = NFSLCK_WRITE;
819                 stp->ls_ownerlen = 0;
820                 stp->ls_op = NULL;
821                 stp->ls_uid = nd->nd_cred->cr_uid;
822                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
823                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
824                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
825                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
826                         if ((nd->nd_flag & ND_NFSV41) != 0)
827                                 clientid.qval = nd->nd_clientid.qval;
828                         else if (nd->nd_clientid.qval != clientid.qval)
829                                 printf("EEK2 multiple clids\n");
830                 } else {
831                         if ((nd->nd_flag & ND_NFSV41) != 0)
832                                 printf("EEK! no clientid from session\n");
833                         nd->nd_flag |= ND_IMPLIEDCLID;
834                         nd->nd_clientid.qval = clientid.qval;
835                 }
836                 stp->ls_stateid.other[2] = *tl++;
837                 off = fxdr_hyper(tl);
838                 lop->lo_first = off;
839                 tl += 2;
840                 stable = fxdr_unsigned(int, *tl++);
841                 retlen = len = fxdr_unsigned(int32_t, *tl);
842                 lop->lo_end = off + len;
843                 /*
844                  * Paranoia, just in case it wraps around, which shouldn't
845                  * ever happen anyhow.
846                  */
847                 if (lop->lo_end < lop->lo_first)
848                         lop->lo_end = NFS64BITSSET;
849         }
850
851         /*
852          * Loop through the mbuf chain, counting how many mbufs are a
853          * part of this write operation, so the iovec size is known.
854          */
855         cnt = 0;
856         mp = nd->nd_md;
857         i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
858         while (len > 0) {
859                 if (i > 0) {
860                         len -= i;
861                         cnt++;
862                 }
863                 mp = mbuf_next(mp);
864                 if (!mp) {
865                         if (len > 0) {
866                                 error = EBADRPC;
867                                 goto nfsmout;
868                         }
869                 } else
870                         i = mbuf_len(mp);
871         }
872
873         if (retlen > NFS_MAXDATA || retlen < 0)
874                 nd->nd_repstat = EIO;
875         if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
876                 if (nd->nd_flag & ND_NFSV3)
877                         nd->nd_repstat = EINVAL;
878                 else
879                         nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
880                             EINVAL;
881         }
882         forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
883         if (!nd->nd_repstat)
884                 nd->nd_repstat = forat_ret;
885         if (!nd->nd_repstat &&
886             (forat.na_uid != nd->nd_cred->cr_uid ||
887              NFSVNO_EXSTRICTACCESS(exp)))
888                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
889                     nd->nd_cred, exp, p,
890                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
891         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
892                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
893                     &stateid, exp, nd, p);
894         }
895         if (nd->nd_repstat) {
896                 vput(vp);
897                 if (nd->nd_flag & ND_NFSV3)
898                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
899                 goto out;
900         }
901
902         /*
903          * For NFS Version 2, it is not obvious what a write of zero length
904          * should do, but I might as well be consistent with Version 3,
905          * which is to return ok so long as there are no permission problems.
906          */
907         if (retlen > 0) {
908                 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
909                     nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
910                 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
911                 if (error)
912                         panic("nfsrv_write mbuf");
913         }
914         if (nd->nd_flag & ND_NFSV4)
915                 aftat_ret = 0;
916         else
917                 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
918         vput(vp);
919         if (!nd->nd_repstat)
920                 nd->nd_repstat = aftat_ret;
921         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
922                 if (nd->nd_flag & ND_NFSV3)
923                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
924                 if (nd->nd_repstat)
925                         goto out;
926                 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
927                 *tl++ = txdr_unsigned(retlen);
928                 /*
929                  * If nfs_async is set, then pretend the write was FILESYNC.
930                  * Warning: Doing this violates RFC1813 and runs a risk
931                  * of data written by a client being lost when the server
932                  * crashes/reboots.
933                  */
934                 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
935                         *tl++ = txdr_unsigned(stable);
936                 else
937                         *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
938                 /*
939                  * Actually, there is no need to txdr these fields,
940                  * but it may make the values more human readable,
941                  * for debugging purposes.
942                  */
943                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
944                 *tl = txdr_unsigned(nfsboottime.tv_usec);
945         } else if (!nd->nd_repstat)
946                 nfsrv_fillattr(nd, &nva);
947
948 out:
949         NFSEXITCODE2(0, nd);
950         return (0);
951 nfsmout:
952         vput(vp);
953         NFSEXITCODE2(error, nd);
954         return (error);
955 }
956
957 /*
958  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
959  * now does a truncate to 0 length via. setattr if it already exists
960  * The core creation routine has been extracted out into nfsrv_creatsub(),
961  * so it can also be used by nfsrv_open() for V4.
962  */
963 APPLESTATIC int
964 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
965     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
966 {
967         struct nfsvattr nva, dirfor, diraft;
968         struct nfsv2_sattr *sp;
969         struct nameidata named;
970         u_int32_t *tl;
971         int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
972         int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
973         NFSDEV_T rdev = 0;
974         vnode_t vp = NULL, dirp = NULL;
975         fhandle_t fh;
976         char *bufp;
977         u_long *hashp;
978         enum vtype vtyp;
979         int32_t cverf[2], tverf[2] = { 0, 0 };
980
981         if (nd->nd_repstat) {
982                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
983                 goto out;
984         }
985         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
986             LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
987         nfsvno_setpathbuf(&named, &bufp, &hashp);
988         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
989         if (error)
990                 goto nfsmout;
991         if (!nd->nd_repstat) {
992                 NFSVNO_ATTRINIT(&nva);
993                 if (nd->nd_flag & ND_NFSV2) {
994                         NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
995                         vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
996                         if (vtyp == VNON)
997                                 vtyp = VREG;
998                         NFSVNO_SETATTRVAL(&nva, type, vtyp);
999                         NFSVNO_SETATTRVAL(&nva, mode,
1000                             nfstov_mode(sp->sa_mode));
1001                         switch (nva.na_type) {
1002                         case VREG:
1003                                 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1004                                 if (tsize != -1)
1005                                         NFSVNO_SETATTRVAL(&nva, size,
1006                                             (u_quad_t)tsize);
1007                                 break;
1008                         case VCHR:
1009                         case VBLK:
1010                         case VFIFO:
1011                                 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1012                                 break;
1013                         default:
1014                                 break;
1015                         };
1016                 } else {
1017                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1018                         how = fxdr_unsigned(int, *tl);
1019                         switch (how) {
1020                         case NFSCREATE_GUARDED:
1021                         case NFSCREATE_UNCHECKED:
1022                                 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1023                                 if (error)
1024                                         goto nfsmout;
1025                                 break;
1026                         case NFSCREATE_EXCLUSIVE:
1027                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1028                                 cverf[0] = *tl++;
1029                                 cverf[1] = *tl;
1030                                 exclusive_flag = 1;
1031                                 break;
1032                         };
1033                         NFSVNO_SETATTRVAL(&nva, type, VREG);
1034                 }
1035         }
1036         if (nd->nd_repstat) {
1037                 nfsvno_relpathbuf(&named);
1038                 if (nd->nd_flag & ND_NFSV3) {
1039                         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
1040                             p, 1);
1041                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1042                             &diraft);
1043                 }
1044                 vput(dp);
1045                 goto out;
1046         }
1047
1048         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1049         if (dirp) {
1050                 if (nd->nd_flag & ND_NFSV2) {
1051                         vrele(dirp);
1052                         dirp = NULL;
1053                 } else {
1054                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1055                             p, 0);
1056                 }
1057         }
1058         if (nd->nd_repstat) {
1059                 if (nd->nd_flag & ND_NFSV3)
1060                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1061                             &diraft);
1062                 if (dirp)
1063                         vrele(dirp);
1064                 goto out;
1065         }
1066
1067         if (!(nd->nd_flag & ND_NFSV2)) {
1068                 switch (how) {
1069                 case NFSCREATE_GUARDED:
1070                         if (named.ni_vp)
1071                                 nd->nd_repstat = EEXIST;
1072                         break;
1073                 case NFSCREATE_UNCHECKED:
1074                         break;
1075                 case NFSCREATE_EXCLUSIVE:
1076                         if (named.ni_vp == NULL)
1077                                 NFSVNO_SETATTRVAL(&nva, mode, 0);
1078                         break;
1079                 };
1080         }
1081
1082         /*
1083          * Iff doesn't exist, create it
1084          * otherwise just truncate to 0 length
1085          *   should I set the mode too ?
1086          */
1087         nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1088             &exclusive_flag, cverf, rdev, p, exp);
1089
1090         if (!nd->nd_repstat) {
1091                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1092                 if (!nd->nd_repstat)
1093                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1094                             p, 1);
1095                 vput(vp);
1096                 if (!nd->nd_repstat) {
1097                         tverf[0] = nva.na_atime.tv_sec;
1098                         tverf[1] = nva.na_atime.tv_nsec;
1099                 }
1100         }
1101         if (nd->nd_flag & ND_NFSV2) {
1102                 if (!nd->nd_repstat) {
1103                         (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
1104                         nfsrv_fillattr(nd, &nva);
1105                 }
1106         } else {
1107                 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1108                     || cverf[1] != tverf[1]))
1109                         nd->nd_repstat = EEXIST;
1110                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1111                 vrele(dirp);
1112                 if (!nd->nd_repstat) {
1113                         (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
1114                         nfsrv_postopattr(nd, 0, &nva);
1115                 }
1116                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1117         }
1118
1119 out:
1120         NFSEXITCODE2(0, nd);
1121         return (0);
1122 nfsmout:
1123         vput(dp);
1124         nfsvno_relpathbuf(&named);
1125         NFSEXITCODE2(error, nd);
1126         return (error);
1127 }
1128
1129 /*
1130  * nfs v3 mknod service (and v4 create)
1131  */
1132 APPLESTATIC int
1133 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1134     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1135     struct nfsexstuff *exp)
1136 {
1137         struct nfsvattr nva, dirfor, diraft;
1138         u_int32_t *tl;
1139         struct nameidata named;
1140         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1141         u_int32_t major, minor;
1142         enum vtype vtyp = VNON;
1143         nfstype nfs4type = NFNON;
1144         vnode_t vp, dirp = NULL;
1145         nfsattrbit_t attrbits;
1146         char *bufp = NULL, *pathcp = NULL;
1147         u_long *hashp, cnflags;
1148         NFSACL_T *aclp = NULL;
1149
1150         NFSVNO_ATTRINIT(&nva);
1151         cnflags = (LOCKPARENT | SAVESTART);
1152         if (nd->nd_repstat) {
1153                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1154                 goto out;
1155         }
1156 #ifdef NFS4_ACL_EXTATTR_NAME
1157         aclp = acl_alloc(M_WAITOK);
1158         aclp->acl_cnt = 0;
1159 #endif
1160
1161         /*
1162          * For V4, the creation stuff is here, Yuck!
1163          */
1164         if (nd->nd_flag & ND_NFSV4) {
1165                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1166                 vtyp = nfsv34tov_type(*tl);
1167                 nfs4type = fxdr_unsigned(nfstype, *tl);
1168                 switch (nfs4type) {
1169                 case NFLNK:
1170                         error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1171                             &pathlen);
1172                         if (error)
1173                                 goto nfsmout;
1174                         break;
1175                 case NFCHR:
1176                 case NFBLK:
1177                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1178                         major = fxdr_unsigned(u_int32_t, *tl++);
1179                         minor = fxdr_unsigned(u_int32_t, *tl);
1180                         nva.na_rdev = NFSMAKEDEV(major, minor);
1181                         break;
1182                 case NFSOCK:
1183                 case NFFIFO:
1184                         break;
1185                 case NFDIR:
1186                         cnflags = (LOCKPARENT | SAVENAME);
1187                         break;
1188                 default:
1189                         nd->nd_repstat = NFSERR_BADTYPE;
1190                         vrele(dp);
1191 #ifdef NFS4_ACL_EXTATTR_NAME
1192                         acl_free(aclp);
1193 #endif
1194                         goto out;
1195                 }
1196         }
1197         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1198         nfsvno_setpathbuf(&named, &bufp, &hashp);
1199         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1200         if (error)
1201                 goto nfsmout;
1202         if (!nd->nd_repstat) {
1203                 if (nd->nd_flag & ND_NFSV3) {
1204                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1205                         vtyp = nfsv34tov_type(*tl);
1206                 }
1207                 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
1208                 if (error)
1209                         goto nfsmout;
1210                 nva.na_type = vtyp;
1211                 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1212                     (vtyp == VCHR || vtyp == VBLK)) {
1213                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1214                         major = fxdr_unsigned(u_int32_t, *tl++);
1215                         minor = fxdr_unsigned(u_int32_t, *tl);
1216                         nva.na_rdev = NFSMAKEDEV(major, minor);
1217                 }
1218         }
1219
1220         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
1221         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1222                 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1223                     dirfor.na_gid == nva.na_gid)
1224                         NFSVNO_UNSET(&nva, gid);
1225                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1226         }
1227         if (nd->nd_repstat) {
1228                 vrele(dp);
1229 #ifdef NFS4_ACL_EXTATTR_NAME
1230                 acl_free(aclp);
1231 #endif
1232                 nfsvno_relpathbuf(&named);
1233                 if (pathcp)
1234                         FREE(pathcp, M_TEMP);
1235                 if (nd->nd_flag & ND_NFSV3)
1236                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1237                             &diraft);
1238                 goto out;
1239         }
1240
1241         /*
1242          * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1243          * in va_mode, so we'll have to set a default here.
1244          */
1245         if (NFSVNO_NOTSETMODE(&nva)) {
1246                 if (vtyp == VLNK)
1247                         nva.na_mode = 0755;
1248                 else
1249                         nva.na_mode = 0400;
1250         }
1251
1252         if (vtyp == VDIR)
1253                 named.ni_cnd.cn_flags |= WILLBEDIR;
1254         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1255         if (nd->nd_repstat) {
1256                 if (dirp) {
1257                         if (nd->nd_flag & ND_NFSV3)
1258                                 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1259                                     nd->nd_cred, p, 0);
1260                         vrele(dirp);
1261                 }
1262 #ifdef NFS4_ACL_EXTATTR_NAME
1263                 acl_free(aclp);
1264 #endif
1265                 if (nd->nd_flag & ND_NFSV3)
1266                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1267                             &diraft);
1268                 goto out;
1269         }
1270         if (dirp)
1271                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1272
1273         if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1274                 if (vtyp == VDIR) {
1275                         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1276                             &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1277                             exp);
1278 #ifdef NFS4_ACL_EXTATTR_NAME
1279                         acl_free(aclp);
1280 #endif
1281                         goto out;
1282                 } else if (vtyp == VLNK) {
1283                         nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1284                             &dirfor, &diraft, &diraft_ret, &attrbits,
1285                             aclp, p, exp, pathcp, pathlen);
1286 #ifdef NFS4_ACL_EXTATTR_NAME
1287                         acl_free(aclp);
1288 #endif
1289                         FREE(pathcp, M_TEMP);
1290                         goto out;
1291                 }
1292         }
1293
1294         nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1295         if (!nd->nd_repstat) {
1296                 vp = named.ni_vp;
1297                 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1298                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1299                 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1300                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
1301                             p, 1);
1302                 if (vpp != NULL && nd->nd_repstat == 0) {
1303                         NFSVOPUNLOCK(vp, 0);
1304                         *vpp = vp;
1305                 } else
1306                         vput(vp);
1307         }
1308
1309         diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1310         vrele(dirp);
1311         if (!nd->nd_repstat) {
1312                 if (nd->nd_flag & ND_NFSV3) {
1313                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1314                         nfsrv_postopattr(nd, 0, &nva);
1315                 } else {
1316                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1317                         *tl++ = newnfs_false;
1318                         txdr_hyper(dirfor.na_filerev, tl);
1319                         tl += 2;
1320                         txdr_hyper(diraft.na_filerev, tl);
1321                         (void) nfsrv_putattrbit(nd, &attrbits);
1322                 }
1323         }
1324         if (nd->nd_flag & ND_NFSV3)
1325                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1326 #ifdef NFS4_ACL_EXTATTR_NAME
1327         acl_free(aclp);
1328 #endif
1329
1330 out:
1331         NFSEXITCODE2(0, nd);
1332         return (0);
1333 nfsmout:
1334         vrele(dp);
1335 #ifdef NFS4_ACL_EXTATTR_NAME
1336         acl_free(aclp);
1337 #endif
1338         if (bufp)
1339                 nfsvno_relpathbuf(&named);
1340         if (pathcp)
1341                 FREE(pathcp, M_TEMP);
1342
1343         NFSEXITCODE2(error, nd);
1344         return (error);
1345 }
1346
1347 /*
1348  * nfs remove service
1349  */
1350 APPLESTATIC int
1351 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1352     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
1353 {
1354         struct nameidata named;
1355         u_int32_t *tl;
1356         int error = 0, dirfor_ret = 1, diraft_ret = 1;
1357         vnode_t dirp = NULL;
1358         struct nfsvattr dirfor, diraft;
1359         char *bufp;
1360         u_long *hashp;
1361
1362         if (nd->nd_repstat) {
1363                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1364                 goto out;
1365         }
1366         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1367             LOCKPARENT | LOCKLEAF);
1368         nfsvno_setpathbuf(&named, &bufp, &hashp);
1369         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1370         if (error) {
1371                 vput(dp);
1372                 nfsvno_relpathbuf(&named);
1373                 goto out;
1374         }
1375         if (!nd->nd_repstat) {
1376                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
1377         } else {
1378                 vput(dp);
1379                 nfsvno_relpathbuf(&named);
1380         }
1381         if (dirp) {
1382                 if (!(nd->nd_flag & ND_NFSV2)) {
1383                         dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1384                             nd->nd_cred, p, 0);
1385                 } else {
1386                         vrele(dirp);
1387                         dirp = NULL;
1388                 }
1389         }
1390         if (!nd->nd_repstat) {
1391                 if (nd->nd_flag & ND_NFSV4) {
1392                         if (vnode_vtype(named.ni_vp) == VDIR)
1393                                 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1394                                     nd->nd_cred, p, exp);
1395                         else
1396                                 nd->nd_repstat = nfsvno_removesub(&named, 1,
1397                                     nd->nd_cred, p, exp);
1398                 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
1399                         nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1400                             nd->nd_cred, p, exp);
1401                 } else {
1402                         nd->nd_repstat = nfsvno_removesub(&named, 0,
1403                             nd->nd_cred, p, exp);
1404                 }
1405         }
1406         if (!(nd->nd_flag & ND_NFSV2)) {
1407                 if (dirp) {
1408                         diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
1409                             p, 0);
1410                         vrele(dirp);
1411                 }
1412                 if (nd->nd_flag & ND_NFSV3) {
1413                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1414                             &diraft);
1415                 } else if (!nd->nd_repstat) {
1416                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1417                         *tl++ = newnfs_false;
1418                         txdr_hyper(dirfor.na_filerev, tl);
1419                         tl += 2;
1420                         txdr_hyper(diraft.na_filerev, tl);
1421                 }
1422         }
1423
1424 out:
1425         NFSEXITCODE2(error, nd);
1426         return (error);
1427 }
1428
1429 /*
1430  * nfs rename service
1431  */
1432 APPLESTATIC int
1433 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1434     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
1435     struct nfsexstuff *toexp)
1436 {
1437         u_int32_t *tl;
1438         int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1439         int tdirfor_ret = 1, tdiraft_ret = 1;
1440         struct nameidata fromnd, tond;
1441         vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1442         struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1443         struct nfsexstuff tnes;
1444         struct nfsrvfh tfh;
1445         char *bufp, *tbufp = NULL;
1446         u_long *hashp;
1447         fhandle_t fh;
1448
1449         if (nd->nd_repstat) {
1450                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1451                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1452                 goto out;
1453         }
1454         if (!(nd->nd_flag & ND_NFSV2))
1455                 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
1456         tond.ni_cnd.cn_nameiop = 0;
1457         tond.ni_startdir = NULL;
1458         NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
1459         nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1460         error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1461         if (error) {
1462                 vput(dp);
1463                 if (todp)
1464                         vrele(todp);
1465                 nfsvno_relpathbuf(&fromnd);
1466                 goto out;
1467         }
1468         /*
1469          * Unlock dp in this code section, so it is unlocked before
1470          * tdp gets locked. This avoids a potential LOR if tdp is the
1471          * parent directory of dp.
1472          */
1473         if (nd->nd_flag & ND_NFSV4) {
1474                 tdp = todp;
1475                 tnes = *toexp;
1476                 if (dp != tdp) {
1477                         NFSVOPUNLOCK(dp, 0);
1478                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1479                             p, 0);      /* Might lock tdp. */
1480                 } else {
1481                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1482                             p, 1);
1483                         NFSVOPUNLOCK(dp, 0);
1484                 }
1485         } else {
1486                 tfh.nfsrvfh_len = 0;
1487                 error = nfsrv_mtofh(nd, &tfh);
1488                 if (error == 0)
1489                         error = nfsvno_getfh(dp, &fh, p);
1490                 if (error) {
1491                         vput(dp);
1492                         /* todp is always NULL except NFSv4 */
1493                         nfsvno_relpathbuf(&fromnd);
1494                         goto out;
1495                 }
1496
1497                 /* If this is the same file handle, just VREF() the vnode. */
1498                 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1499                     !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1500                         VREF(dp);
1501                         tdp = dp;
1502                         tnes = *exp;
1503                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1504                             p, 1);
1505                         NFSVOPUNLOCK(dp, 0);
1506                 } else {
1507                         NFSVOPUNLOCK(dp, 0);
1508                         nd->nd_cred->cr_uid = nd->nd_saveduid;
1509                         nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1510                             0, p);      /* Locks tdp. */
1511                         if (tdp) {
1512                                 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1513                                     nd->nd_cred, p, 1);
1514                                 NFSVOPUNLOCK(tdp, 0);
1515                         }
1516                 }
1517         }
1518         NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1519         nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1520         if (!nd->nd_repstat) {
1521                 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1522                 if (error) {
1523                         if (tdp)
1524                                 vrele(tdp);
1525                         vrele(dp);
1526                         nfsvno_relpathbuf(&fromnd);
1527                         nfsvno_relpathbuf(&tond);
1528                         goto out;
1529                 }
1530         }
1531         if (nd->nd_repstat) {
1532                 if (nd->nd_flag & ND_NFSV3) {
1533                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1534                             &fdiraft);
1535                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1536                             &tdiraft);
1537                 }
1538                 if (tdp)
1539                         vrele(tdp);
1540                 vrele(dp);
1541                 nfsvno_relpathbuf(&fromnd);
1542                 nfsvno_relpathbuf(&tond);
1543                 goto out;
1544         }
1545
1546         /*
1547          * Done parsing, now down to business.
1548          */
1549         nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1550         if (nd->nd_repstat) {
1551                 if (nd->nd_flag & ND_NFSV3) {
1552                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1553                             &fdiraft);
1554                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1555                             &tdiraft);
1556                 }
1557                 if (fdirp)
1558                         vrele(fdirp);
1559                 if (tdp)
1560                         vrele(tdp);
1561                 nfsvno_relpathbuf(&tond);
1562                 goto out;
1563         }
1564         if (vnode_vtype(fromnd.ni_vp) == VDIR)
1565                 tond.ni_cnd.cn_flags |= WILLBEDIR;
1566         nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1567         nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1568             nd->nd_flag, nd->nd_cred, p);
1569         if (fdirp)
1570                 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1571                     0);
1572         if (tdirp)
1573                 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1574                     0);
1575         if (fdirp)
1576                 vrele(fdirp);
1577         if (tdirp)
1578                 vrele(tdirp);
1579         if (nd->nd_flag & ND_NFSV3) {
1580                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1581                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1582         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1583                 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1584                 *tl++ = newnfs_false;
1585                 txdr_hyper(fdirfor.na_filerev, tl);
1586                 tl += 2;
1587                 txdr_hyper(fdiraft.na_filerev, tl);
1588                 tl += 2;
1589                 *tl++ = newnfs_false;
1590                 txdr_hyper(tdirfor.na_filerev, tl);
1591                 tl += 2;
1592                 txdr_hyper(tdiraft.na_filerev, tl);
1593         }
1594
1595 out:
1596         NFSEXITCODE2(error, nd);
1597         return (error);
1598 }
1599
1600 /*
1601  * nfs link service
1602  */
1603 APPLESTATIC int
1604 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1605     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1606     struct nfsexstuff *toexp)
1607 {
1608         struct nameidata named;
1609         u_int32_t *tl;
1610         int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1611         vnode_t dirp = NULL, dp = NULL;
1612         struct nfsvattr dirfor, diraft, at;
1613         struct nfsexstuff tnes;
1614         struct nfsrvfh dfh;
1615         char *bufp;
1616         u_long *hashp;
1617
1618         if (nd->nd_repstat) {
1619                 nfsrv_postopattr(nd, getret, &at);
1620                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1621                 goto out;
1622         }
1623         NFSVOPUNLOCK(vp, 0);
1624         if (vnode_vtype(vp) == VDIR) {
1625                 if (nd->nd_flag & ND_NFSV4)
1626                         nd->nd_repstat = NFSERR_ISDIR;
1627                 else
1628                         nd->nd_repstat = NFSERR_INVAL;
1629                 if (tovp)
1630                         vrele(tovp);
1631         }
1632         if (!nd->nd_repstat) {
1633                 if (nd->nd_flag & ND_NFSV4) {
1634                         dp = tovp;
1635                         tnes = *toexp;
1636                 } else {
1637                         error = nfsrv_mtofh(nd, &dfh);
1638                         if (error) {
1639                                 vrele(vp);
1640                                 /* tovp is always NULL unless NFSv4 */
1641                                 goto out;
1642                         }
1643                         nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1644                             p);
1645                         if (dp)
1646                                 NFSVOPUNLOCK(dp, 0);
1647                 }
1648         }
1649         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1650             LOCKPARENT | SAVENAME | NOCACHE);
1651         if (!nd->nd_repstat) {
1652                 nfsvno_setpathbuf(&named, &bufp, &hashp);
1653                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1654                 if (error) {
1655                         vrele(vp);
1656                         if (dp)
1657                                 vrele(dp);
1658                         nfsvno_relpathbuf(&named);
1659                         goto out;
1660                 }
1661                 if (!nd->nd_repstat) {
1662                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1663                             p, &dirp);
1664                 } else {
1665                         if (dp)
1666                                 vrele(dp);
1667                         nfsvno_relpathbuf(&named);
1668                 }
1669         }
1670         if (dirp) {
1671                 if (nd->nd_flag & ND_NFSV2) {
1672                         vrele(dirp);
1673                         dirp = NULL;
1674                 } else {
1675                         dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1676                             nd->nd_cred, p, 0);
1677                 }
1678         }
1679         if (!nd->nd_repstat)
1680                 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1681         if (nd->nd_flag & ND_NFSV3)
1682                 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1683         if (dirp) {
1684                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1685                 vrele(dirp);
1686         }
1687         vrele(vp);
1688         if (nd->nd_flag & ND_NFSV3) {
1689                 nfsrv_postopattr(nd, getret, &at);
1690                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1691         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1692                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1693                 *tl++ = newnfs_false;
1694                 txdr_hyper(dirfor.na_filerev, tl);
1695                 tl += 2;
1696                 txdr_hyper(diraft.na_filerev, tl);
1697         }
1698
1699 out:
1700         NFSEXITCODE2(error, nd);
1701         return (error);
1702 }
1703
1704 /*
1705  * nfs symbolic link service
1706  */
1707 APPLESTATIC int
1708 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1709     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1710     struct nfsexstuff *exp)
1711 {
1712         struct nfsvattr nva, dirfor, diraft;
1713         struct nameidata named;
1714         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1715         vnode_t dirp = NULL;
1716         char *bufp, *pathcp = NULL;
1717         u_long *hashp;
1718
1719         if (nd->nd_repstat) {
1720                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1721                 goto out;
1722         }
1723         if (vpp)
1724                 *vpp = NULL;
1725         NFSVNO_ATTRINIT(&nva);
1726         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1727             LOCKPARENT | SAVESTART | NOCACHE);
1728         nfsvno_setpathbuf(&named, &bufp, &hashp);
1729         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1730         if (!error && !nd->nd_repstat)
1731                 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1732         if (error) {
1733                 vrele(dp);
1734                 nfsvno_relpathbuf(&named);
1735                 goto out;
1736         }
1737         if (!nd->nd_repstat) {
1738                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1739         } else {
1740                 vrele(dp);
1741                 nfsvno_relpathbuf(&named);
1742         }
1743         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1744                 vrele(dirp);
1745                 dirp = NULL;
1746         }
1747
1748         /*
1749          * And call nfsrvd_symlinksub() to do the common code. It will
1750          * return EBADRPC upon a parsing error, 0 otherwise.
1751          */
1752         if (!nd->nd_repstat) {
1753                 if (dirp != NULL)
1754                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1755                             p, 0);
1756                 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1757                     &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1758                     pathcp, pathlen);
1759         } else if (dirp != NULL) {
1760                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1761                 vrele(dirp);
1762         }
1763         if (pathcp)
1764                 FREE(pathcp, M_TEMP);
1765
1766         if (nd->nd_flag & ND_NFSV3) {
1767                 if (!nd->nd_repstat) {
1768                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1769                         nfsrv_postopattr(nd, 0, &nva);
1770                 }
1771                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1772         }
1773
1774 out:
1775         NFSEXITCODE2(error, nd);
1776         return (error);
1777 }
1778
1779 /*
1780  * Common code for creating a symbolic link.
1781  */
1782 static void
1783 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1784     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1785     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1786     int *diraft_retp, nfsattrbit_t *attrbitp,
1787     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1788     int pathlen)
1789 {
1790         u_int32_t *tl;
1791
1792         nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1793             !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1794         if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1795                 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1796                 if (nd->nd_flag & ND_NFSV3) {
1797                         nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1798                         if (!nd->nd_repstat)
1799                                 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1800                                     nvap, nd->nd_cred, p, 1);
1801                 }
1802                 if (vpp != NULL && nd->nd_repstat == 0) {
1803                         NFSVOPUNLOCK(ndp->ni_vp, 0);
1804                         *vpp = ndp->ni_vp;
1805                 } else
1806                         vput(ndp->ni_vp);
1807         }
1808         if (dirp) {
1809                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1810                 vrele(dirp);
1811         }
1812         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1813                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1814                 *tl++ = newnfs_false;
1815                 txdr_hyper(dirforp->na_filerev, tl);
1816                 tl += 2;
1817                 txdr_hyper(diraftp->na_filerev, tl);
1818                 (void) nfsrv_putattrbit(nd, attrbitp);
1819         }
1820
1821         NFSEXITCODE2(0, nd);
1822 }
1823
1824 /*
1825  * nfs mkdir service
1826  */
1827 APPLESTATIC int
1828 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1829     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1830     struct nfsexstuff *exp)
1831 {
1832         struct nfsvattr nva, dirfor, diraft;
1833         struct nameidata named;
1834         u_int32_t *tl;
1835         int error = 0, dirfor_ret = 1, diraft_ret = 1;
1836         vnode_t dirp = NULL;
1837         char *bufp;
1838         u_long *hashp;
1839
1840         if (nd->nd_repstat) {
1841                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1842                 goto out;
1843         }
1844         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1845             LOCKPARENT | SAVENAME | NOCACHE);
1846         nfsvno_setpathbuf(&named, &bufp, &hashp);
1847         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1848         if (error)
1849                 goto nfsmout;
1850         if (!nd->nd_repstat) {
1851                 NFSVNO_ATTRINIT(&nva);
1852                 if (nd->nd_flag & ND_NFSV3) {
1853                         error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1854                         if (error)
1855                                 goto nfsmout;
1856                 } else {
1857                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1858                         nva.na_mode = nfstov_mode(*tl++);
1859                 }
1860         }
1861         if (!nd->nd_repstat) {
1862                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1863         } else {
1864                 vrele(dp);
1865                 nfsvno_relpathbuf(&named);
1866         }
1867         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1868                 vrele(dirp);
1869                 dirp = NULL;
1870         }
1871         if (nd->nd_repstat) {
1872                 if (dirp != NULL) {
1873                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1874                             p, 0);
1875                         vrele(dirp);
1876                 }
1877                 if (nd->nd_flag & ND_NFSV3)
1878                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1879                             &diraft);
1880                 goto out;
1881         }
1882         if (dirp != NULL)
1883                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1884
1885         /*
1886          * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1887          */
1888         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1889             &diraft_ret, NULL, NULL, p, exp);
1890
1891         if (nd->nd_flag & ND_NFSV3) {
1892                 if (!nd->nd_repstat) {
1893                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1894                         nfsrv_postopattr(nd, 0, &nva);
1895                 }
1896                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1897         } else if (!nd->nd_repstat) {
1898                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1899                 nfsrv_fillattr(nd, &nva);
1900         }
1901
1902 out:
1903         NFSEXITCODE2(0, nd);
1904         return (0);
1905 nfsmout:
1906         vrele(dp);
1907         nfsvno_relpathbuf(&named);
1908         NFSEXITCODE2(error, nd);
1909         return (error);
1910 }
1911
1912 /*
1913  * Code common to mkdir for V2,3 and 4.
1914  */
1915 static void
1916 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1917     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1918     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1919     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1920     NFSPROC_T *p, struct nfsexstuff *exp)
1921 {
1922         vnode_t vp;
1923         u_int32_t *tl;
1924
1925         NFSVNO_SETATTRVAL(nvap, type, VDIR);
1926         nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1927             nd->nd_cred, p, exp);
1928         if (!nd->nd_repstat) {
1929                 vp = ndp->ni_vp;
1930                 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1931                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1932                 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1933                         nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1934                             p, 1);
1935                 if (vpp && !nd->nd_repstat) {
1936                         NFSVOPUNLOCK(vp, 0);
1937                         *vpp = vp;
1938                 } else {
1939                         vput(vp);
1940                 }
1941         }
1942         if (dirp) {
1943                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1944                 vrele(dirp);
1945         }
1946         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1947                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1948                 *tl++ = newnfs_false;
1949                 txdr_hyper(dirforp->na_filerev, tl);
1950                 tl += 2;
1951                 txdr_hyper(diraftp->na_filerev, tl);
1952                 (void) nfsrv_putattrbit(nd, attrbitp);
1953         }
1954
1955         NFSEXITCODE2(0, nd);
1956 }
1957
1958 /*
1959  * nfs commit service
1960  */
1961 APPLESTATIC int
1962 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1963     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1964 {
1965         struct nfsvattr bfor, aft;
1966         u_int32_t *tl;
1967         int error = 0, for_ret = 1, aft_ret = 1, cnt;
1968         u_int64_t off;
1969
1970         if (nd->nd_repstat) {
1971                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1972                 goto out;
1973         }
1974         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1975         /*
1976          * XXX At this time VOP_FSYNC() does not accept offset and byte
1977          * count parameters, so these arguments are useless (someday maybe).
1978          */
1979         off = fxdr_hyper(tl);
1980         tl += 2;
1981         cnt = fxdr_unsigned(int, *tl);
1982         if (nd->nd_flag & ND_NFSV3)
1983                 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1984         nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1985         if (nd->nd_flag & ND_NFSV3) {
1986                 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1987                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1988         }
1989         vput(vp);
1990         if (!nd->nd_repstat) {
1991                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1992                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1993                 *tl = txdr_unsigned(nfsboottime.tv_usec);
1994         }
1995
1996 out:
1997         NFSEXITCODE2(0, nd);
1998         return (0);
1999 nfsmout:
2000         vput(vp);
2001         NFSEXITCODE2(error, nd);
2002         return (error);
2003 }
2004
2005 /*
2006  * nfs statfs service
2007  */
2008 APPLESTATIC int
2009 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2010     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2011 {
2012         struct statfs *sf;
2013         u_int32_t *tl;
2014         int getret = 1;
2015         struct nfsvattr at;
2016         struct statfs sfs;
2017         u_quad_t tval;
2018
2019         if (nd->nd_repstat) {
2020                 nfsrv_postopattr(nd, getret, &at);
2021                 goto out;
2022         }
2023         sf = &sfs;
2024         nd->nd_repstat = nfsvno_statfs(vp, sf);
2025         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2026         vput(vp);
2027         if (nd->nd_flag & ND_NFSV3)
2028                 nfsrv_postopattr(nd, getret, &at);
2029         if (nd->nd_repstat)
2030                 goto out;
2031         if (nd->nd_flag & ND_NFSV2) {
2032                 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2033                 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2034                 *tl++ = txdr_unsigned(sf->f_bsize);
2035                 *tl++ = txdr_unsigned(sf->f_blocks);
2036                 *tl++ = txdr_unsigned(sf->f_bfree);
2037                 *tl = txdr_unsigned(sf->f_bavail);
2038         } else {
2039                 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2040                 tval = (u_quad_t)sf->f_blocks;
2041                 tval *= (u_quad_t)sf->f_bsize;
2042                 txdr_hyper(tval, tl); tl += 2;
2043                 tval = (u_quad_t)sf->f_bfree;
2044                 tval *= (u_quad_t)sf->f_bsize;
2045                 txdr_hyper(tval, tl); tl += 2;
2046                 tval = (u_quad_t)sf->f_bavail;
2047                 tval *= (u_quad_t)sf->f_bsize;
2048                 txdr_hyper(tval, tl); tl += 2;
2049                 tval = (u_quad_t)sf->f_files;
2050                 txdr_hyper(tval, tl); tl += 2;
2051                 tval = (u_quad_t)sf->f_ffree;
2052                 txdr_hyper(tval, tl); tl += 2;
2053                 tval = (u_quad_t)sf->f_ffree;
2054                 txdr_hyper(tval, tl); tl += 2;
2055                 *tl = 0;
2056         }
2057
2058 out:
2059         NFSEXITCODE2(0, nd);
2060         return (0);
2061 }
2062
2063 /*
2064  * nfs fsinfo service
2065  */
2066 APPLESTATIC int
2067 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2068     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2069 {
2070         u_int32_t *tl;
2071         struct nfsfsinfo fs;
2072         int getret = 1;
2073         struct nfsvattr at;
2074
2075         if (nd->nd_repstat) {
2076                 nfsrv_postopattr(nd, getret, &at);
2077                 goto out;
2078         }
2079         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2080         nfsvno_getfs(&fs, isdgram);
2081         vput(vp);
2082         nfsrv_postopattr(nd, getret, &at);
2083         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2084         *tl++ = txdr_unsigned(fs.fs_rtmax);
2085         *tl++ = txdr_unsigned(fs.fs_rtpref);
2086         *tl++ = txdr_unsigned(fs.fs_rtmult);
2087         *tl++ = txdr_unsigned(fs.fs_wtmax);
2088         *tl++ = txdr_unsigned(fs.fs_wtpref);
2089         *tl++ = txdr_unsigned(fs.fs_wtmult);
2090         *tl++ = txdr_unsigned(fs.fs_dtpref);
2091         txdr_hyper(fs.fs_maxfilesize, tl);
2092         tl += 2;
2093         txdr_nfsv3time(&fs.fs_timedelta, tl);
2094         tl += 2;
2095         *tl = txdr_unsigned(fs.fs_properties);
2096
2097 out:
2098         NFSEXITCODE2(0, nd);
2099         return (0);
2100 }
2101
2102 /*
2103  * nfs pathconf service
2104  */
2105 APPLESTATIC int
2106 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2107     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2108 {
2109         struct nfsv3_pathconf *pc;
2110         int getret = 1;
2111         register_t linkmax, namemax, chownres, notrunc;
2112         struct nfsvattr at;
2113
2114         if (nd->nd_repstat) {
2115                 nfsrv_postopattr(nd, getret, &at);
2116                 goto out;
2117         }
2118         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2119             nd->nd_cred, p);
2120         if (!nd->nd_repstat)
2121                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2122                     nd->nd_cred, p);
2123         if (!nd->nd_repstat)
2124                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2125                     &chownres, nd->nd_cred, p);
2126         if (!nd->nd_repstat)
2127                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2128                     nd->nd_cred, p);
2129         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2130         vput(vp);
2131         nfsrv_postopattr(nd, getret, &at);
2132         if (!nd->nd_repstat) {
2133                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2134                 pc->pc_linkmax = txdr_unsigned(linkmax);
2135                 pc->pc_namemax = txdr_unsigned(namemax);
2136                 pc->pc_notrunc = txdr_unsigned(notrunc);
2137                 pc->pc_chownrestricted = txdr_unsigned(chownres);
2138
2139                 /*
2140                  * These should probably be supported by VOP_PATHCONF(), but
2141                  * until msdosfs is exportable (why would you want to?), the
2142                  * Unix defaults should be ok.
2143                  */
2144                 pc->pc_caseinsensitive = newnfs_false;
2145                 pc->pc_casepreserving = newnfs_true;
2146         }
2147
2148 out:
2149         NFSEXITCODE2(0, nd);
2150         return (0);
2151 }
2152
2153 /*
2154  * nfsv4 lock service
2155  */
2156 APPLESTATIC int
2157 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2158     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2159 {
2160         u_int32_t *tl;
2161         int i;
2162         struct nfsstate *stp = NULL;
2163         struct nfslock *lop;
2164         struct nfslockconflict cf;
2165         int error = 0;
2166         u_short flags = NFSLCK_LOCK, lflags;
2167         u_int64_t offset, len;
2168         nfsv4stateid_t stateid;
2169         nfsquad_t clientid;
2170
2171         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2172         i = fxdr_unsigned(int, *tl++);
2173         switch (i) {
2174         case NFSV4LOCKT_READW:
2175                 flags |= NFSLCK_BLOCKING;
2176         case NFSV4LOCKT_READ:
2177                 lflags = NFSLCK_READ;
2178                 break;
2179         case NFSV4LOCKT_WRITEW:
2180                 flags |= NFSLCK_BLOCKING;
2181         case NFSV4LOCKT_WRITE:
2182                 lflags = NFSLCK_WRITE;
2183                 break;
2184         default:
2185                 nd->nd_repstat = NFSERR_BADXDR;
2186                 goto nfsmout;
2187         };
2188         if (*tl++ == newnfs_true)
2189                 flags |= NFSLCK_RECLAIM;
2190         offset = fxdr_hyper(tl);
2191         tl += 2;
2192         len = fxdr_hyper(tl);
2193         tl += 2;
2194         if (*tl == newnfs_true)
2195                 flags |= NFSLCK_OPENTOLOCK;
2196         if (flags & NFSLCK_OPENTOLOCK) {
2197                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2198                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2199                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2200                         nd->nd_repstat = NFSERR_BADXDR;
2201                         goto nfsmout;
2202                 }
2203                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2204                         M_NFSDSTATE, M_WAITOK);
2205                 stp->ls_ownerlen = i;
2206                 stp->ls_op = nd->nd_rp;
2207                 stp->ls_seq = fxdr_unsigned(int, *tl++);
2208                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2209                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2210                         NFSX_STATEIDOTHER);
2211                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2212                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2213                 clientid.lval[0] = *tl++;
2214                 clientid.lval[1] = *tl++;
2215                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2216                         if ((nd->nd_flag & ND_NFSV41) != 0)
2217                                 clientid.qval = nd->nd_clientid.qval;
2218                         else if (nd->nd_clientid.qval != clientid.qval)
2219                                 printf("EEK3 multiple clids\n");
2220                 } else {
2221                         if ((nd->nd_flag & ND_NFSV41) != 0)
2222                                 printf("EEK! no clientid from session\n");
2223                         nd->nd_flag |= ND_IMPLIEDCLID;
2224                         nd->nd_clientid.qval = clientid.qval;
2225                 }
2226                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2227                 if (error)
2228                         goto nfsmout;
2229         } else {
2230                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2231                 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2232                         M_NFSDSTATE, M_WAITOK);
2233                 stp->ls_ownerlen = 0;
2234                 stp->ls_op = nd->nd_rp;
2235                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2236                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2237                         NFSX_STATEIDOTHER);
2238                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2239                 stp->ls_seq = fxdr_unsigned(int, *tl);
2240                 clientid.lval[0] = stp->ls_stateid.other[0];
2241                 clientid.lval[1] = stp->ls_stateid.other[1];
2242                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2243                         if ((nd->nd_flag & ND_NFSV41) != 0)
2244                                 clientid.qval = nd->nd_clientid.qval;
2245                         else if (nd->nd_clientid.qval != clientid.qval)
2246                                 printf("EEK4 multiple clids\n");
2247                 } else {
2248                         if ((nd->nd_flag & ND_NFSV41) != 0)
2249                                 printf("EEK! no clientid from session\n");
2250                         nd->nd_flag |= ND_IMPLIEDCLID;
2251                         nd->nd_clientid.qval = clientid.qval;
2252                 }
2253         }
2254         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2255                 M_NFSDLOCK, M_WAITOK);
2256         lop->lo_first = offset;
2257         if (len == NFS64BITSSET) {
2258                 lop->lo_end = NFS64BITSSET;
2259         } else {
2260                 lop->lo_end = offset + len;
2261                 if (lop->lo_end <= lop->lo_first)
2262                         nd->nd_repstat = NFSERR_INVAL;
2263         }
2264         lop->lo_flags = lflags;
2265         stp->ls_flags = flags;
2266         stp->ls_uid = nd->nd_cred->cr_uid;
2267
2268         /*
2269          * Do basic access checking.
2270          */
2271         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2272             if (vnode_vtype(vp) == VDIR)
2273                 nd->nd_repstat = NFSERR_ISDIR;
2274             else
2275                 nd->nd_repstat = NFSERR_INVAL;
2276         }
2277         if (!nd->nd_repstat) {
2278             if (lflags & NFSLCK_WRITE) {
2279                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2280                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2281                     NFSACCCHK_VPISLOCKED, NULL);
2282             } else {
2283                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2284                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2285                     NFSACCCHK_VPISLOCKED, NULL);
2286                 if (nd->nd_repstat)
2287                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2288                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2289                         NFSACCCHK_VPISLOCKED, NULL);
2290             }
2291         }
2292
2293         /*
2294          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2295          * seqid# gets updated. nfsrv_lockctrl() will return the value
2296          * of nd_repstat, if it gets that far.
2297          */
2298         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
2299                 &stateid, exp, nd, p);
2300         if (lop)
2301                 FREE((caddr_t)lop, M_NFSDLOCK);
2302         if (stp)
2303                 FREE((caddr_t)stp, M_NFSDSTATE);
2304         if (!nd->nd_repstat) {
2305                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2306                 *tl++ = txdr_unsigned(stateid.seqid);
2307                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2308         } else if (nd->nd_repstat == NFSERR_DENIED) {
2309                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2310                 txdr_hyper(cf.cl_first, tl);
2311                 tl += 2;
2312                 if (cf.cl_end == NFS64BITSSET)
2313                         len = NFS64BITSSET;
2314                 else
2315                         len = cf.cl_end - cf.cl_first;
2316                 txdr_hyper(len, tl);
2317                 tl += 2;
2318                 if (cf.cl_flags == NFSLCK_WRITE)
2319                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2320                 else
2321                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2322                 *tl++ = stateid.other[0];
2323                 *tl = stateid.other[1];
2324                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2325         }
2326         vput(vp);
2327         NFSEXITCODE2(0, nd);
2328         return (0);
2329 nfsmout:
2330         vput(vp);
2331         if (stp)
2332                 free((caddr_t)stp, M_NFSDSTATE);
2333         NFSEXITCODE2(error, nd);
2334         return (error);
2335 }
2336
2337 /*
2338  * nfsv4 lock test service
2339  */
2340 APPLESTATIC int
2341 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2342     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2343 {
2344         u_int32_t *tl;
2345         int i;
2346         struct nfsstate *stp = NULL;
2347         struct nfslock lo, *lop = &lo;
2348         struct nfslockconflict cf;
2349         int error = 0;
2350         nfsv4stateid_t stateid;
2351         nfsquad_t clientid;
2352         u_int64_t len;
2353
2354         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2355         i = fxdr_unsigned(int, *(tl + 7));
2356         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2357                 nd->nd_repstat = NFSERR_BADXDR;
2358                 goto nfsmout;
2359         }
2360         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2361             M_NFSDSTATE, M_WAITOK);
2362         stp->ls_ownerlen = i;
2363         stp->ls_op = NULL;
2364         stp->ls_flags = NFSLCK_TEST;
2365         stp->ls_uid = nd->nd_cred->cr_uid;
2366         i = fxdr_unsigned(int, *tl++);
2367         switch (i) {
2368         case NFSV4LOCKT_READW:
2369                 stp->ls_flags |= NFSLCK_BLOCKING;
2370         case NFSV4LOCKT_READ:
2371                 lo.lo_flags = NFSLCK_READ;
2372                 break;
2373         case NFSV4LOCKT_WRITEW:
2374                 stp->ls_flags |= NFSLCK_BLOCKING;
2375         case NFSV4LOCKT_WRITE:
2376                 lo.lo_flags = NFSLCK_WRITE;
2377                 break;
2378         default:
2379                 nd->nd_repstat = NFSERR_BADXDR;
2380                 goto nfsmout;
2381         };
2382         lo.lo_first = fxdr_hyper(tl);
2383         tl += 2;
2384         len = fxdr_hyper(tl);
2385         if (len == NFS64BITSSET) {
2386                 lo.lo_end = NFS64BITSSET;
2387         } else {
2388                 lo.lo_end = lo.lo_first + len;
2389                 if (lo.lo_end <= lo.lo_first)
2390                         nd->nd_repstat = NFSERR_INVAL;
2391         }
2392         tl += 2;
2393         clientid.lval[0] = *tl++;
2394         clientid.lval[1] = *tl;
2395         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2396                 if ((nd->nd_flag & ND_NFSV41) != 0)
2397                         clientid.qval = nd->nd_clientid.qval;
2398                 else if (nd->nd_clientid.qval != clientid.qval)
2399                         printf("EEK5 multiple clids\n");
2400         } else {
2401                 if ((nd->nd_flag & ND_NFSV41) != 0)
2402                         printf("EEK! no clientid from session\n");
2403                 nd->nd_flag |= ND_IMPLIEDCLID;
2404                 nd->nd_clientid.qval = clientid.qval;
2405         }
2406         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2407         if (error)
2408                 goto nfsmout;
2409         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2410             if (vnode_vtype(vp) == VDIR)
2411                 nd->nd_repstat = NFSERR_ISDIR;
2412             else
2413                 nd->nd_repstat = NFSERR_INVAL;
2414         }
2415         if (!nd->nd_repstat)
2416           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2417             &stateid, exp, nd, p);
2418         if (stp)
2419                 FREE((caddr_t)stp, M_NFSDSTATE);
2420         if (nd->nd_repstat) {
2421             if (nd->nd_repstat == NFSERR_DENIED) {
2422                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2423                 txdr_hyper(cf.cl_first, tl);
2424                 tl += 2;
2425                 if (cf.cl_end == NFS64BITSSET)
2426                         len = NFS64BITSSET;
2427                 else
2428                         len = cf.cl_end - cf.cl_first;
2429                 txdr_hyper(len, tl);
2430                 tl += 2;
2431                 if (cf.cl_flags == NFSLCK_WRITE)
2432                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2433                 else
2434                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2435                 *tl++ = stp->ls_stateid.other[0];
2436                 *tl = stp->ls_stateid.other[1];
2437                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2438             }
2439         }
2440         vput(vp);
2441         NFSEXITCODE2(0, nd);
2442         return (0);
2443 nfsmout:
2444         vput(vp);
2445         if (stp)
2446                 free((caddr_t)stp, M_NFSDSTATE);
2447         NFSEXITCODE2(error, nd);
2448         return (error);
2449 }
2450
2451 /*
2452  * nfsv4 unlock service
2453  */
2454 APPLESTATIC int
2455 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2456     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2457 {
2458         u_int32_t *tl;
2459         int i;
2460         struct nfsstate *stp;
2461         struct nfslock *lop;
2462         int error = 0;
2463         nfsv4stateid_t stateid;
2464         nfsquad_t clientid;
2465         u_int64_t len;
2466
2467         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2468         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2469             M_NFSDSTATE, M_WAITOK);
2470         MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2471             M_NFSDLOCK, M_WAITOK);
2472         stp->ls_flags = NFSLCK_UNLOCK;
2473         lop->lo_flags = NFSLCK_UNLOCK;
2474         stp->ls_op = nd->nd_rp;
2475         i = fxdr_unsigned(int, *tl++);
2476         switch (i) {
2477         case NFSV4LOCKT_READW:
2478                 stp->ls_flags |= NFSLCK_BLOCKING;
2479         case NFSV4LOCKT_READ:
2480                 break;
2481         case NFSV4LOCKT_WRITEW:
2482                 stp->ls_flags |= NFSLCK_BLOCKING;
2483         case NFSV4LOCKT_WRITE:
2484                 break;
2485         default:
2486                 nd->nd_repstat = NFSERR_BADXDR;
2487                 free(stp, M_NFSDSTATE);
2488                 free(lop, M_NFSDLOCK);
2489                 goto nfsmout;
2490         };
2491         stp->ls_ownerlen = 0;
2492         stp->ls_uid = nd->nd_cred->cr_uid;
2493         stp->ls_seq = fxdr_unsigned(int, *tl++);
2494         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2495         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2496             NFSX_STATEIDOTHER);
2497         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2498         lop->lo_first = fxdr_hyper(tl);
2499         tl += 2;
2500         len = fxdr_hyper(tl);
2501         if (len == NFS64BITSSET) {
2502                 lop->lo_end = NFS64BITSSET;
2503         } else {
2504                 lop->lo_end = lop->lo_first + len;
2505                 if (lop->lo_end <= lop->lo_first)
2506                         nd->nd_repstat = NFSERR_INVAL;
2507         }
2508         clientid.lval[0] = stp->ls_stateid.other[0];
2509         clientid.lval[1] = stp->ls_stateid.other[1];
2510         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2511                 if ((nd->nd_flag & ND_NFSV41) != 0)
2512                         clientid.qval = nd->nd_clientid.qval;
2513                 else if (nd->nd_clientid.qval != clientid.qval)
2514                         printf("EEK6 multiple clids\n");
2515         } else {
2516                 if ((nd->nd_flag & ND_NFSV41) != 0)
2517                         printf("EEK! no clientid from session\n");
2518                 nd->nd_flag |= ND_IMPLIEDCLID;
2519                 nd->nd_clientid.qval = clientid.qval;
2520         }
2521         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2522             if (vnode_vtype(vp) == VDIR)
2523                 nd->nd_repstat = NFSERR_ISDIR;
2524             else
2525                 nd->nd_repstat = NFSERR_INVAL;
2526         }
2527         /*
2528          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2529          * seqid# gets incremented. nfsrv_lockctrl() will return the
2530          * value of nd_repstat, if it gets that far.
2531          */
2532         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2533             &stateid, exp, nd, p);
2534         if (stp)
2535                 FREE((caddr_t)stp, M_NFSDSTATE);
2536         if (lop)
2537                 free((caddr_t)lop, M_NFSDLOCK);
2538         if (!nd->nd_repstat) {
2539                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2540                 *tl++ = txdr_unsigned(stateid.seqid);
2541                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2542         }
2543 nfsmout:
2544         vput(vp);
2545         NFSEXITCODE2(error, nd);
2546         return (error);
2547 }
2548
2549 /*
2550  * nfsv4 open service
2551  */
2552 APPLESTATIC int
2553 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2554     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2555     struct nfsexstuff *exp)
2556 {
2557         u_int32_t *tl;
2558         int i, retext;
2559         struct nfsstate *stp = NULL;
2560         int error = 0, create, claim, exclusive_flag = 0;
2561         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2562         int how = NFSCREATE_UNCHECKED;
2563         int32_t cverf[2], tverf[2] = { 0, 0 };
2564         vnode_t vp = NULL, dirp = NULL;
2565         struct nfsvattr nva, dirfor, diraft;
2566         struct nameidata named;
2567         nfsv4stateid_t stateid, delegstateid;
2568         nfsattrbit_t attrbits;
2569         nfsquad_t clientid;
2570         char *bufp = NULL;
2571         u_long *hashp;
2572         NFSACL_T *aclp = NULL;
2573
2574 #ifdef NFS4_ACL_EXTATTR_NAME
2575         aclp = acl_alloc(M_WAITOK);
2576         aclp->acl_cnt = 0;
2577 #endif
2578         NFSZERO_ATTRBIT(&attrbits);
2579         named.ni_startdir = NULL;
2580         named.ni_cnd.cn_nameiop = 0;
2581         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2582         i = fxdr_unsigned(int, *(tl + 5));
2583         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2584                 nd->nd_repstat = NFSERR_BADXDR;
2585                 goto nfsmout;
2586         }
2587         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2588             M_NFSDSTATE, M_WAITOK);
2589         stp->ls_ownerlen = i;
2590         stp->ls_op = nd->nd_rp;
2591         stp->ls_flags = NFSLCK_OPEN;
2592         stp->ls_uid = nd->nd_cred->cr_uid;
2593         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2594         i = fxdr_unsigned(int, *tl++);
2595         retext = 0;
2596         if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2597             NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2598                 retext = 1;
2599                 /* For now, ignore these. */
2600                 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2601                 switch (i & NFSV4OPEN_WANTDELEGMASK) {
2602                 case NFSV4OPEN_WANTANYDELEG:
2603                         stp->ls_flags |= (NFSLCK_WANTRDELEG |
2604                             NFSLCK_WANTWDELEG);
2605                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2606                         break;
2607                 case NFSV4OPEN_WANTREADDELEG:
2608                         stp->ls_flags |= NFSLCK_WANTRDELEG;
2609                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2610                         break;
2611                 case NFSV4OPEN_WANTWRITEDELEG:
2612                         stp->ls_flags |= NFSLCK_WANTWDELEG;
2613                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2614                         break;
2615                 case NFSV4OPEN_WANTNODELEG:
2616                         stp->ls_flags |= NFSLCK_WANTNODELEG;
2617                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2618                         break;
2619                 case NFSV4OPEN_WANTCANCEL:
2620                         printf("NFSv4: ignore Open WantCancel\n");
2621                         i &= ~NFSV4OPEN_WANTDELEGMASK;
2622                         break;
2623                 default:
2624                         /* nd_repstat will be set to NFSERR_INVAL below. */
2625                         break;
2626                 };
2627         }
2628         switch (i) {
2629         case NFSV4OPEN_ACCESSREAD:
2630                 stp->ls_flags |= NFSLCK_READACCESS;
2631                 break;
2632         case NFSV4OPEN_ACCESSWRITE:
2633                 stp->ls_flags |= NFSLCK_WRITEACCESS;
2634                 break;
2635         case NFSV4OPEN_ACCESSBOTH:
2636                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2637                 break;
2638         default:
2639                 nd->nd_repstat = NFSERR_INVAL;
2640         };
2641         i = fxdr_unsigned(int, *tl++);
2642         switch (i) {
2643         case NFSV4OPEN_DENYNONE:
2644                 break;
2645         case NFSV4OPEN_DENYREAD:
2646                 stp->ls_flags |= NFSLCK_READDENY;
2647                 break;
2648         case NFSV4OPEN_DENYWRITE:
2649                 stp->ls_flags |= NFSLCK_WRITEDENY;
2650                 break;
2651         case NFSV4OPEN_DENYBOTH:
2652                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2653                 break;
2654         default:
2655                 nd->nd_repstat = NFSERR_INVAL;
2656         };
2657         clientid.lval[0] = *tl++;
2658         clientid.lval[1] = *tl;
2659         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2660                 if ((nd->nd_flag & ND_NFSV41) != 0)
2661                         clientid.qval = nd->nd_clientid.qval;
2662                 else if (nd->nd_clientid.qval != clientid.qval)
2663                         printf("EEK7 multiple clids\n");
2664         } else {
2665                 if ((nd->nd_flag & ND_NFSV41) != 0)
2666                         printf("EEK! no clientid from session\n");
2667                 nd->nd_flag |= ND_IMPLIEDCLID;
2668                 nd->nd_clientid.qval = clientid.qval;
2669         }
2670         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2671         if (error)
2672                 goto nfsmout;
2673         NFSVNO_ATTRINIT(&nva);
2674         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2675         create = fxdr_unsigned(int, *tl);
2676         if (!nd->nd_repstat)
2677                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2678         if (create == NFSV4OPEN_CREATE) {
2679                 nva.na_type = VREG;
2680                 nva.na_mode = 0;
2681                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2682                 how = fxdr_unsigned(int, *tl);
2683                 switch (how) {
2684                 case NFSCREATE_UNCHECKED:
2685                 case NFSCREATE_GUARDED:
2686                         error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2687                         if (error)
2688                                 goto nfsmout;
2689                         /*
2690                          * If the na_gid being set is the same as that of
2691                          * the directory it is going in, clear it, since
2692                          * that is what will be set by default. This allows
2693                          * a user that isn't in that group to do the create.
2694                          */
2695                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2696                             nva.na_gid == dirfor.na_gid)
2697                                 NFSVNO_UNSET(&nva, gid);
2698                         if (!nd->nd_repstat)
2699                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2700                         break;
2701                 case NFSCREATE_EXCLUSIVE:
2702                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2703                         cverf[0] = *tl++;
2704                         cverf[1] = *tl;
2705                         break;
2706                 case NFSCREATE_EXCLUSIVE41:
2707                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2708                         cverf[0] = *tl++;
2709                         cverf[1] = *tl;
2710                         error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2711                         if (error != 0)
2712                                 goto nfsmout;
2713                         if (NFSISSET_ATTRBIT(&attrbits,
2714                             NFSATTRBIT_TIMEACCESSSET))
2715                                 nd->nd_repstat = NFSERR_INVAL;
2716                         /*
2717                          * If the na_gid being set is the same as that of
2718                          * the directory it is going in, clear it, since
2719                          * that is what will be set by default. This allows
2720                          * a user that isn't in that group to do the create.
2721                          */
2722                         if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2723                             nva.na_gid == dirfor.na_gid)
2724                                 NFSVNO_UNSET(&nva, gid);
2725                         if (nd->nd_repstat == 0)
2726                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2727                         break;
2728                 default:
2729                         nd->nd_repstat = NFSERR_BADXDR;
2730                         goto nfsmout;
2731                 };
2732         } else if (create != NFSV4OPEN_NOCREATE) {
2733                 nd->nd_repstat = NFSERR_BADXDR;
2734                 goto nfsmout;
2735         }
2736
2737         /*
2738          * Now, handle the claim, which usually includes looking up a
2739          * name in the directory referenced by dp. The exception is
2740          * NFSV4OPEN_CLAIMPREVIOUS.
2741          */
2742         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2743         claim = fxdr_unsigned(int, *tl);
2744         if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2745                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2746                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2747                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2748                 stp->ls_flags |= NFSLCK_DELEGCUR;
2749         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2750                 stp->ls_flags |= NFSLCK_DELEGPREV;
2751         }
2752         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2753             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2754                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2755                     claim != NFSV4OPEN_CLAIMNULL)
2756                         nd->nd_repstat = NFSERR_INVAL;
2757                 if (nd->nd_repstat) {
2758                         nd->nd_repstat = nfsrv_opencheck(clientid,
2759                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
2760                         goto nfsmout;
2761                 }
2762                 if (create == NFSV4OPEN_CREATE)
2763                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2764                         LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
2765                 else
2766                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2767                         LOCKLEAF | SAVESTART);
2768                 nfsvno_setpathbuf(&named, &bufp, &hashp);
2769                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2770                 if (error) {
2771                         vrele(dp);
2772 #ifdef NFS4_ACL_EXTATTR_NAME
2773                         acl_free(aclp);
2774 #endif
2775                         FREE((caddr_t)stp, M_NFSDSTATE);
2776                         nfsvno_relpathbuf(&named);
2777                         NFSEXITCODE2(error, nd);
2778                         return (error);
2779                 }
2780                 if (!nd->nd_repstat) {
2781                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2782                             p, &dirp);
2783                 } else {
2784                         vrele(dp);
2785                         nfsvno_relpathbuf(&named);
2786                 }
2787                 if (create == NFSV4OPEN_CREATE) {
2788                     switch (how) {
2789                     case NFSCREATE_UNCHECKED:
2790                         if (named.ni_vp) {
2791                                 /*
2792                                  * Clear the setable attribute bits, except
2793                                  * for Size, if it is being truncated.
2794                                  */
2795                                 NFSZERO_ATTRBIT(&attrbits);
2796                                 if (NFSVNO_ISSETSIZE(&nva))
2797                                         NFSSETBIT_ATTRBIT(&attrbits,
2798                                             NFSATTRBIT_SIZE);
2799                         }
2800                         break;
2801                     case NFSCREATE_GUARDED:
2802                         if (named.ni_vp && !nd->nd_repstat)
2803                                 nd->nd_repstat = EEXIST;
2804                         break;
2805                     case NFSCREATE_EXCLUSIVE:
2806                         exclusive_flag = 1;
2807                         if (!named.ni_vp)
2808                                 nva.na_mode = 0;
2809                         break;
2810                     case NFSCREATE_EXCLUSIVE41:
2811                         exclusive_flag = 1;
2812                         break;
2813                     };
2814                 }
2815                 nfsvno_open(nd, &named, clientid, &stateid, stp,
2816                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2817                     nd->nd_cred, p, exp, &vp);
2818         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2819             NFSV4OPEN_CLAIMFH) {
2820                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2821                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2822                         i = fxdr_unsigned(int, *tl);
2823                         switch (i) {
2824                         case NFSV4OPEN_DELEGATEREAD:
2825                                 stp->ls_flags |= NFSLCK_DELEGREAD;
2826                                 break;
2827                         case NFSV4OPEN_DELEGATEWRITE:
2828                                 stp->ls_flags |= NFSLCK_DELEGWRITE;
2829                         case NFSV4OPEN_DELEGATENONE:
2830                                 break;
2831                         default:
2832                                 nd->nd_repstat = NFSERR_BADXDR;
2833                                 goto nfsmout;
2834                         };
2835                         stp->ls_flags |= NFSLCK_RECLAIM;
2836                 } else {
2837                         /* CLAIM_NULL_FH */
2838                         if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
2839                                 nd->nd_repstat = NFSERR_INVAL;
2840                 }
2841                 vp = dp;
2842                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2843                 if ((vp->v_iflag & VI_DOOMED) == 0)
2844                         nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2845                             stp, vp, nd, p, nd->nd_repstat);
2846                 else
2847                         nd->nd_repstat = NFSERR_PERM;
2848         } else {
2849                 nd->nd_repstat = NFSERR_BADXDR;
2850                 goto nfsmout;
2851         }
2852
2853         /*
2854          * Do basic access checking.
2855          */
2856         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2857                 /*
2858                  * The IETF working group decided that this is the correct
2859                  * error return for all non-regular files.
2860                  */
2861                 nd->nd_repstat = NFSERR_SYMLINK;
2862         }
2863         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2864             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2865                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2866         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2867             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2868                 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2869             if (nd->nd_repstat)
2870                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2871                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2872                     NFSACCCHK_VPISLOCKED, NULL);
2873         }
2874
2875         if (!nd->nd_repstat) {
2876                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2877                 if (!nd->nd_repstat) {
2878                         tverf[0] = nva.na_atime.tv_sec;
2879                         tverf[1] = nva.na_atime.tv_nsec;
2880                 }
2881         }
2882         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2883             cverf[1] != tverf[1]))
2884                 nd->nd_repstat = EEXIST;
2885         /*
2886          * Do the open locking/delegation stuff.
2887          */
2888         if (!nd->nd_repstat)
2889             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2890                 &delegstateid, &rflags, exp, p, nva.na_filerev);
2891
2892         /*
2893          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2894          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2895          * (ie: Leave the NFSVOPUNLOCK() about here.)
2896          */
2897         if (vp)
2898                 NFSVOPUNLOCK(vp, 0);
2899         if (stp)
2900                 FREE((caddr_t)stp, M_NFSDSTATE);
2901         if (!nd->nd_repstat && dirp)
2902                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2903                     0);
2904         if (!nd->nd_repstat) {
2905                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2906                 *tl++ = txdr_unsigned(stateid.seqid);
2907                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2908                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2909                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2910                         *tl++ = newnfs_true;
2911                         *tl++ = 0;
2912                         *tl++ = 0;
2913                         *tl++ = 0;
2914                         *tl++ = 0;
2915                 } else {
2916                         *tl++ = newnfs_false;   /* Since dirp is not locked */
2917                         txdr_hyper(dirfor.na_filerev, tl);
2918                         tl += 2;
2919                         txdr_hyper(diraft.na_filerev, tl);
2920                         tl += 2;
2921                 }
2922                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2923                 (void) nfsrv_putattrbit(nd, &attrbits);
2924                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2925                 if (rflags & NFSV4OPEN_READDELEGATE)
2926                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2927                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2928                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2929                 else if (retext != 0) {
2930                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
2931                         if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
2932                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2933                                 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
2934                                 *tl = newnfs_false;
2935                         } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
2936                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2937                                 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
2938                                 *tl = newnfs_false;
2939                         } else {
2940                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2941                                 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
2942                         }
2943                 } else
2944                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2945                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2946                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2947                         *tl++ = txdr_unsigned(delegstateid.seqid);
2948                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2949                             NFSX_STATEIDOTHER);
2950                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2951                         if (rflags & NFSV4OPEN_RECALL)
2952                                 *tl = newnfs_true;
2953                         else
2954                                 *tl = newnfs_false;
2955                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2956                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2957                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2958                                 txdr_hyper(nva.na_size, tl);
2959                         }
2960                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2961                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2962                         *tl++ = txdr_unsigned(0x0);
2963                         acemask = NFSV4ACE_ALLFILESMASK;
2964                         if (nva.na_mode & S_IRUSR)
2965                             acemask |= NFSV4ACE_READMASK;
2966                         if (nva.na_mode & S_IWUSR)
2967                             acemask |= NFSV4ACE_WRITEMASK;
2968                         if (nva.na_mode & S_IXUSR)
2969                             acemask |= NFSV4ACE_EXECUTEMASK;
2970                         *tl = txdr_unsigned(acemask);
2971                         (void) nfsm_strtom(nd, "OWNER@", 6);
2972                 }
2973                 *vpp = vp;
2974         } else if (vp) {
2975                 vrele(vp);
2976         }
2977         if (dirp)
2978                 vrele(dirp);
2979 #ifdef NFS4_ACL_EXTATTR_NAME
2980         acl_free(aclp);
2981 #endif
2982         NFSEXITCODE2(0, nd);
2983         return (0);
2984 nfsmout:
2985         vrele(dp);
2986 #ifdef NFS4_ACL_EXTATTR_NAME
2987         acl_free(aclp);
2988 #endif
2989         if (stp)
2990                 FREE((caddr_t)stp, M_NFSDSTATE);
2991         NFSEXITCODE2(error, nd);
2992         return (error);
2993 }
2994
2995 /*
2996  * nfsv4 close service
2997  */
2998 APPLESTATIC int
2999 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3000     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3001 {
3002         u_int32_t *tl;
3003         struct nfsstate st, *stp = &st;
3004         int error = 0;
3005         nfsv4stateid_t stateid;
3006         nfsquad_t clientid;
3007
3008         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3009         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3010         stp->ls_ownerlen = 0;
3011         stp->ls_op = nd->nd_rp;
3012         stp->ls_uid = nd->nd_cred->cr_uid;
3013         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3014         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3015             NFSX_STATEIDOTHER);
3016         stp->ls_flags = NFSLCK_CLOSE;
3017         clientid.lval[0] = stp->ls_stateid.other[0];
3018         clientid.lval[1] = stp->ls_stateid.other[1];
3019         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3020                 if ((nd->nd_flag & ND_NFSV41) != 0)
3021                         clientid.qval = nd->nd_clientid.qval;
3022                 else if (nd->nd_clientid.qval != clientid.qval)
3023                         printf("EEK8 multiple clids\n");
3024         } else {
3025                 if ((nd->nd_flag & ND_NFSV41) != 0)
3026                         printf("EEK! no clientid from session\n");
3027                 nd->nd_flag |= ND_IMPLIEDCLID;
3028                 nd->nd_clientid.qval = clientid.qval;
3029         }
3030         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3031         vput(vp);
3032         if (!nd->nd_repstat) {
3033                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3034                 *tl++ = txdr_unsigned(stateid.seqid);
3035                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3036         }
3037         NFSEXITCODE2(0, nd);
3038         return (0);
3039 nfsmout:
3040         vput(vp);
3041         NFSEXITCODE2(error, nd);
3042         return (error);
3043 }
3044
3045 /*
3046  * nfsv4 delegpurge service
3047  */
3048 APPLESTATIC int
3049 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3050     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3051 {
3052         u_int32_t *tl;
3053         int error = 0;
3054         nfsquad_t clientid;
3055
3056         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3057                 nd->nd_repstat = NFSERR_WRONGSEC;
3058                 goto nfsmout;
3059         }
3060         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3061         clientid.lval[0] = *tl++;
3062         clientid.lval[1] = *tl;
3063         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3064                 if ((nd->nd_flag & ND_NFSV41) != 0)
3065                         clientid.qval = nd->nd_clientid.qval;
3066                 else if (nd->nd_clientid.qval != clientid.qval)
3067                         printf("EEK9 multiple clids\n");
3068         } else {
3069                 if ((nd->nd_flag & ND_NFSV41) != 0)
3070                         printf("EEK! no clientid from session\n");
3071                 nd->nd_flag |= ND_IMPLIEDCLID;
3072                 nd->nd_clientid.qval = clientid.qval;
3073         }
3074         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3075             NFSV4OP_DELEGPURGE, nd->nd_cred, p);
3076 nfsmout:
3077         NFSEXITCODE2(error, nd);
3078         return (error);
3079 }
3080
3081 /*
3082  * nfsv4 delegreturn service
3083  */
3084 APPLESTATIC int
3085 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3086     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3087 {
3088         u_int32_t *tl;
3089         int error = 0;
3090         nfsv4stateid_t stateid;
3091         nfsquad_t clientid;
3092
3093         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3094         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3095         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3096         clientid.lval[0] = stateid.other[0];
3097         clientid.lval[1] = stateid.other[1];
3098         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3099                 if ((nd->nd_flag & ND_NFSV41) != 0)
3100                         clientid.qval = nd->nd_clientid.qval;
3101                 else if (nd->nd_clientid.qval != clientid.qval)
3102                         printf("EEK10 multiple clids\n");
3103         } else {
3104                 if ((nd->nd_flag & ND_NFSV41) != 0)
3105                         printf("EEK! no clientid from session\n");
3106                 nd->nd_flag |= ND_IMPLIEDCLID;
3107                 nd->nd_clientid.qval = clientid.qval;
3108         }
3109         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3110             NFSV4OP_DELEGRETURN, nd->nd_cred, p);
3111 nfsmout:
3112         vput(vp);
3113         NFSEXITCODE2(error, nd);
3114         return (error);
3115 }
3116
3117 /*
3118  * nfsv4 get file handle service
3119  */
3120 APPLESTATIC int
3121 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3122     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3123 {
3124         fhandle_t fh;
3125
3126         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3127         vput(vp);
3128         if (!nd->nd_repstat)
3129                 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3130         NFSEXITCODE2(0, nd);
3131         return (0);
3132 }
3133
3134 /*
3135  * nfsv4 open confirm service
3136  */
3137 APPLESTATIC int
3138 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3139     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3140 {
3141         u_int32_t *tl;
3142         struct nfsstate st, *stp = &st;
3143         int error = 0;
3144         nfsv4stateid_t stateid;
3145         nfsquad_t clientid;
3146
3147         if ((nd->nd_flag & ND_NFSV41) != 0) {
3148                 nd->nd_repstat = NFSERR_NOTSUPP;
3149                 goto nfsmout;
3150         }
3151         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3152         stp->ls_ownerlen = 0;
3153         stp->ls_op = nd->nd_rp;
3154         stp->ls_uid = nd->nd_cred->cr_uid;
3155         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3156         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3157             NFSX_STATEIDOTHER);
3158         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3159         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3160         stp->ls_flags = NFSLCK_CONFIRM;
3161         clientid.lval[0] = stp->ls_stateid.other[0];
3162         clientid.lval[1] = stp->ls_stateid.other[1];
3163         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3164                 if ((nd->nd_flag & ND_NFSV41) != 0)
3165                         clientid.qval = nd->nd_clientid.qval;
3166                 else if (nd->nd_clientid.qval != clientid.qval)
3167                         printf("EEK11 multiple clids\n");
3168         } else {
3169                 if ((nd->nd_flag & ND_NFSV41) != 0)
3170                         printf("EEK! no clientid from session\n");
3171                 nd->nd_flag |= ND_IMPLIEDCLID;
3172                 nd->nd_clientid.qval = clientid.qval;
3173         }
3174         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3175         if (!nd->nd_repstat) {
3176                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3177                 *tl++ = txdr_unsigned(stateid.seqid);
3178                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3179         }
3180 nfsmout:
3181         vput(vp);
3182         NFSEXITCODE2(error, nd);
3183         return (error);
3184 }
3185
3186 /*
3187  * nfsv4 open downgrade service
3188  */
3189 APPLESTATIC int
3190 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3191     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3192 {
3193         u_int32_t *tl;
3194         int i;
3195         struct nfsstate st, *stp = &st;
3196         int error = 0;
3197         nfsv4stateid_t stateid;
3198         nfsquad_t clientid;
3199
3200         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3201         stp->ls_ownerlen = 0;
3202         stp->ls_op = nd->nd_rp;
3203         stp->ls_uid = nd->nd_cred->cr_uid;
3204         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3205         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3206             NFSX_STATEIDOTHER);
3207         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3208         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3209         i = fxdr_unsigned(int, *tl++);
3210         switch (i) {
3211         case NFSV4OPEN_ACCESSREAD:
3212                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3213                 break;
3214         case NFSV4OPEN_ACCESSWRITE:
3215                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3216                 break;
3217         case NFSV4OPEN_ACCESSBOTH:
3218                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3219                     NFSLCK_DOWNGRADE);
3220                 break;
3221         default:
3222                 nd->nd_repstat = NFSERR_BADXDR;
3223         };
3224         i = fxdr_unsigned(int, *tl);
3225         switch (i) {
3226         case NFSV4OPEN_DENYNONE:
3227                 break;
3228         case NFSV4OPEN_DENYREAD:
3229                 stp->ls_flags |= NFSLCK_READDENY;
3230                 break;
3231         case NFSV4OPEN_DENYWRITE:
3232                 stp->ls_flags |= NFSLCK_WRITEDENY;
3233                 break;
3234         case NFSV4OPEN_DENYBOTH:
3235                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3236                 break;
3237         default:
3238                 nd->nd_repstat = NFSERR_BADXDR;
3239         };
3240
3241         clientid.lval[0] = stp->ls_stateid.other[0];
3242         clientid.lval[1] = stp->ls_stateid.other[1];
3243         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3244                 if ((nd->nd_flag & ND_NFSV41) != 0)
3245                         clientid.qval = nd->nd_clientid.qval;
3246                 else if (nd->nd_clientid.qval != clientid.qval)
3247                         printf("EEK12 multiple clids\n");
3248         } else {
3249                 if ((nd->nd_flag & ND_NFSV41) != 0)
3250                         printf("EEK! no clientid from session\n");
3251                 nd->nd_flag |= ND_IMPLIEDCLID;
3252                 nd->nd_clientid.qval = clientid.qval;
3253         }
3254         if (!nd->nd_repstat)
3255                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3256                     nd, p);
3257         if (!nd->nd_repstat) {
3258                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3259                 *tl++ = txdr_unsigned(stateid.seqid);
3260                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3261         }
3262 nfsmout:
3263         vput(vp);
3264         NFSEXITCODE2(error, nd);
3265         return (error);
3266 }
3267
3268 /*
3269  * nfsv4 renew lease service
3270  */
3271 APPLESTATIC int
3272 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3273     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3274 {
3275         u_int32_t *tl;
3276         int error = 0;
3277         nfsquad_t clientid;
3278
3279         if ((nd->nd_flag & ND_NFSV41) != 0) {
3280                 nd->nd_repstat = NFSERR_NOTSUPP;
3281                 goto nfsmout;
3282         }
3283         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3284                 nd->nd_repstat = NFSERR_WRONGSEC;
3285                 goto nfsmout;
3286         }
3287         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3288         clientid.lval[0] = *tl++;
3289         clientid.lval[1] = *tl;
3290         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3291                 if ((nd->nd_flag & ND_NFSV41) != 0)
3292                         clientid.qval = nd->nd_clientid.qval;
3293                 else if (nd->nd_clientid.qval != clientid.qval)
3294                         printf("EEK13 multiple clids\n");
3295         } else {
3296                 if ((nd->nd_flag & ND_NFSV41) != 0)
3297                         printf("EEK! no clientid from session\n");
3298                 nd->nd_flag |= ND_IMPLIEDCLID;
3299                 nd->nd_clientid.qval = clientid.qval;
3300         }
3301         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3302             NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3303 nfsmout:
3304         NFSEXITCODE2(error, nd);
3305         return (error);
3306 }
3307
3308 /*
3309  * nfsv4 security info service
3310  */
3311 APPLESTATIC int
3312 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3313     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3314 {
3315         u_int32_t *tl;
3316         int len;
3317         struct nameidata named;
3318         vnode_t dirp = NULL, vp;
3319         struct nfsrvfh fh;
3320         struct nfsexstuff retnes;
3321         u_int32_t *sizp;
3322         int error = 0, savflag, i;
3323         char *bufp;
3324         u_long *hashp;
3325
3326         /*
3327          * All this just to get the export flags for the name.
3328          */
3329         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3330             LOCKLEAF | SAVESTART);
3331         nfsvno_setpathbuf(&named, &bufp, &hashp);
3332         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3333         if (error) {
3334                 vput(dp);
3335                 nfsvno_relpathbuf(&named);
3336                 goto out;
3337         }
3338         if (!nd->nd_repstat) {
3339                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3340         } else {
3341                 vput(dp);
3342                 nfsvno_relpathbuf(&named);
3343         }
3344         if (dirp)
3345                 vrele(dirp);
3346         if (nd->nd_repstat)
3347                 goto out;
3348         vrele(named.ni_startdir);
3349         nfsvno_relpathbuf(&named);
3350         fh.nfsrvfh_len = NFSX_MYFH;
3351         vp = named.ni_vp;
3352         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3353         vput(vp);
3354         savflag = nd->nd_flag;
3355         if (!nd->nd_repstat) {
3356                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3357                 if (vp)
3358                         vput(vp);
3359         }
3360         nd->nd_flag = savflag;
3361         if (nd->nd_repstat)
3362                 goto out;
3363
3364         /*
3365          * Finally have the export flags for name, so we can create
3366          * the security info.
3367          */
3368         len = 0;
3369         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3370         for (i = 0; i < retnes.nes_numsecflavor; i++) {
3371                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3372                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3373                         *tl = txdr_unsigned(RPCAUTH_UNIX);
3374                         len++;
3375                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3376                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3377                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3378                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3379                             nfsgss_mechlist[KERBV_MECH].len);
3380                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3381                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3382                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3383                         len++;
3384                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3385                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3386                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3387                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3388                             nfsgss_mechlist[KERBV_MECH].len);
3389                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3390                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3391                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3392                         len++;
3393                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3394                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3395                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
3396                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3397                             nfsgss_mechlist[KERBV_MECH].len);
3398                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3399                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3400                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3401                         len++;
3402                 }
3403         }
3404         *sizp = txdr_unsigned(len);
3405
3406 out:
3407         NFSEXITCODE2(error, nd);
3408         return (error);
3409 }
3410
3411 /*
3412  * nfsv4 set client id service
3413  */
3414 APPLESTATIC int
3415 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3416     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3417 {
3418         u_int32_t *tl;
3419         int i;
3420         int error = 0, idlen;
3421         struct nfsclient *clp = NULL;
3422         struct sockaddr_in *rad;
3423         u_char *verf, *ucp, *ucp2, addrbuf[24];
3424         nfsquad_t clientid, confirm;
3425
3426         if ((nd->nd_flag & ND_NFSV41) != 0) {
3427                 nd->nd_repstat = NFSERR_NOTSUPP;
3428                 goto nfsmout;
3429         }
3430         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3431                 nd->nd_repstat = NFSERR_WRONGSEC;
3432                 goto out;
3433         }
3434         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3435         verf = (u_char *)tl;
3436         tl += (NFSX_VERF / NFSX_UNSIGNED);
3437         i = fxdr_unsigned(int, *tl);
3438         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3439                 nd->nd_repstat = NFSERR_BADXDR;
3440                 goto nfsmout;
3441         }
3442         idlen = i;
3443         if (nd->nd_flag & ND_GSS)
3444                 i += nd->nd_princlen;
3445         MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3446             M_NFSDCLIENT, M_WAITOK);
3447         NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3448         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3449         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3450         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3451         clp->lc_req.nr_cred = NULL;
3452         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3453         clp->lc_idlen = idlen;
3454         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3455         if (error)
3456                 goto nfsmout;
3457         if (nd->nd_flag & ND_GSS) {
3458                 clp->lc_flags = LCL_GSS;
3459                 if (nd->nd_flag & ND_GSSINTEGRITY)
3460                         clp->lc_flags |= LCL_GSSINTEGRITY;
3461                 else if (nd->nd_flag & ND_GSSPRIVACY)
3462                         clp->lc_flags |= LCL_GSSPRIVACY;
3463         } else {
3464                 clp->lc_flags = 0;
3465         }
3466         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3467                 clp->lc_flags |= LCL_NAME;
3468                 clp->lc_namelen = nd->nd_princlen;
3469                 clp->lc_name = &clp->lc_id[idlen];
3470                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3471         } else {
3472                 clp->lc_uid = nd->nd_cred->cr_uid;
3473                 clp->lc_gid = nd->nd_cred->cr_gid;
3474         }
3475         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3476         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3477         error = nfsrv_getclientipaddr(nd, clp);
3478         if (error)
3479                 goto nfsmout;
3480         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3481         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3482
3483         /*
3484          * nfsrv_setclient() does the actual work of adding it to the
3485          * client list. If there is no error, the structure has been
3486          * linked into the client list and clp should no longer be used
3487          * here. When an error is returned, it has not been linked in,
3488          * so it should be free'd.
3489          */
3490         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3491         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3492                 if (clp->lc_flags & LCL_TCPCALLBACK)
3493                         (void) nfsm_strtom(nd, "tcp", 3);
3494                 else 
3495                         (void) nfsm_strtom(nd, "udp", 3);
3496                 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3497                 ucp = (u_char *)&rad->sin_addr.s_addr;
3498                 ucp2 = (u_char *)&rad->sin_port;
3499                 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3500                     ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3501                     ucp2[0] & 0xff, ucp2[1] & 0xff);
3502                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3503         }
3504         if (clp) {
3505                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3506                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3507                 free((caddr_t)clp, M_NFSDCLIENT);
3508         }
3509         if (!nd->nd_repstat) {
3510                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3511                 *tl++ = clientid.lval[0];
3512                 *tl++ = clientid.lval[1];
3513                 *tl++ = confirm.lval[0];
3514                 *tl = confirm.lval[1];
3515         }
3516
3517 out:
3518         NFSEXITCODE2(0, nd);
3519         return (0);
3520 nfsmout:
3521         if (clp) {
3522                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3523                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3524                 free((caddr_t)clp, M_NFSDCLIENT);
3525         }
3526         NFSEXITCODE2(error, nd);
3527         return (error);
3528 }
3529
3530 /*
3531  * nfsv4 set client id confirm service
3532  */
3533 APPLESTATIC int
3534 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3535     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3536     __unused struct nfsexstuff *exp)
3537 {
3538         u_int32_t *tl;
3539         int error = 0;
3540         nfsquad_t clientid, confirm;
3541
3542         if ((nd->nd_flag & ND_NFSV41) != 0) {
3543                 nd->nd_repstat = NFSERR_NOTSUPP;
3544                 goto nfsmout;
3545         }
3546         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3547                 nd->nd_repstat = NFSERR_WRONGSEC;
3548                 goto nfsmout;
3549         }
3550         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3551         clientid.lval[0] = *tl++;
3552         clientid.lval[1] = *tl++;
3553         confirm.lval[0] = *tl++;
3554         confirm.lval[1] = *tl;
3555
3556         /*
3557          * nfsrv_getclient() searches the client list for a match and
3558          * returns the appropriate NFSERR status.
3559          */
3560         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3561             NULL, NULL, confirm, 0, nd, p);
3562 nfsmout:
3563         NFSEXITCODE2(error, nd);
3564         return (error);
3565 }
3566
3567 /*
3568  * nfsv4 verify service
3569  */
3570 APPLESTATIC int
3571 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3572     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3573 {
3574         int error = 0, ret, fhsize = NFSX_MYFH;
3575         struct nfsvattr nva;
3576         struct statfs sf;
3577         struct nfsfsinfo fs;
3578         fhandle_t fh;
3579
3580         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3581         if (!nd->nd_repstat)
3582                 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3583         if (!nd->nd_repstat)
3584                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3585         if (!nd->nd_repstat) {
3586                 nfsvno_getfs(&fs, isdgram);
3587                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3588                     &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3589                 if (!error) {
3590                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3591                                 if (ret == 0)
3592                                         nd->nd_repstat = NFSERR_SAME;
3593                                 else if (ret != NFSERR_NOTSAME)
3594                                         nd->nd_repstat = ret;
3595                         } else if (ret)
3596                                 nd->nd_repstat = ret;
3597                 }
3598         }
3599         vput(vp);
3600         NFSEXITCODE2(error, nd);
3601         return (error);
3602 }
3603
3604 /*
3605  * nfs openattr rpc
3606  */
3607 APPLESTATIC int
3608 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3609     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3610     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3611 {
3612         u_int32_t *tl;
3613         int error = 0, createdir;
3614
3615         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3616         createdir = fxdr_unsigned(int, *tl);
3617         nd->nd_repstat = NFSERR_NOTSUPP;
3618 nfsmout:
3619         vrele(dp);
3620         NFSEXITCODE2(error, nd);
3621         return (error);
3622 }
3623
3624 /*
3625  * nfsv4 release lock owner service
3626  */
3627 APPLESTATIC int
3628 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3629     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3630 {
3631         u_int32_t *tl;
3632         struct nfsstate *stp = NULL;
3633         int error = 0, len;
3634         nfsquad_t clientid;
3635
3636         if ((nd->nd_flag & ND_NFSV41) != 0) {
3637                 nd->nd_repstat = NFSERR_NOTSUPP;
3638                 goto nfsmout;
3639         }
3640         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3641                 nd->nd_repstat = NFSERR_WRONGSEC;
3642                 goto nfsmout;
3643         }
3644         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3645         len = fxdr_unsigned(int, *(tl + 2));
3646         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3647                 nd->nd_repstat = NFSERR_BADXDR;
3648                 goto nfsmout;
3649         }
3650         MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3651             M_NFSDSTATE, M_WAITOK);
3652         stp->ls_ownerlen = len;
3653         stp->ls_op = NULL;
3654         stp->ls_flags = NFSLCK_RELEASE;
3655         stp->ls_uid = nd->nd_cred->cr_uid;
3656         clientid.lval[0] = *tl++;
3657         clientid.lval[1] = *tl;
3658         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3659                 if ((nd->nd_flag & ND_NFSV41) != 0)
3660                         clientid.qval = nd->nd_clientid.qval;
3661                 else if (nd->nd_clientid.qval != clientid.qval)
3662                         printf("EEK14 multiple clids\n");
3663         } else {
3664                 if ((nd->nd_flag & ND_NFSV41) != 0)
3665                         printf("EEK! no clientid from session\n");
3666                 nd->nd_flag |= ND_IMPLIEDCLID;
3667                 nd->nd_clientid.qval = clientid.qval;
3668         }
3669         error = nfsrv_mtostr(nd, stp->ls_owner, len);
3670         if (error)
3671                 goto nfsmout;
3672         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3673         FREE((caddr_t)stp, M_NFSDSTATE);
3674
3675         NFSEXITCODE2(0, nd);
3676         return (0);
3677 nfsmout:
3678         if (stp)
3679                 free((caddr_t)stp, M_NFSDSTATE);
3680         NFSEXITCODE2(error, nd);
3681         return (error);
3682 }
3683
3684 /*
3685  * nfsv4 exchange_id service
3686  */
3687 APPLESTATIC int
3688 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3689     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3690 {
3691         uint32_t *tl;
3692         int error = 0, i, idlen;
3693         struct nfsclient *clp = NULL;
3694         nfsquad_t clientid, confirm;
3695         uint8_t *verf;
3696         uint32_t sp4type, v41flags;
3697         uint64_t owner_minor;
3698         struct timespec verstime;
3699
3700         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3701                 nd->nd_repstat = NFSERR_WRONGSEC;
3702                 goto nfsmout;
3703         }
3704         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3705         verf = (uint8_t *)tl;
3706         tl += (NFSX_VERF / NFSX_UNSIGNED);
3707         i = fxdr_unsigned(int, *tl);
3708         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3709                 nd->nd_repstat = NFSERR_BADXDR;
3710                 goto nfsmout;
3711         }
3712         idlen = i;
3713         if (nd->nd_flag & ND_GSS)
3714                 i += nd->nd_princlen;
3715         clp = (struct nfsclient *)malloc(sizeof(struct nfsclient) + i,
3716             M_NFSDCLIENT, M_WAITOK | M_ZERO);
3717         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3718         NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3719         NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3720         clp->lc_req.nr_cred = NULL;
3721         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3722         clp->lc_idlen = idlen;
3723         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3724         if (error != 0)
3725                 goto nfsmout;
3726         if ((nd->nd_flag & ND_GSS) != 0) {
3727                 clp->lc_flags = LCL_GSS | LCL_NFSV41;
3728                 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
3729                         clp->lc_flags |= LCL_GSSINTEGRITY;
3730                 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
3731                         clp->lc_flags |= LCL_GSSPRIVACY;
3732         } else
3733                 clp->lc_flags = LCL_NFSV41;
3734         if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
3735                 clp->lc_flags |= LCL_NAME;
3736                 clp->lc_namelen = nd->nd_princlen;
3737                 clp->lc_name = &clp->lc_id[idlen];
3738                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3739         } else {
3740                 clp->lc_uid = nd->nd_cred->cr_uid;
3741                 clp->lc_gid = nd->nd_cred->cr_gid;
3742         }
3743         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3744         v41flags = fxdr_unsigned(uint32_t, *tl++);
3745         if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
3746             NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
3747             NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
3748                 nd->nd_repstat = NFSERR_INVAL;
3749                 goto nfsmout;
3750         }
3751         if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
3752                 confirm.lval[1] = 1;
3753         else
3754                 confirm.lval[1] = 0;
3755         v41flags = NFSV4EXCH_USENONPNFS;
3756         sp4type = fxdr_unsigned(uint32_t, *tl);
3757         if (sp4type != NFSV4EXCH_SP4NONE) {
3758                 nd->nd_repstat = NFSERR_NOTSUPP;
3759                 goto nfsmout;
3760         }
3761
3762         /*
3763          * nfsrv_setclient() does the actual work of adding it to the
3764          * client list. If there is no error, the structure has been
3765          * linked into the client list and clp should no longer be used
3766          * here. When an error is returned, it has not been linked in,
3767          * so it should be free'd.
3768          */
3769         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3770         if (clp != NULL) {
3771                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3772                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3773                 free(clp, M_NFSDCLIENT);
3774         }
3775         if (nd->nd_repstat == 0) {
3776                 if (confirm.lval[1] != 0)
3777                         v41flags |= NFSV4EXCH_CONFIRMEDR;
3778                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
3779                 *tl++ = clientid.lval[0];                       /* ClientID */
3780                 *tl++ = clientid.lval[1];
3781                 *tl++ = txdr_unsigned(confirm.lval[0]);         /* SequenceID */
3782                 *tl++ = txdr_unsigned(v41flags);                /* Exch flags */
3783                 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);       /* No SSV */
3784                 owner_minor = 0;                                /* Owner */
3785                 txdr_hyper(owner_minor, tl);                    /* Minor */
3786                 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
3787                     strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
3788                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3789                 *tl++ = txdr_unsigned(NFSX_UNSIGNED);
3790                 *tl++ = time_uptime;            /* Make scope a unique value. */
3791                 *tl = txdr_unsigned(1);
3792                 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
3793                 (void)nfsm_strtom(nd, version, strlen(version));
3794                 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
3795                 verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
3796                 verstime.tv_nsec = 0;
3797                 txdr_nfsv4time(&verstime, tl);
3798         }
3799         NFSEXITCODE2(0, nd);
3800         return (0);
3801 nfsmout:
3802         if (clp != NULL) {
3803                 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3804                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3805                 free(clp, M_NFSDCLIENT);
3806         }
3807         NFSEXITCODE2(error, nd);
3808         return (error);
3809 }
3810
3811 /*
3812  * nfsv4 create session service
3813  */
3814 APPLESTATIC int
3815 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
3816     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3817 {
3818         uint32_t *tl;
3819         int error = 0;
3820         nfsquad_t clientid, confirm;
3821         struct nfsdsession *sep = NULL;
3822         uint32_t rdmacnt;
3823
3824         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3825                 nd->nd_repstat = NFSERR_WRONGSEC;
3826                 goto nfsmout;
3827         }
3828         sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
3829             M_NFSDSESSION, M_WAITOK | M_ZERO);
3830         sep->sess_refcnt = 1;
3831         mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
3832         NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
3833         clientid.lval[0] = *tl++;
3834         clientid.lval[1] = *tl++;
3835         confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
3836         sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
3837         /* Persistent sessions and RDMA are not supported. */
3838         sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
3839
3840         /* Fore channel attributes. */
3841         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3842         tl++;                                   /* Header pad always 0. */
3843         sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
3844         sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
3845         sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
3846         sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
3847         sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
3848         if (sep->sess_maxslots > NFSV4_SLOTS)
3849                 sep->sess_maxslots = NFSV4_SLOTS;
3850         rdmacnt = fxdr_unsigned(uint32_t, *tl);
3851         if (rdmacnt > 1) {
3852                 nd->nd_repstat = NFSERR_BADXDR;
3853                 goto nfsmout;
3854         } else if (rdmacnt == 1)
3855                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3856
3857         /* Back channel attributes. */
3858         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3859         tl++;                                   /* Header pad always 0. */
3860         sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
3861         sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
3862         sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
3863         sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
3864         sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
3865         rdmacnt = fxdr_unsigned(uint32_t, *tl);
3866         if (rdmacnt > 1) {
3867                 nd->nd_repstat = NFSERR_BADXDR;
3868                 goto nfsmout;
3869         } else if (rdmacnt == 1)
3870                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3871
3872         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3873         sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
3874
3875         /*
3876          * nfsrv_getclient() searches the client list for a match and
3877          * returns the appropriate NFSERR status.
3878          */
3879         nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
3880             NULL, sep, confirm, sep->sess_cbprogram, nd, p);
3881         if (nd->nd_repstat == 0) {
3882                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3883                 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
3884                 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
3885                 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
3886                 *tl++ = txdr_unsigned(sep->sess_crflags);
3887
3888                 /* Fore channel attributes. */
3889                 *tl++ = 0;
3890                 *tl++ = txdr_unsigned(sep->sess_maxreq);
3891                 *tl++ = txdr_unsigned(sep->sess_maxresp);
3892                 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
3893                 *tl++ = txdr_unsigned(sep->sess_maxops);
3894                 *tl++ = txdr_unsigned(sep->sess_maxslots);
3895                 *tl++ = txdr_unsigned(1);
3896                 *tl++ = txdr_unsigned(0);                       /* No RDMA. */
3897
3898                 /* Back channel attributes. */
3899                 *tl++ = 0;
3900                 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
3901                 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
3902                 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
3903                 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
3904                 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
3905                 *tl++ = txdr_unsigned(1);
3906                 *tl = txdr_unsigned(0);                 /* No RDMA. */
3907         }
3908 nfsmout:
3909         if (nd->nd_repstat != 0 && sep != NULL)
3910                 free(sep, M_NFSDSESSION);
3911         NFSEXITCODE2(error, nd);
3912         return (error);
3913 }
3914
3915 /*
3916  * nfsv4 sequence service
3917  */
3918 APPLESTATIC int
3919 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
3920     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3921 {
3922         uint32_t *tl;
3923         uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
3924         int cache_this, error = 0;
3925
3926         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3927                 nd->nd_repstat = NFSERR_WRONGSEC;
3928                 goto nfsmout;
3929         }
3930         NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
3931         NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
3932         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
3933         sequenceid = fxdr_unsigned(uint32_t, *tl++);
3934         nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
3935         highest_slotid = fxdr_unsigned(uint32_t, *tl++);
3936         if (*tl == newnfs_true)
3937                 cache_this = 1;
3938         else
3939                 cache_this = 0;
3940         nd->nd_flag |= ND_HASSEQUENCE;
3941         nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
3942             &target_highest_slotid, cache_this, &sflags, p);
3943         if (nd->nd_repstat == 0) {
3944                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3945                 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
3946                 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
3947                 *tl++ = txdr_unsigned(sequenceid);
3948                 *tl++ = txdr_unsigned(nd->nd_slotid);
3949                 *tl++ = txdr_unsigned(highest_slotid);
3950                 *tl++ = txdr_unsigned(target_highest_slotid);
3951                 *tl = txdr_unsigned(sflags);
3952         }
3953 nfsmout:
3954         NFSEXITCODE2(error, nd);
3955         return (error);
3956 }
3957
3958 /*
3959  * nfsv4 reclaim complete service
3960  */
3961 APPLESTATIC int
3962 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
3963     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3964 {
3965         uint32_t *tl;
3966         int error = 0;
3967
3968         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3969                 nd->nd_repstat = NFSERR_WRONGSEC;
3970                 goto nfsmout;
3971         }
3972         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3973         if (*tl == newnfs_true)
3974                 nd->nd_repstat = NFSERR_NOTSUPP;
3975         else
3976                 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
3977 nfsmout:
3978         NFSEXITCODE2(error, nd);
3979         return (error);
3980 }
3981
3982 /*
3983  * nfsv4 destroy clientid service
3984  */
3985 APPLESTATIC int
3986 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
3987     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3988 {
3989         uint32_t *tl;
3990         nfsquad_t clientid;
3991         int error = 0;
3992
3993         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3994                 nd->nd_repstat = NFSERR_WRONGSEC;
3995                 goto nfsmout;
3996         }
3997         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3998         clientid.lval[0] = *tl++;
3999         clientid.lval[1] = *tl;
4000         nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4001 nfsmout:
4002         NFSEXITCODE2(error, nd);
4003         return (error);
4004 }
4005
4006 /*
4007  * nfsv4 destroy session service
4008  */
4009 APPLESTATIC int
4010 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4011     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4012 {
4013         uint8_t *cp, sessid[NFSX_V4SESSIONID];
4014         int error = 0;
4015
4016         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4017                 nd->nd_repstat = NFSERR_WRONGSEC;
4018                 goto nfsmout;
4019         }
4020         NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4021         NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4022         nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4023 nfsmout:
4024         NFSEXITCODE2(error, nd);
4025         return (error);
4026 }
4027
4028 /*
4029  * nfsv4 free stateid service
4030  */
4031 APPLESTATIC int
4032 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4033     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4034 {
4035         uint32_t *tl;
4036         nfsv4stateid_t stateid;
4037         int error = 0;
4038
4039         if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4040                 nd->nd_repstat = NFSERR_WRONGSEC;
4041                 goto nfsmout;
4042         }
4043         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4044         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4045         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4046         nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4047 nfsmout:
4048         NFSEXITCODE2(error, nd);
4049         return (error);
4050 }
4051
4052 /*
4053  * nfsv4 service not supported
4054  */
4055 APPLESTATIC int
4056 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4057     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4058 {
4059
4060         nd->nd_repstat = NFSERR_NOTSUPP;
4061         NFSEXITCODE2(0, nd);
4062         return (0);
4063 }
4064