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