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