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