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