2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
65 * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
69 * nfs version 2 and 3 server calls to vnode ops
70 * - these routines generally have 3 phases
71 * 1 - break down and validate rpc request in mbuf list
72 * 2 - do the vnode ops for the request
73 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
74 * 3 - build the rpc reply in an mbuf list
76 * - do not mix the phases, since the nfsm_?? macros can return failures
77 * on a bad rpc or similar and do not do any vnode_rele()s or vnode_put()s
79 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
80 * error number iff error != 0 whereas
81 * returning an error from the server function implies a fatal error
82 * such as a badly constructed rpc request that should be dropped without
84 * For Version 3, nfsm_reply() does not return for the error case, since
85 * most version 3 rpcs return more than the status for error cases.
88 #include <sys/param.h>
89 #include <sys/systm.h>
91 #include <sys/kauth.h>
92 #include <sys/unistd.h>
93 #include <sys/malloc.h>
94 #include <sys/vnode.h>
95 #include <sys/mount_internal.h>
96 #include <sys/socket.h>
97 #include <sys/socketvar.h>
98 #include <sys/kpi_mbuf.h>
99 #include <sys/dirent.h>
100 #include <sys/stat.h>
101 #include <sys/kernel.h>
102 #include <sys/sysctl.h>
104 #include <sys/vnode_internal.h>
105 #include <sys/uio_internal.h>
106 #include <libkern/OSAtomic.h>
109 #include <sys/vmparam.h>
111 #include <nfs/nfsproto.h>
112 #include <nfs/rpcv2.h>
114 #include <nfs/xdr_subs.h>
115 #include <nfs/nfsm_subs.h>
117 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
120 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
123 extern u_long nfs_xdrneg1
;
124 extern u_long nfs_false
, nfs_true
;
125 extern enum vtype nv3tov_type
[8];
126 extern struct nfsstats nfsstats
;
128 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
129 int nfsrvw_procrastinate_v3
= 0;
133 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
134 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
137 static int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
138 static void nfsrvw_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
140 #define THREAD_SAFE_FS(VP) \
141 ((VP)->v_mount ? (VP)->v_mount->mnt_vtable->vfc_threadsafe : 0)
144 * nfs v3 access service
147 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
148 struct nfsrv_descript
*nfsd
;
149 struct nfssvc_sock
*slp
;
153 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
154 mbuf_t nam
= nfsd
->nd_nam
;
155 caddr_t dpos
= nfsd
->nd_dpos
;
157 struct nfs_filehandle nfh
;
161 int error
= 0, getret
;
163 mbuf_t mb
, mreq
, mb2
;
164 struct vnode_attr vattr
, *vap
= &vattr
;
166 kauth_action_t testaction
;
167 struct vfs_context context
;
168 struct nfs_export
*nx
;
169 struct nfs_export_options
*nxo
;
172 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
173 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
174 nfsm_reply(NFSX_UNSIGNED
);
175 nfsm_srvpostop_attr(1, NULL
);
178 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
180 nfsm_reply(NFSX_UNSIGNED
);
181 nfsm_srvpostop_attr(1, NULL
);
184 nfsmode
= fxdr_unsigned(u_long
, *tl
);
186 context
.vc_proc
= procp
;
187 context
.vc_ucred
= nfsd
->nd_cr
;
190 * Each NFS mode bit is tested separately.
192 * XXX this code is nominally correct, but returns a pessimistic
193 * rather than optimistic result. It will be necessary to add
194 * an NFS-specific interface to the vnode_authorize code to
195 * obtain good performance in the optimistic mode.
197 if (nfsmode
& NFSV3ACCESS_READ
) {
198 if (vnode_isdir(vp
)) {
200 KAUTH_VNODE_LIST_DIRECTORY
|
201 KAUTH_VNODE_READ_EXTATTRIBUTES
;
204 KAUTH_VNODE_READ_DATA
|
205 KAUTH_VNODE_READ_EXTATTRIBUTES
;
207 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
208 nfsmode
&= ~NFSV3ACCESS_READ
;
210 if ((nfsmode
& NFSV3ACCESS_LOOKUP
) &&
212 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
, nxo
, 0)))
213 nfsmode
&= ~NFSV3ACCESS_LOOKUP
;
214 if (nfsmode
& NFSV3ACCESS_MODIFY
) {
215 if (vnode_isdir(vp
)) {
217 KAUTH_VNODE_ADD_FILE
|
218 KAUTH_VNODE_ADD_SUBDIRECTORY
|
219 KAUTH_VNODE_DELETE_CHILD
;
222 KAUTH_VNODE_WRITE_DATA
;
224 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
225 nfsmode
&= ~NFSV3ACCESS_MODIFY
;
227 if (nfsmode
& NFSV3ACCESS_EXTEND
) {
228 if (vnode_isdir(vp
)) {
230 KAUTH_VNODE_ADD_FILE
|
231 KAUTH_VNODE_ADD_SUBDIRECTORY
;
234 KAUTH_VNODE_WRITE_DATA
|
235 KAUTH_VNODE_APPEND_DATA
;
237 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
238 nfsmode
&= ~NFSV3ACCESS_EXTEND
;
242 * Note concerning NFSV3ACCESS_DELETE:
243 * For hard links, the answer may be wrong if the vnode
244 * has multiple parents with different permissions.
245 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
246 * interpret the missing/cleared DELETE bit.
247 * So we'll just leave the DELETE bit alone. At worst,
248 * we're telling the client it might be able to do
249 * something it really can't.
252 if ((nfsmode
& NFSV3ACCESS_EXECUTE
) &&
254 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 0)))
255 nfsmode
&= ~NFSV3ACCESS_EXECUTE
;
257 nfsm_srv_vattr_init(vap
, 1);
258 getret
= vnode_getattr(vp
, vap
, &context
);
260 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
261 nfsm_srvpostop_attr(getret
, vap
);
262 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
263 *tl
= txdr_unsigned(nfsmode
);
269 * nfs getattr service
272 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
273 struct nfsrv_descript
*nfsd
;
274 struct nfssvc_sock
*slp
;
278 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
279 mbuf_t nam
= nfsd
->nd_nam
;
280 caddr_t dpos
= nfsd
->nd_dpos
;
281 struct nfs_fattr
*fp
;
282 struct vnode_attr va
;
283 struct vnode_attr
*vap
= &va
;
285 struct nfs_filehandle nfh
;
291 mbuf_t mb
, mb2
, mreq
;
292 struct vfs_context context
;
293 struct nfs_export
*nx
;
294 struct nfs_export_options
*nxo
;
295 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
298 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
302 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
307 context
.vc_proc
= procp
;
308 context
.vc_ucred
= nfsd
->nd_cr
;
310 nfsm_srv_vattr_init(vap
, v3
);
311 error
= vnode_getattr(vp
, vap
, &context
);
313 nfsm_reply(NFSX_FATTR(v3
));
316 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(v3
));
317 nfsm_srvfillattr(vap
, fp
);
323 * nfs setattr service
326 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
327 struct nfsrv_descript
*nfsd
;
328 struct nfssvc_sock
*slp
;
332 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
333 mbuf_t nam
= nfsd
->nd_nam
;
334 caddr_t dpos
= nfsd
->nd_dpos
;
335 struct vnode_attr preat
;
336 struct vnode_attr postat
;
337 struct vnode_attr va
;
338 struct vnode_attr
*vap
= &va
;
339 struct nfsv2_sattr
*sp
;
340 struct nfs_fattr
*fp
;
342 struct nfs_filehandle nfh
;
343 struct nfs_export
*nx
;
344 struct nfs_export_options
*nxo
;
348 int error
= 0, preat_ret
= 1, postat_ret
= 1;
349 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
351 mbuf_t mb
, mb2
, mreq
;
352 struct timespec guard
;
353 struct vfs_context context
;
354 kauth_action_t action
;
361 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
362 gcheck
= fxdr_unsigned(int, *tl
);
364 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
365 fxdr_nfsv3time(tl
, &guard
);
368 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
370 * Nah nah nah nah na nah
371 * There is a bug in the Sun client that puts 0xffff in the mode
372 * field of sattr when it should put in 0xffffffff. The u_short
373 * doesn't sign extend.
374 * --> check the low order 2 bytes for 0xffff
376 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
377 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
378 if (sp
->sa_uid
!= nfs_xdrneg1
)
379 VATTR_SET(vap
, va_uid
, fxdr_unsigned(uid_t
, sp
->sa_uid
));
380 if (sp
->sa_gid
!= nfs_xdrneg1
)
381 VATTR_SET(vap
, va_gid
, fxdr_unsigned(gid_t
, sp
->sa_gid
));
382 if (sp
->sa_size
!= nfs_xdrneg1
)
383 VATTR_SET(vap
, va_data_size
, fxdr_unsigned(u_quad_t
, sp
->sa_size
));
384 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
385 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_access_time
);
386 VATTR_SET_ACTIVE(vap
, va_access_time
);
388 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
) {
389 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_modify_time
);
390 VATTR_SET_ACTIVE(vap
, va_modify_time
);
395 * Save the original credential UID in case they are
396 * mapped and we need to map the IDs in the attributes.
398 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
401 * Now that we have all the fields, lets do it.
403 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
404 nfsm_reply(2 * NFSX_UNSIGNED
);
405 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
408 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
410 nfsm_reply(2 * NFSX_UNSIGNED
);
411 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
415 context
.vc_proc
= procp
;
416 context
.vc_ucred
= nfsd
->nd_cr
;
419 nfsm_srv_pre_vattr_init(&preat
, v3
);
420 error
= preat_ret
= vnode_getattr(vp
, &preat
, &context
);
421 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preat
, va_change_time
) &&
422 (preat
.va_change_time
.tv_sec
!= guard
.tv_sec
||
423 preat
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
424 error
= NFSERR_NOT_SYNC
;
425 if (!preat_ret
&& !VATTR_ALL_SUPPORTED(&preat
))
429 nfsm_reply(NFSX_WCCDATA(v3
));
430 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
436 * If the credentials were mapped, we should
437 * map the same values in the attributes.
439 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
441 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
442 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
443 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
447 * Authorize the attribute changes.
449 if (((error
= vnode_authattr(vp
, vap
, &action
, &context
))) ||
450 ((error
= nfsrv_authorize(vp
, NULL
, action
, &context
, nxo
, 0))))
452 error
= vnode_setattr(vp
, vap
, &context
);
454 nfsm_srv_vattr_init(&postat
, v3
);
455 postat_ret
= vnode_getattr(vp
, &postat
, &context
);
460 nfsm_reply(NFSX_WCCORFATTR(v3
));
462 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
465 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
466 nfsm_srvfillattr(&postat
, fp
);
476 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
477 struct nfsrv_descript
*nfsd
;
478 struct nfssvc_sock
*slp
;
482 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
483 mbuf_t nam
= nfsd
->nd_nam
;
484 caddr_t dpos
= nfsd
->nd_dpos
;
485 struct nfs_fattr
*fp
;
486 struct nameidata nd
, *ndp
= &nd
;
487 /* XXX Revisit when enabling WebNFS */
488 #ifdef WEBNFS_ENABLED
489 struct nameidata ind
;
491 vnode_t vp
, dirp
= NULL
;
492 struct nfs_filehandle dnfh
, nfh
;
493 struct nfs_export
*nx
;
494 struct nfs_export_options
*nxo
;
499 int error
= 0, len
, dirattr_ret
= 1, isdotdot
;
500 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
502 mbuf_t mb
, mb2
, mreq
;
503 struct vnode_attr va
, dirattr
, *vap
= &va
;
504 struct vfs_context context
;
506 context
.vc_proc
= procp
;
507 context
.vc_ucred
= nfsd
->nd_cr
;
509 nfsm_srvmtofh(&dnfh
);
510 nfsm_srvnamesiz(len
, v3
);
512 pubflag
= nfs_ispublicfh(&dnfh
);
514 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
515 nd
.ni_cnd
.cn_flags
= LOCKLEAF
;
516 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, pubflag
, &len
, &nd
);
517 isdotdot
= ((len
== 2) && (nd
.ni_cnd
.cn_pnbuf
[0] == '.') && (nd
.ni_cnd
.cn_pnbuf
[1] == '.'));
519 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, pubflag
, &dirp
, &nx
, &nxo
);
521 /* XXX Revisit when enabling WebNFS */
522 #ifdef WEBNFS_ENABLED
523 if (!error
&& pubflag
) {
524 if (vnode_vtype(nd
.ni_vp
) == VDIR
&& nfs_pub
.np_index
!= NULL
) {
526 * Setup call to lookup() to see if we can find
527 * the index file. Arguably, this doesn't belong
531 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
532 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
534 ind
.ni_startdir
= nd
.ni_vp
;
535 ind
.ni_usedvp
= nd
.ni_vp
;
537 if (!(error
= lookup(&ind
))) {
539 * Found an index file. Get rid of
540 * the old references.
545 vnode_put(nd
.ni_startdir
);
551 * If the public filehandle was used, check that this lookup
552 * didn't result in a filehandle outside the publicly exported
556 if (!error
&& vnode_mount(ndp
->ni_vp
) != nfs_pub
.np_mount
) {
566 nfsm_srv_vattr_init(&dirattr
, v3
);
567 dirattr_ret
= vnode_getattr(dirp
, &dirattr
, &context
);
573 nfsm_reply(NFSX_POSTOPATTR(v3
));
574 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
580 error
= nfsrv_vptofh(nx
, !v3
, (isdotdot
? &dnfh
: NULL
), vp
, &context
, &nfh
);
582 nfsm_srv_vattr_init(vap
, v3
);
583 error
= vnode_getattr(vp
, vap
, &context
);
586 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
588 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
591 nfsm_srvfhtom(&nfh
, v3
);
593 nfsm_srvpostop_attr(0, vap
);
594 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
596 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
597 nfsm_srvfillattr(vap
, fp
);
604 * nfs readlink service
607 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
608 struct nfsrv_descript
*nfsd
;
609 struct nfssvc_sock
*slp
;
613 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
614 mbuf_t nam
= nfsd
->nd_nam
;
615 caddr_t dpos
= nfsd
->nd_dpos
;
620 int error
= 0, i
, tlen
, len
, getret
= 1;
621 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
623 mbuf_t mb
, mb2
, mp2
, mp3
, mreq
;
625 struct vnode_attr attr
;
626 struct nfs_filehandle nfh
;
627 struct nfs_export
*nx
;
628 struct nfs_export_options
*nxo
;
630 char uio_buf
[ UIO_SIZEOF(4) ];
631 char *uio_bufp
= &uio_buf
[0];
632 int uio_buflen
= UIO_SIZEOF(4);
634 struct vfs_context context
;
642 while (len
< NFS_MAXPATHLEN
) {
644 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
)))
646 mblen
= mbuf_maxlen(mp
);
647 mbuf_setlen(mp
, mblen
);
651 if ((error
= mbuf_setnext(mp2
, mp
))) {
657 if ((len
+ mblen
) > NFS_MAXPATHLEN
) {
658 mbuf_setlen(mp
, NFS_MAXPATHLEN
- len
);
659 len
= NFS_MAXPATHLEN
;
665 uio_buflen
= UIO_SIZEOF(i
);
666 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
670 nfsm_reply(2 * NFSX_UNSIGNED
);
671 nfsm_srvpostop_attr(1, NULL
);
675 uiop
= uio_createwithbuffer(i
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
679 if (uio_bufp
!= &uio_buf
[0]) {
680 FREE(uio_bufp
, M_TEMP
);
681 uio_bufp
= &uio_buf
[0];
683 nfsm_reply(2 * NFSX_UNSIGNED
);
684 nfsm_srvpostop_attr(1, NULL
);
689 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
693 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
695 if (uio_bufp
!= &uio_buf
[0]) {
696 FREE(uio_bufp
, M_TEMP
);
697 uio_bufp
= &uio_buf
[0];
699 nfsm_reply(2 * NFSX_UNSIGNED
);
700 nfsm_srvpostop_attr(1, NULL
);
703 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
706 if (uio_bufp
!= &uio_buf
[0]) {
707 FREE(uio_bufp
, M_TEMP
);
708 uio_bufp
= &uio_buf
[0];
710 nfsm_reply(2 * NFSX_UNSIGNED
);
711 nfsm_srvpostop_attr(1, NULL
);
714 if (vnode_vtype(vp
) != VLNK
) {
722 context
.vc_proc
= procp
;
723 context
.vc_ucred
= nfsd
->nd_cr
;
725 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 0)))
727 error
= VNOP_READLINK(vp
, uiop
, &context
);
731 nfsm_srv_vattr_init(&attr
, v3
);
732 getret
= vnode_getattr(vp
, &attr
, &context
);
740 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
742 nfsm_srvpostop_attr(getret
, &attr
);
744 if (uio_bufp
!= &uio_buf
[0])
745 FREE(uio_bufp
, M_TEMP
);
750 if (uiop
&& (uio_resid(uiop
) > 0)) {
751 // LP64todo - fix this
752 len
-= uio_resid(uiop
);
753 tlen
= nfsm_rndup(len
);
754 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
756 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
757 *tl
= txdr_unsigned(len
);
758 mbuf_setnext(mb
, mp3
);
761 if (uio_bufp
!= &uio_buf
[0])
762 FREE(uio_bufp
, M_TEMP
);
770 nfsrv_read(nfsd
, slp
, procp
, mrq
)
771 struct nfsrv_descript
*nfsd
;
772 struct nfssvc_sock
*slp
;
776 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
777 mbuf_t nam
= nfsd
->nd_nam
;
778 caddr_t dpos
= nfsd
->nd_dpos
;
780 struct nfs_fattr
*fp
;
785 int error
= 0, count
, len
, left
, siz
, tlen
, getret
;
786 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
, maxlen
;
788 mbuf_t mb
, mb2
, mreq
;
791 struct nfs_filehandle nfh
;
792 struct nfs_export
*nx
;
793 struct nfs_export_options
*nxo
;
795 char *uio_bufp
= NULL
;
796 struct vnode_attr va
, *vap
= &va
;
798 char uio_buf
[ UIO_SIZEOF(0) ];
799 struct vfs_context context
;
803 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
804 fxdr_hyper(tl
, &off
);
806 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
807 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
809 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
810 reqlen
= fxdr_unsigned(u_long
, *tl
);
811 maxlen
= NFS_SRVMAXDATA(nfsd
);
815 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
816 nfsm_reply(2 * NFSX_UNSIGNED
);
817 nfsm_srvpostop_attr(1, NULL
);
820 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
822 nfsm_reply(2 * NFSX_UNSIGNED
);
823 nfsm_srvpostop_attr(1, NULL
);
826 if (vnode_vtype(vp
) != VREG
) {
830 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
833 context
.vc_proc
= procp
;
834 context
.vc_ucred
= nfsd
->nd_cr
;
837 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 1)))
838 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 1);
840 nfsm_srv_vattr_init(vap
, v3
);
841 getret
= vnode_getattr(vp
, vap
, &context
);
846 nfsm_reply(NFSX_POSTOPATTR(v3
));
847 nfsm_srvpostop_attr(getret
, vap
);
850 if ((u_quad_t
)off
>= vap
->va_data_size
)
852 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
853 count
= nfsm_rndup(vap
->va_data_size
- off
);
856 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(count
));
858 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
860 fp
= (struct nfs_fattr
*)tl
;
861 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
863 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
864 fp
= (struct nfs_fattr
*)tl
;
865 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
870 * Generate the mbuf list with the uio_iov ref. to it.
875 siz
= min(mbuf_trailingspace(m
), left
);
882 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m
)))
888 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
893 uiop
= uio_createwithbuffer(i
, off
, UIO_SYSSPACE
, UIO_READ
,
894 uio_bufp
, UIO_SIZEOF(i
));
904 panic("nfsrv_read iov");
905 siz
= min(mbuf_trailingspace(m
), left
);
908 uio_addiov(uiop
, CAST_USER_ADDR_T((char *)mbuf_data(m
) + tlen
), siz
);
909 mbuf_setlen(m
, tlen
+ siz
);
915 error
= VNOP_READ(vp
, uiop
, IO_NODELOCKED
, &context
);
916 off
= uio_offset(uiop
);
919 * This may seem a little weird that we drop the whole
920 * successful read if we get an error on the getattr.
921 * The reason is because we've already set up the reply
922 * to have postop attrs and omitting these optional bits
923 * would require shifting all the data in the reply.
925 * It would be more correct if we would simply drop the
926 * postop attrs if the getattr fails. We might be able to
927 * do that easier if we allocated separate mbufs for the data.
929 nfsm_srv_vattr_init(vap
, v3
);
930 if (error
|| (getret
= vnode_getattr(vp
, vap
, &context
))) {
935 nfsm_reply(NFSX_POSTOPATTR(v3
));
936 nfsm_srvpostop_attr(getret
, vap
);
937 if (uio_bufp
!= NULL
) {
938 FREE(uio_bufp
, M_TEMP
);
943 uiop
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
950 nfsm_srvfillattr(vap
, fp
);
951 // LP64todo - fix this
952 len
-= uio_resid(uiop
);
953 tlen
= nfsm_rndup(len
);
954 if (count
!= tlen
|| tlen
!= len
)
955 nfsm_adj(mb
, count
- tlen
, tlen
- len
);
957 *tl
++ = txdr_unsigned(len
);
963 *tl
= txdr_unsigned(len
);
965 if (uio_bufp
!= NULL
) {
966 FREE(uio_bufp
, M_TEMP
);
975 nfsrv_write(nfsd
, slp
, procp
, mrq
)
976 struct nfsrv_descript
*nfsd
;
977 struct nfssvc_sock
*slp
;
981 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
982 mbuf_t nam
= nfsd
->nd_nam
;
983 caddr_t dpos
= nfsd
->nd_dpos
;
986 struct nfs_fattr
*fp
;
987 struct vnode_attr va
, forat
;
988 struct vnode_attr
*vap
= &va
;
992 int error
= 0, len
, forat_ret
= 1;
993 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
, tlen
;
994 int stable
= NFSV3WRITE_FILESYNC
;
995 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
997 mbuf_t mb
, mb2
, mreq
;
999 struct nfs_filehandle nfh
;
1000 struct nfs_export
*nx
;
1001 struct nfs_export_options
*nxo
;
1004 char *uio_bufp
= NULL
;
1005 struct vfs_context context
;
1011 nfsm_srvmtofh(&nfh
);
1013 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1014 fxdr_hyper(tl
, &off
);
1016 stable
= fxdr_unsigned(int, *tl
++);
1018 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1019 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1022 stable
= NFSV3WRITE_UNSTABLE
;
1024 retlen
= len
= fxdr_unsigned(long, *tl
);
1028 * For NFS Version 2, it is not obvious what a write of zero length
1029 * should do, but I might as well be consistent with Version 3,
1030 * which is to return ok so long as there are no permission problems.
1038 tpos
= mbuf_data(mp
);
1039 tlen
= mbuf_len(mp
);
1040 adjust
= dpos
- tpos
;
1042 mbuf_setlen(mp
, tlen
);
1043 if (tlen
> 0 && adjust
> 0) {
1045 if ((error
= mbuf_setdata(mp
, tpos
, tlen
))) {
1046 nfsm_reply(2 * NFSX_UNSIGNED
);
1047 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1054 else if ((tlen
= mbuf_len(mp
)) > 0) {
1057 mbuf_setlen(mp
, tlen
- (i
- len
));
1060 if (mbuf_len(mp
) > 0)
1066 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1068 nfsm_reply(2 * NFSX_UNSIGNED
);
1069 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1072 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
1073 nfsm_reply(2 * NFSX_UNSIGNED
);
1074 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1077 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
1079 nfsm_reply(2 * NFSX_UNSIGNED
);
1080 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1083 context
.vc_proc
= procp
;
1084 context
.vc_ucred
= nfsd
->nd_cr
;
1087 nfsm_srv_pre_vattr_init(&forat
, v3
);
1088 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1090 if (vnode_vtype(vp
) != VREG
) {
1094 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1097 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1101 nfsm_reply(NFSX_WCCDATA(v3
));
1102 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1107 MALLOC(uio_bufp
, char *, UIO_SIZEOF(count
), M_TEMP
, M_WAITOK
);
1111 nfsm_reply(NFSX_WCCDATA(v3
));
1112 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1115 uiop
= uio_createwithbuffer(count
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(count
));
1119 nfsm_reply(NFSX_WCCDATA(v3
));
1120 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1121 if (uio_bufp
!= NULL
) {
1122 FREE(uio_bufp
, M_TEMP
);
1128 if ((tlen
= mbuf_len(mp
)) > 0)
1129 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1135 * The IO_METASYNC flag indicates that all metadata (and not just
1136 * enough to ensure data integrity) mus be written to stable storage
1138 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1140 if (stable
== NFSV3WRITE_UNSTABLE
)
1141 ioflags
= IO_NODELOCKED
;
1142 else if (stable
== NFSV3WRITE_DATASYNC
)
1143 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1145 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1147 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1148 OSAddAtomic(1, (SInt32
*)(SInt32
*)&nfsstats
.srvvop_writes
);
1150 nfsm_srv_vattr_init(vap
, v3
);
1151 aftat_ret
= vnode_getattr(vp
, vap
, &context
);
1155 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
1156 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
1158 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1160 if (uio_bufp
!= NULL
) {
1161 FREE(uio_bufp
, M_TEMP
);
1165 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1166 *tl
++ = txdr_unsigned(retlen
);
1168 * If nfs_async is set, then pretend the write was FILESYNC.
1170 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1171 *tl
++ = txdr_unsigned(stable
);
1173 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1175 * Actually, there is no need to txdr these fields,
1176 * but it may make the values more human readable,
1177 * for debugging purposes.
1179 *tl
++ = txdr_unsigned(boottime_sec());
1180 *tl
= txdr_unsigned(0);
1182 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1183 nfsm_srvfillattr(vap
, fp
);
1186 if (uio_bufp
!= NULL
) {
1187 FREE(uio_bufp
, M_TEMP
);
1193 * NFS write service with write gathering support. Called when
1194 * nfsrvw_procrastinate > 0.
1195 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1196 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1200 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
1201 struct nfsrv_descript
**ndp
;
1202 struct nfssvc_sock
*slp
;
1207 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1208 struct nfs_export
*nx
;
1209 struct nfs_export_options
*nxo
;
1210 struct nfs_fattr
*fp
;
1212 struct nfsrvw_delayhash
*wpp
;
1214 struct vnode_attr va
, forat
;
1217 caddr_t bpos
, dpos
, tpos
;
1218 int error
= 0, len
, forat_ret
= 1;
1219 int ioflags
, aftat_ret
= 1, adjust
, v3
, zeroing
, tlen
;
1221 mbuf_t mb
, mb2
, mreq
, mrep
, md
;
1224 char *uio_bufp
= NULL
;
1227 struct vfs_context context
;
1229 context
.vc_proc
= procp
;
1240 mrep
= nfsd
->nd_mrep
;
1242 dpos
= nfsd
->nd_dpos
;
1244 context
.vc_ucred
= cred
;
1245 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1246 LIST_INIT(&nfsd
->nd_coalesce
);
1247 nfsd
->nd_mreq
= NULL
;
1248 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1250 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1251 nfsd
->nd_time
= cur_usec
+
1252 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1255 * Now, get the write header..
1257 nfsm_srvmtofh(&nfsd
->nd_fh
);
1258 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1260 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1261 fxdr_hyper(tl
, &nfsd
->nd_off
);
1263 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1265 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1266 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1269 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1271 len
= fxdr_unsigned(long, *tl
);
1273 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1276 * Trim the header out of the mbuf list and trim off any trailing
1277 * junk so that the mbuf list has only the write data.
1285 tpos
= mbuf_data(mp
);
1286 tlen
= mbuf_len(mp
);
1287 adjust
= dpos
- tpos
;
1289 mbuf_setlen(mp
, tlen
);
1290 if (tlen
> 0 && adjust
> 0) {
1292 if ((error
= mbuf_setdata(mp
, tpos
, tlen
)))
1299 tlen
= mbuf_len(mp
);
1302 mbuf_setlen(mp
, tlen
- (i
- len
));
1308 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1313 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1315 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1316 nfsd
->nd_mreq
= mreq
;
1317 nfsd
->nd_mrep
= NULL
;
1322 * Add this entry to the hash and time queues.
1324 lck_mtx_lock(&slp
->ns_wgmutex
);
1326 wp
= slp
->ns_tq
.lh_first
;
1327 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1329 wp
= wp
->nd_tq
.le_next
;
1332 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1334 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1336 if (nfsd
->nd_mrep
) {
1337 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.nfh_fid
);
1340 while (wp
&& !nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1342 wp
= wp
->nd_hash
.le_next
;
1344 while (wp
&& (wp
->nd_off
< nfsd
->nd_off
) &&
1345 nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1347 wp
= wp
->nd_hash
.le_next
;
1350 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1353 * Search the hash list for overlapping entries and
1356 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1357 wp
= nfsd
->nd_hash
.le_next
;
1358 if (NFSW_SAMECRED(owp
, nfsd
))
1359 nfsrvw_coalesce(owp
, nfsd
);
1362 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1366 lck_mtx_lock(&slp
->ns_wgmutex
);
1370 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1371 * and generate the associated reply mbuf list(s).
1375 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1376 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1377 owp
= nfsd
->nd_tq
.le_next
;
1378 if (nfsd
->nd_time
> cur_usec
)
1382 LIST_REMOVE(nfsd
, nd_tq
);
1383 LIST_REMOVE(nfsd
, nd_hash
);
1384 mrep
= nfsd
->nd_mrep
;
1385 nfsd
->nd_mrep
= NULL
;
1386 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1387 forat_ret
= aftat_ret
= 1;
1388 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, nfsd
->nd_nam
, TRUE
, &vp
, &nx
, &nxo
);
1390 error
= nfsrv_credcheck(nfsd
, nx
, nxo
);
1395 context
.vc_ucred
= cred
;
1398 nfsm_srv_pre_vattr_init(&forat
, v3
);
1399 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1401 if (vnode_vtype(vp
) != VREG
) {
1405 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1410 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1413 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1414 ioflags
= IO_NODELOCKED
;
1415 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1416 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1418 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1420 if (!error
&& ((nfsd
->nd_eoff
- nfsd
->nd_off
) > 0)) {
1424 if (mbuf_len(mp
) > 0)
1429 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1431 uiop
= uio_createwithbuffer(i
, nfsd
->nd_off
, UIO_SYSSPACE
,
1432 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1433 if (!uio_bufp
|| !uiop
)
1438 if ((tlen
= mbuf_len(mp
)) > 0)
1439 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1442 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1443 OSAddAtomic(1, (SInt32
*)&nfsstats
.srvvop_writes
);
1446 FREE(uio_bufp
, M_TEMP
);
1453 nfsm_srv_pre_vattr_init(&va
, v3
);
1454 aftat_ret
= vnode_getattr(vp
, &va
, &context
);
1459 * Loop around generating replies for all write rpcs that have
1460 * now been completed.
1465 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1467 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1470 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1471 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1472 NFSX_WRITEVERF(v3
), v3
);
1474 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1475 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1476 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1477 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1479 * Actually, there is no need to txdr these fields,
1480 * but it may make the values more human readable,
1481 * for debugging purposes.
1483 *tl
++ = txdr_unsigned(boottime_sec());
1484 *tl
= txdr_unsigned(0);
1486 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1487 nfsm_srvfillattr(&va
, fp
);
1490 nfsd
->nd_mreq
= mreq
;
1492 panic("nfsrv_write: nd_mrep not free");
1495 * Done. Put it at the head of the timer queue so that
1496 * the final phase can return the reply.
1500 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1502 nfsd
= swp
->nd_coalesce
.lh_first
;
1504 LIST_REMOVE(nfsd
, nd_tq
);
1508 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1513 * Search for a reply to return.
1515 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1516 if (nfsd
->nd_mreq
) {
1517 LIST_REMOVE(nfsd
, nd_tq
);
1518 *mrq
= nfsd
->nd_mreq
;
1522 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1523 lck_mtx_unlock(&slp
->ns_wgmutex
);
1528 * Coalesce the write request nfsd into owp. To do this we must:
1529 * - remove nfsd from the queues
1530 * - merge nfsd->nd_mrep into owp->nd_mrep
1531 * - update the nd_eoff and nd_stable for owp
1532 * - put nfsd on owp's nd_coalesce list
1536 struct nfsrv_descript
*owp
,
1537 struct nfsrv_descript
*nfsd
)
1541 struct nfsrv_descript
*p
;
1543 LIST_REMOVE(nfsd
, nd_hash
);
1544 LIST_REMOVE(nfsd
, nd_tq
);
1545 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1546 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1548 panic("nfsrv_coalesce: bad off");
1550 mbuf_adj(nfsd
->nd_mrep
, overlap
);
1552 while ((mpnext
= mbuf_next(mp
)))
1554 error
= mbuf_setnext(mp
, nfsd
->nd_mrep
);
1556 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error
);
1557 owp
->nd_eoff
= nfsd
->nd_eoff
;
1559 mbuf_freem(nfsd
->nd_mrep
);
1561 nfsd
->nd_mrep
= NULL
;
1562 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1563 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1564 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1565 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1566 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1567 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1570 * If nfsd had anything else coalesced into it, transfer them
1571 * to owp, otherwise their replies will never get sent.
1573 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1574 p
= nfsd
->nd_coalesce
.lh_first
) {
1575 LIST_REMOVE(p
, nd_tq
);
1576 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1581 * Sort the group list in increasing numerical order.
1582 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1583 * that used to be here.)
1588 nfsrvw_sort(list
, num
)
1595 /* Insertion sort. */
1596 for (i
= 1; i
< num
; i
++) {
1598 /* find correct slot for value v, moving others up */
1599 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1600 list
[j
+ 1] = list
[j
];
1606 * copy credentials making sure that the result can be compared with bcmp().
1611 nfsrv_setcred(kauth_cred_t incred
, kauth_cred_t outcred
)
1615 bzero((caddr_t
)outcred
, sizeof (*outcred
));
1616 outcred
->cr_ref
= 1;
1617 outcred
->cr_uid
= kauth_cred_getuid(incred
);
1618 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1619 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1620 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1621 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1625 * nfs create service
1626 * now does a truncate to 0 length via. setattr if it already exists
1629 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1630 struct nfsrv_descript
*nfsd
;
1631 struct nfssvc_sock
*slp
;
1635 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1636 mbuf_t nam
= nfsd
->nd_nam
;
1637 caddr_t dpos
= nfsd
->nd_dpos
;
1638 struct nfs_fattr
*fp
;
1639 struct vnode_attr dirfor
, diraft
, postat
;
1640 struct vnode_attr va
;
1641 struct vnode_attr
*vap
= &va
;
1642 struct nfsv2_sattr
*sp
;
1644 struct nameidata nd
;
1648 int error
= 0, rdev
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1649 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1651 mbuf_t mb
, mb2
, mreq
;
1652 vnode_t vp
, dvp
, dirp
= NULL
;
1653 struct nfs_filehandle nfh
;
1654 struct nfs_export
*nx
;
1655 struct nfs_export_options
*nxo
;
1657 u_char cverf
[NFSX_V3CREATEVERF
];
1658 struct vfs_context context
;
1661 context
.vc_proc
= procp
;
1662 context
.vc_ucred
= nfsd
->nd_cr
;
1665 * Save the original credential UID in case they are
1666 * mapped and we need to map the IDs in the attributes.
1668 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1673 nd
.ni_cnd
.cn_nameiop
= 0;
1675 nfsm_srvmtofh(&nfh
);
1676 nfsm_srvnamesiz(len
, v3
);
1678 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1679 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1680 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
1682 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
1685 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
1686 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
1693 nd
.ni_cnd
.cn_nameiop
= 0;
1694 nfsm_reply(NFSX_WCCDATA(v3
));
1695 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1706 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1707 how
= fxdr_unsigned(int, *tl
);
1709 case NFSV3CREATE_GUARDED
:
1714 case NFSV3CREATE_UNCHECKED
:
1717 case NFSV3CREATE_EXCLUSIVE
:
1718 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1719 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1722 VATTR_SET(vap
, va_mode
, 0);
1725 VATTR_SET(vap
, va_type
, VREG
);
1729 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1730 v_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1733 VATTR_SET(vap
, va_type
, v_type
);
1734 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
1738 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1740 VATTR_SET(vap
, va_data_size
, (u_quad_t
)tsize
);
1745 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1753 * If it doesn't exist, create it
1754 * otherwise just truncate to 0 length
1755 * should I set the mode too ??
1758 kauth_acl_t xacl
= NULL
;
1761 * If the credentials were mapped, we should
1762 * map the same values in the attributes.
1764 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
1766 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
1767 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
1768 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
1771 /* authorize before creating */
1772 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
1774 /* construct ACL and handle inheritance */
1776 error
= kauth_acl_inherit(dvp
,
1782 if (!error
&& xacl
!= NULL
)
1783 VATTR_SET(vap
, va_acl
, xacl
);
1785 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1786 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
1788 /* validate new-file security information */
1790 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1791 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
1793 * Most NFS servers just ignore the UID/GID attributes, so we
1794 * try ignoring them if that'll help the request succeed.
1796 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1797 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1798 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1802 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1805 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1807 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
1809 * If some of the requested attributes weren't handled by the VNOP,
1810 * use our fallback code.
1812 error
= vnode_setattr_fallback(vp
, vap
, &context
);
1815 kauth_acl_free(xacl
);
1818 if (exclusive_flag
) {
1821 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
1823 VATTR_SET_ACTIVE(vap
, va_access_time
);
1824 // skip authorization, as this is an
1825 // NFS internal implementation detail.
1826 error
= vnode_setattr(vp
, vap
, &context
);
1830 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1831 vap
->va_type
== VFIFO
) {
1832 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
1833 VATTR_SET(vap
, va_type
, VFIFO
);
1834 if (vap
->va_type
!= VFIFO
&&
1835 (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
1838 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
1840 error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1843 kauth_acl_free(xacl
);
1853 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1854 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
1855 nd
.ni_cnd
.cn_context
= &context
;
1856 nd
.ni_startdir
= dvp
;
1858 error
= lookup(&nd
);
1860 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
1870 * nameidone has to happen before we vnode_put(dvp)
1871 * since it may need to release the fs_nodelock on the dvp
1874 nd
.ni_cnd
.cn_nameiop
= 0;
1879 * nameidone has to happen before we vnode_put(dvp)
1880 * since it may need to release the fs_nodelock on the dvp
1883 nd
.ni_cnd
.cn_nameiop
= 0;
1887 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
1888 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
1891 tempsize
= vap
->va_data_size
;
1893 VATTR_SET(vap
, va_data_size
, tempsize
);
1894 error
= vnode_setattr(vp
, vap
, &context
);
1899 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
1901 nfsm_srv_vattr_init(&postat
, v3
);
1902 error
= vnode_getattr(vp
, &postat
, &context
);
1909 if (exclusive_flag
&& !error
&&
1910 bcmp(cverf
, (caddr_t
)&postat
.va_access_time
, NFSX_V3CREATEVERF
))
1912 nfsm_srv_vattr_init(&diraft
, v3
);
1913 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
1917 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1921 nfsm_srvpostop_fh(&nfh
);
1922 nfsm_srvpostop_attr(0, &postat
);
1924 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1926 nfsm_srvfhtom(&nfh
, v3
);
1927 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1928 nfsm_srvfillattr(&postat
, fp
);
1932 if (nd
.ni_cnd
.cn_nameiop
) {
1934 * nameidone has to happen before we vnode_put(dvp)
1935 * since it may need to release the fs_nodelock on the dvp
1949 * nfs v3 mknod service
1952 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1953 struct nfsrv_descript
*nfsd
;
1954 struct nfssvc_sock
*slp
;
1958 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1959 mbuf_t nam
= nfsd
->nd_nam
;
1960 caddr_t dpos
= nfsd
->nd_dpos
;
1961 struct vnode_attr dirfor
, diraft
, postat
;
1962 struct vnode_attr va
;
1963 struct vnode_attr
*vap
= &va
;
1965 struct nameidata nd
;
1968 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1969 u_long major
, minor
;
1972 mbuf_t mb
, mb2
, mreq
;
1973 vnode_t vp
, dvp
, dirp
= NULL
;
1974 struct nfs_filehandle nfh
;
1975 struct nfs_export
*nx
;
1976 struct nfs_export_options
*nxo
;
1977 struct vfs_context hacked_context
; /* XXX should we have this? */
1978 struct vfs_context context
;
1980 kauth_acl_t xacl
= NULL
;
1982 context
.vc_proc
= procp
;
1983 context
.vc_ucred
= nfsd
->nd_cr
;
1984 hacked_context
.vc_proc
= procp
;
1985 hacked_context
.vc_ucred
= proc_ucred(procp
);
1988 * Save the original credential UID in case they are
1989 * mapped and we need to map the IDs in the attributes.
1991 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1994 nd
.ni_cnd
.cn_nameiop
= 0;
1995 nfsm_srvmtofh(&nfh
);
1996 nfsm_srvnamesiz(len
, 1);
1998 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1999 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2000 error
= nfsm_path_mbuftond(&md
, &dpos
, 1, FALSE
, &len
, &nd
);
2002 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2004 nfsm_srv_pre_vattr_init(&dirfor
, 1);
2005 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2008 nd
.ni_cnd
.cn_nameiop
= 0;
2009 nfsm_reply(NFSX_WCCDATA(1));
2010 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2018 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2019 vtyp
= nfsv3tov_type(*tl
);
2020 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
2021 error
= NFSERR_BADTYPE
;
2027 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
2028 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2029 major
= fxdr_unsigned(u_long
, *tl
++);
2030 minor
= fxdr_unsigned(u_long
, *tl
);
2031 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2035 * If it doesn't exist, create it.
2041 VATTR_SET(vap
, va_type
, vtyp
);
2044 * If the credentials were mapped, we should
2045 * map the same values in the attributes.
2047 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
2049 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
2050 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2051 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
2054 /* authorize before creating */
2055 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2057 /* construct ACL and handle inheritance */
2059 error
= kauth_acl_inherit(dvp
,
2065 if (!error
&& xacl
!= NULL
)
2066 VATTR_SET(vap
, va_acl
, xacl
);
2068 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2069 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2071 /* validate new-file security information */
2073 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2074 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
2076 * Most NFS servers just ignore the UID/GID attributes, so we
2077 * try ignoring them if that'll help the request succeed.
2079 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2080 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2081 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2085 if (vtyp
== VSOCK
) {
2086 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
2088 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2090 * If some of the requested attributes weren't handled by the VNOP,
2091 * use our fallback code.
2093 error
= vnode_setattr_fallback(vp
, vap
, &context
);
2095 if (vtyp
!= VFIFO
&& (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
2098 if ((error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
))) {
2106 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2107 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2108 nd
.ni_cnd
.cn_context
= &hacked_context
;
2109 nd
.ni_startdir
= dvp
;
2111 error
= lookup(&nd
);
2114 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
2120 kauth_acl_free(xacl
);
2123 * nameidone has to happen before we vnode_put(dvp)
2124 * since it may need to release the fs_nodelock on the dvp
2127 nd
.ni_cnd
.cn_nameiop
= 0;
2132 error
= nfsrv_vptofh(nx
, 0, NULL
, vp
, &context
, &nfh
);
2134 nfsm_srv_vattr_init(&postat
, 1);
2135 error
= vnode_getattr(vp
, &postat
, &context
);
2141 nfsm_srv_vattr_init(&diraft
, 1);
2142 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2146 nfsm_reply(NFSX_SRVFH(1, &nfh
) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2148 nfsm_srvpostop_fh(&nfh
);
2149 nfsm_srvpostop_attr(0, &postat
);
2151 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2154 if (nd
.ni_cnd
.cn_nameiop
) {
2156 * nameidone has to happen before we vnode_put(dvp)
2157 * since it may need to release the fs_nodelock on the dvp
2171 * nfs remove service
2174 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
2175 struct nfsrv_descript
*nfsd
;
2176 struct nfssvc_sock
*slp
;
2180 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2181 mbuf_t nam
= nfsd
->nd_nam
;
2182 caddr_t dpos
= nfsd
->nd_dpos
;
2183 struct nameidata nd
;
2187 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2188 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2191 vnode_t vp
, dvp
, dirp
= NULL
;
2192 struct vnode_attr dirfor
, diraft
;
2193 struct nfs_filehandle nfh
;
2194 struct nfs_export
*nx
;
2195 struct nfs_export_options
*nxo
;
2196 struct vfs_context context
;
2198 context
.vc_proc
= procp
;
2199 context
.vc_ucred
= nfsd
->nd_cr
;
2202 nfsm_srvmtofh(&nfh
);
2203 nfsm_srvnamesiz(len
, v3
);
2205 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2206 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2207 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2209 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2212 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2213 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2223 if (vnode_vtype(vp
) == VDIR
)
2224 error
= EPERM
; /* POSIX */
2225 else if (vnode_isvroot(vp
))
2227 * The root of a mounted filesystem cannot be deleted.
2231 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
2234 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, 0, &context
);
2237 * nameidone has to happen before we vnode_put(dvp)
2238 * since it may need to release the fs_nodelock on the dvp
2246 nfsm_srv_vattr_init(&diraft
, v3
);
2247 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2250 nfsm_reply(NFSX_WCCDATA(v3
));
2252 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2260 * nfs rename service
2263 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
2264 struct nfsrv_descript
*nfsd
;
2265 struct nfssvc_sock
*slp
;
2269 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2270 mbuf_t nam
= nfsd
->nd_nam
;
2271 caddr_t dpos
= nfsd
->nd_dpos
;
2272 kauth_cred_t saved_cred
= NULL
;
2276 int error
= 0, fromlen
, tolen
;
2277 int fdirfor_ret
= 1, fdiraft_ret
= 1;
2278 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2279 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2280 char *cp2
, *frompath
= NULL
, *topath
= NULL
;
2282 struct nameidata fromnd
, tond
;
2283 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
= NULL
;
2284 vnode_t tdirp
= NULL
;
2285 struct vnode_attr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2286 struct nfs_filehandle fnfh
, tnfh
;
2287 struct nfs_export
*fnx
, *tnx
;
2288 struct nfs_export_options
*fnxo
, *tnxo
;
2289 enum vtype fvtype
, tvtype
;
2290 int holding_mntlock
;
2292 struct vfs_context context
;
2294 context
.vc_proc
= procp
;
2295 context
.vc_ucred
= nfsd
->nd_cr
;
2302 * these need to be set before
2303 * calling any nfsm_xxxx macros
2304 * since they may take us out
2305 * through the error path
2307 holding_mntlock
= 0;
2312 nfsm_srvmtofh(&fnfh
);
2313 nfsm_srvnamesiz(fromlen
, v3
);
2314 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &fromlen
, &fromnd
);
2319 frompath
= fromnd
.ni_cnd
.cn_pnbuf
;
2320 nfsm_srvmtofh(&tnfh
);
2321 nfsm_strsiz(tolen
, NFS_MAXNAMLEN
, v3
);
2322 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &tolen
, &tond
);
2325 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2328 topath
= tond
.ni_cnd
.cn_pnbuf
;
2331 * Remember our original uid so that we can reset cr_uid before
2332 * the second nfs_namei() call, in case it is remapped.
2334 saved_cred
= nfsd
->nd_cr
;
2335 kauth_cred_ref(saved_cred
);
2337 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
2338 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
;
2340 fromnd
.ni_cnd
.cn_pnbuf
= frompath
;
2342 fromnd
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2343 fromnd
.ni_cnd
.cn_flags
|= HASBUF
;
2345 error
= nfs_namei(nfsd
, &context
, &fromnd
, &fnfh
, nam
, FALSE
, &fdirp
, &fnx
, &fnxo
);
2348 fdvp
= fromnd
.ni_dvp
;
2353 nfsm_srv_pre_vattr_init(&fdirfor
, v3
);
2354 fdirfor_ret
= vnode_getattr(fdirp
, &fdirfor
, &context
);
2360 fvtype
= vnode_vtype(fvp
);
2362 /* reset credential if it was remapped */
2363 if (nfsd
->nd_cr
!= saved_cred
) {
2364 kauth_cred_rele(nfsd
->nd_cr
);
2365 nfsd
->nd_cr
= saved_cred
;
2366 kauth_cred_ref(nfsd
->nd_cr
);
2369 tond
.ni_cnd
.cn_nameiop
= RENAME
;
2370 tond
.ni_cnd
.cn_flags
= WANTPARENT
;
2372 tond
.ni_cnd
.cn_pnbuf
= topath
;
2374 tond
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2375 tond
.ni_cnd
.cn_flags
|= HASBUF
;
2378 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2380 error
= nfs_namei(nfsd
, &context
, &tond
, &tnfh
, nam
, FALSE
, &tdirp
, &tnx
, &tnxo
);
2383 * Translate error code for rename("dir1", "dir2/.").
2385 if (error
== EISDIR
&& fvtype
== VDIR
) {
2398 nfsm_srv_pre_vattr_init(&tdirfor
, v3
);
2399 tdirfor_ret
= vnode_getattr(tdirp
, &tdirfor
, &context
);
2407 tvtype
= vnode_vtype(tvp
);
2409 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2415 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2422 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2441 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2442 * the node is moving between directories and we need rights to remove from the
2443 * old and add to the new.
2445 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2447 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2448 * implement the deferred-inherit bit.
2454 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2457 } else if (tdvp
!= fdvp
) {
2461 /* moving out of fdvp, must have delete rights */
2462 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
, fnxo
, 0)) != 0)
2464 /* moving into tdvp or tvp, must have rights to add */
2465 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2467 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2468 &context
, tnxo
, 0)) != 0)
2471 /* node staying in same directory, must be allowed to add new name */
2472 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2473 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2474 &context
, fnxo
, 0)) != 0)
2477 /* overwriting tvp */
2478 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2479 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
, tnxo
, 0)) != 0))
2482 /* XXX more checks? */
2485 /* authorization denied */
2490 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2491 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2499 * The following edge case is caught here:
2500 * (to cannot be a descendent of from)
2513 if (tdvp
->v_parent
== fvp
) {
2520 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2528 * If source is the same as the destination (that is the
2529 * same vnode) then there is nothing to do...
2530 * EXCEPT if the underlying file system supports case
2531 * insensitivity and is case preserving. In this case
2532 * the file system needs to handle the special case of
2533 * getting the same vnode as target (fvp) and source (tvp).
2535 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2536 * and _PC_CASE_PRESERVING can have this exception, and they need to
2537 * handle the special case of getting the same vnode as target and
2538 * source. NOTE: Then the target is unlocked going into vnop_rename,
2539 * so not to cause locking problems. There is a single reference on tvp.
2541 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2542 * that correct behaviour then is just to remove the source (link)
2544 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2545 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2546 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2547 fromnd
.ni_cnd
.cn_namelen
)) {
2552 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2554 * we're holding a reference and lock
2555 * on locked_mp, but it no longer matches
2556 * what we want to do... so drop our hold
2558 mount_unlock_renames(locked_mp
);
2559 mount_drop(locked_mp
, 0);
2560 holding_mntlock
= 0;
2562 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2564 * serialize renames that re-shape
2565 * the tree... if holding_mntlock is
2566 * set, then we're ready to go...
2568 * first need to drop the iocounts
2569 * we picked up, second take the
2570 * lock to serialize the access,
2571 * then finally start the lookup
2572 * process over with the lock held
2574 if (!holding_mntlock
) {
2576 * need to grab a reference on
2577 * the mount point before we
2578 * drop all the iocounts... once
2579 * the iocounts are gone, the mount
2582 locked_mp
= vnode_mount(fvp
);
2583 mount_ref(locked_mp
, 0);
2585 /* make a copy of to path to pass to nfs_namei() again */
2586 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2588 bcopy(tond
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2591 * nameidone has to happen before we vnode_put(tdvp)
2592 * since it may need to release the fs_nodelock on the tdvp
2600 /* make a copy of from path to pass to nfs_namei() again */
2601 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2603 bcopy(fromnd
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
2606 * nameidone has to happen before we vnode_put(fdvp)
2607 * since it may need to release the fs_nodelock on the fdvp
2622 mount_lock_renames(locked_mp
);
2623 holding_mntlock
= 1;
2628 fdirfor_ret
= tdirfor_ret
= 1;
2630 if (!topath
|| !frompath
) {
2631 /* we couldn't allocate a path, so bail */
2640 * when we dropped the iocounts to take
2641 * the lock, we allowed the identity of
2642 * the various vnodes to change... if they did,
2643 * we may no longer be dealing with a rename
2644 * that reshapes the tree... once we're holding
2645 * the iocounts, the vnodes can't change type
2646 * so we're free to drop the lock at this point
2649 if (holding_mntlock
) {
2650 mount_unlock_renames(locked_mp
);
2651 mount_drop(locked_mp
, 0);
2652 holding_mntlock
= 0;
2656 // save these off so we can later verify that fvp is the same
2659 oname
= fvp
->v_name
;
2660 oparent
= fvp
->v_parent
;
2662 error
= VNOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2663 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
, &context
);
2665 * fix up name & parent pointers. note that we first
2666 * check that fvp has the same name/parent pointers it
2667 * had before the rename call... this is a 'weak' check
2670 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
2672 update_flags
= VNODE_UPDATE_NAME
;
2674 update_flags
|= VNODE_UPDATE_PARENT
;
2675 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
2678 if (holding_mntlock
) {
2679 mount_unlock_renames(locked_mp
);
2680 mount_drop(locked_mp
, 0);
2681 holding_mntlock
= 0;
2685 * nameidone has to happen before we vnode_put(tdvp)
2686 * since it may need to release the fs_nodelock on the tdvp
2697 * nameidone has to happen before we vnode_put(fdvp)
2698 * since it may need to release the fs_nodelock on the fdvp
2709 nfsm_srv_vattr_init(&fdiraft
, v3
);
2710 fdiraft_ret
= vnode_getattr(fdirp
, &fdiraft
, &context
);
2715 nfsm_srv_vattr_init(&tdiraft
, v3
);
2716 tdiraft_ret
= vnode_getattr(tdirp
, &tdiraft
, &context
);
2720 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2722 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2723 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2726 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2728 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2730 kauth_cred_rele(saved_cred
);
2734 if (holding_mntlock
) {
2735 mount_unlock_renames(locked_mp
);
2736 mount_drop(locked_mp
, 0);
2740 * nameidone has to happen before we vnode_put(tdvp)
2741 * since it may need to release the fs_nodelock on the tdvp
2751 * nameidone has to happen before we vnode_put(fdvp)
2752 * since it may need to release the fs_nodelock on the fdvp
2765 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2767 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2769 kauth_cred_rele(saved_cred
);
2777 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2778 struct nfsrv_descript
*nfsd
;
2779 struct nfssvc_sock
*slp
;
2783 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2784 mbuf_t nam
= nfsd
->nd_nam
;
2785 caddr_t dpos
= nfsd
->nd_dpos
;
2786 struct nameidata nd
;
2790 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2791 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2794 vnode_t vp
, xp
, dvp
, dirp
= NULL
;
2795 struct vnode_attr dirfor
, diraft
, at
;
2796 struct nfs_filehandle nfh
, dnfh
;
2797 struct nfs_export
*nx
;
2798 struct nfs_export_options
*nxo
;
2799 struct vfs_context context
;
2801 vp
= xp
= dvp
= NULL
;
2802 nfsm_srvmtofh(&nfh
);
2803 nfsm_srvmtofh(&dnfh
);
2804 nfsm_srvnamesiz(len
, v3
);
2805 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
2806 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2807 nfsm_srvpostop_attr(getret
, &at
);
2808 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2811 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
2813 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2814 nfsm_srvpostop_attr(getret
, &at
);
2815 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2819 /* we're not allowed to link to directories... */
2820 if (vnode_vtype(vp
) == VDIR
) {
2821 error
= EPERM
; /* POSIX */
2825 context
.vc_proc
= procp
;
2826 context
.vc_ucred
= nfsd
->nd_cr
;
2828 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2829 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
, nxo
, 0)) != 0)
2832 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2833 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2834 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2836 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2839 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2840 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2853 else if (vnode_mount(vp
) != vnode_mount(dvp
))
2856 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2859 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
2862 * nameidone has to happen before we vnode_put(dvp)
2863 * since it may need to release the fs_nodelock on the dvp
2872 nfsm_srv_vattr_init(&at
, v3
);
2873 getret
= vnode_getattr(vp
, &at
, &context
);
2876 nfsm_srv_vattr_init(&diraft
, v3
);
2877 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2882 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2884 nfsm_srvpostop_attr(getret
, &at
);
2885 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2893 * nfs symbolic link service
2896 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2897 struct nfsrv_descript
*nfsd
;
2898 struct nfssvc_sock
*slp
;
2902 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2903 mbuf_t nam
= nfsd
->nd_nam
;
2904 caddr_t dpos
= nfsd
->nd_dpos
;
2905 struct vnode_attr dirfor
, diraft
, postat
;
2906 struct nameidata nd
;
2907 struct vnode_attr va
;
2908 struct vnode_attr
*vap
= &va
;
2911 struct nfsv2_sattr
*sp
;
2912 char *bpos
, *linkdata
= NULL
, *cp2
;
2913 int error
= 0, len
, linkdatalen
;
2914 int dirfor_ret
= 1, diraft_ret
= 1;
2915 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2916 mbuf_t mb
, mreq
, mb2
;
2917 vnode_t vp
, dvp
, dirp
= NULL
;
2918 struct nfs_filehandle nfh
;
2919 struct nfs_export
*nx
;
2920 struct nfs_export_options
*nxo
;
2922 char uio_buf
[ UIO_SIZEOF(1) ];
2923 struct vfs_context context
;
2926 context
.vc_proc
= procp
;
2927 context
.vc_ucred
= nfsd
->nd_cr
;
2930 * Save the original credential UID in case they are
2931 * mapped and we need to map the IDs in the attributes.
2933 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
2935 nd
.ni_cnd
.cn_nameiop
= 0;
2937 nfsm_srvmtofh(&nfh
);
2938 nfsm_srvnamesiz(len
, v3
);
2940 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2941 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2942 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2944 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2947 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2948 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2955 nd
.ni_cnd
.cn_nameiop
= 0;
2964 nfsm_strsiz(linkdatalen
, NFS_MAXPATHLEN
, v3
);
2965 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
2968 nd
.ni_cnd
.cn_nameiop
= 0;
2969 vnode_put(nd
.ni_dvp
);
2970 vnode_put(nd
.ni_vp
);
2974 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
2975 &uio_buf
[0], sizeof(uio_buf
));
2978 nd
.ni_cnd
.cn_nameiop
= 0;
2979 vnode_put(nd
.ni_dvp
);
2980 vnode_put(nd
.ni_vp
);
2984 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
2985 nfsm_mtouio(auio
, linkdatalen
);
2987 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2988 VATTR_SET(vap
, va_mode
, fxdr_unsigned(u_short
, sp
->sa_mode
));
2990 *(linkdata
+ linkdatalen
) = '\0';
2997 * If the credentials were mapped, we should
2998 * map the same values in the attributes.
3000 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
3002 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
3003 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3004 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
3006 VATTR_SET(vap
, va_type
, VLNK
);
3007 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3008 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3010 /* authorize before creating */
3011 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
3013 /* validate given attributes */
3015 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3016 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3018 * Most NFS servers just ignore the UID/GID attributes, so we
3019 * try ignoring them if that'll help the request succeed.
3021 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3022 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3023 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3027 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, vap
, linkdata
, &context
);
3031 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3032 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3033 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3034 nd
.ni_cnd
.cn_context
= &context
;
3035 nd
.ni_startdir
= dvp
;
3037 error
= lookup(&nd
);
3042 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3044 nfsm_srv_vattr_init(&postat
, v3
);
3045 error
= vnode_getattr(vp
, &postat
, &context
);
3051 * nameidone has to happen before we vnode_put(dvp)
3052 * since it may need to release the fs_nodelock on the dvp
3055 nd
.ni_cnd
.cn_nameiop
= 0;
3062 FREE(linkdata
, M_TEMP
);
3064 nfsm_srv_vattr_init(&diraft
, v3
);
3065 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3068 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3071 nfsm_srvpostop_fh(&nfh
);
3072 nfsm_srvpostop_attr(0, &postat
);
3074 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3078 if (nd
.ni_cnd
.cn_nameiop
) {
3080 * nameidone has to happen before we vnode_put(dvp)
3081 * since it may need to release the fs_nodelock on the dvp
3092 FREE(linkdata
, M_TEMP
);
3100 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
3101 struct nfsrv_descript
*nfsd
;
3102 struct nfssvc_sock
*slp
;
3106 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3107 mbuf_t nam
= nfsd
->nd_nam
;
3108 caddr_t dpos
= nfsd
->nd_dpos
;
3109 struct vnode_attr dirfor
, diraft
, postat
;
3110 struct vnode_attr va
;
3111 struct vnode_attr
*vap
= &va
;
3112 struct nfs_fattr
*fp
;
3113 struct nameidata nd
;
3119 int dirfor_ret
= 1, diraft_ret
= 1;
3120 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3122 mbuf_t mb
, mb2
, mreq
;
3123 vnode_t vp
, dvp
, dirp
= NULL
;
3124 struct nfs_filehandle nfh
;
3125 struct nfs_export
*nx
;
3126 struct nfs_export_options
*nxo
;
3127 struct vfs_context context
;
3129 kauth_acl_t xacl
= NULL
;
3131 context
.vc_proc
= procp
;
3132 context
.vc_ucred
= nfsd
->nd_cr
;
3135 * Save the original credential UID in case they are
3136 * mapped and we need to map the IDs in the attributes.
3138 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
3140 nd
.ni_cnd
.cn_nameiop
= 0;
3142 nfsm_srvmtofh(&nfh
);
3143 nfsm_srvnamesiz(len
, v3
);
3145 nd
.ni_cnd
.cn_nameiop
= CREATE
;
3146 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
3147 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3149 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3152 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3153 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3160 nd
.ni_cnd
.cn_nameiop
= 0;
3161 nfsm_reply(NFSX_WCCDATA(v3
));
3162 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3174 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3175 VATTR_SET(vap
, va_mode
, nfstov_mode(*tl
++));
3177 VATTR_SET(vap
, va_type
, VDIR
);
3181 * nameidone has to happen before we vnode_put(dvp)
3182 * since it may need to release the fs_nodelock on the dvp
3193 * If the credentials were mapped, we should
3194 * map the same values in the attributes.
3196 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
3198 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
3199 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3200 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
3203 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, &context
, nxo
, 0);
3205 /* construct ACL and handle inheritance */
3207 error
= kauth_acl_inherit(dvp
,
3213 if (!error
&& xacl
!= NULL
)
3214 VATTR_SET(vap
, va_acl
, xacl
);
3216 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3217 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3219 /* validate new-file security information */
3221 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3222 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3224 * Most NFS servers just ignore the UID/GID attributes, so we
3225 * try ignoring them if that'll help the request succeed.
3227 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3228 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3229 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3234 error
= VNOP_MKDIR(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
3236 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3238 * If some of the requested attributes weren't handled by the VNOP,
3239 * use our fallback code.
3241 error
= vnode_setattr_fallback(vp
, vap
, &context
);
3244 kauth_acl_free(xacl
);
3247 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3249 nfsm_srv_vattr_init(&postat
, v3
);
3250 error
= vnode_getattr(vp
, &postat
, &context
);
3256 * nameidone has to happen before we vnode_put(dvp)
3257 * since it may need to release the fs_nodelock on the dvp
3263 nd
.ni_cnd
.cn_nameiop
= 0;
3266 nfsm_srv_vattr_init(&diraft
, v3
);
3267 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3270 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3273 nfsm_srvpostop_fh(&nfh
);
3274 nfsm_srvpostop_attr(0, &postat
);
3276 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3278 nfsm_srvfhtom(&nfh
, v3
);
3279 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
3280 nfsm_srvfillattr(&postat
, fp
);
3284 if (nd
.ni_cnd
.cn_nameiop
) {
3286 * nameidone has to happen before we vnode_put(dvp)
3287 * since it may need to release the fs_nodelock on the dvp
3303 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
3304 struct nfsrv_descript
*nfsd
;
3305 struct nfssvc_sock
*slp
;
3309 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3310 mbuf_t nam
= nfsd
->nd_nam
;
3311 caddr_t dpos
= nfsd
->nd_dpos
;
3316 int dirfor_ret
= 1, diraft_ret
= 1;
3317 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3320 vnode_t vp
, dvp
, dirp
= NULL
;
3321 struct vnode_attr dirfor
, diraft
;
3322 struct nfs_filehandle nfh
;
3323 struct nfs_export
*nx
;
3324 struct nfs_export_options
*nxo
;
3325 struct nameidata nd
;
3326 struct vfs_context context
;
3328 context
.vc_proc
= procp
;
3329 context
.vc_ucred
= nfsd
->nd_cr
;
3332 nfsm_srvmtofh(&nfh
);
3333 nfsm_srvnamesiz(len
, v3
);
3335 nd
.ni_cnd
.cn_nameiop
= DELETE
;
3336 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3337 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3339 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3342 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3343 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3350 nfsm_reply(NFSX_WCCDATA(v3
));
3351 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3359 if (vnode_vtype(vp
) != VDIR
) {
3364 * No rmdir "." please.
3371 * The root of a mounted filesystem cannot be deleted.
3373 if (vnode_isvroot(vp
))
3376 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
3378 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
3381 * nameidone has to happen before we vnode_put(dvp)
3382 * since it may need to release the fs_nodelock on the dvp
3390 nfsm_srv_vattr_init(&diraft
, v3
);
3391 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3394 nfsm_reply(NFSX_WCCDATA(v3
));
3396 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3404 * nfs readdir service
3405 * - mallocs what it thinks is enough to read
3406 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3407 * - calls VNOP_READDIR()
3408 * - loops around building the reply
3409 * if the output generated exceeds count break out of loop
3410 * The nfsm_clget macro is used here so that the reply will be packed
3411 * tightly in mbuf clusters.
3412 * - it only knows that it has encountered eof when the VNOP_READDIR()
3414 * - as such one readdir rpc will return eof false although you are there
3415 * and then the next will return eof
3416 * - it trims out records with d_fileno == 0
3417 * this doesn't matter for Unix clients, but they might confuse clients
3419 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3420 * than requested, but this may not apply to all filesystems. For
3421 * example, client NFS does not { although it is never remote mounted
3423 * The alternate call nfsrv_readdirplus() does lookups as well.
3424 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3425 * are supposed to cover. For readdir, the count is the total number of
3426 * bytes included in everything from the directory's postopattr through
3427 * the EOF flag. For readdirplus, the maxcount is the same, and the
3428 * dircount includes all that except for the entry attributes and handles.
3432 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
3433 struct nfsrv_descript
*nfsd
;
3434 struct nfssvc_sock
*slp
;
3438 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3439 mbuf_t nam
= nfsd
->nd_nam
;
3440 caddr_t dpos
= nfsd
->nd_dpos
;
3443 struct direntry
*dp
;
3448 mbuf_t mb
, mb2
, mreq
, mp2
;
3449 char *cpos
, *cend
, *cp2
, *rbuf
;
3451 struct vnode_attr at
;
3452 struct nfs_filehandle nfh
;
3453 struct nfs_export
*nx
;
3454 struct nfs_export_options
*nxo
;
3456 char uio_buf
[ UIO_SIZEOF(1) ];
3457 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3458 int siz
, count
, fullsiz
, eofflag
, nentries
= 0;
3459 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3460 u_quad_t off
, toff
, verf
;
3463 struct vfs_context context
;
3465 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3467 nfsm_srvmtofh(&nfh
);
3469 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
3470 fxdr_hyper(tl
, &toff
);
3472 fxdr_hyper(tl
, &verf
);
3475 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3476 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
3479 count
= fxdr_unsigned(int, *tl
);
3480 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3481 xfer
= NFS_SRVMAXDATA(nfsd
);
3485 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3486 nfsm_reply(NFSX_UNSIGNED
);
3487 nfsm_srvpostop_attr(getret
, &at
);
3490 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3492 nfsm_reply(NFSX_UNSIGNED
);
3493 nfsm_srvpostop_attr(getret
, &at
);
3496 context
.vc_proc
= procp
;
3497 context
.vc_ucred
= nfsd
->nd_cr
;
3498 if (!v3
|| (nxo
->nxo_flags
& NX_32BITCLIENTS
))
3499 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3501 nfsm_srv_vattr_init(&at
, v3
);
3502 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3503 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3504 error
= NFSERR_BAD_COOKIE
;
3507 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3510 nfsm_reply(NFSX_POSTOPATTR(v3
));
3511 nfsm_srvpostop_attr(getret
, &at
);
3514 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3518 nfsm_reply(NFSX_POSTOPATTR(v3
));
3519 nfsm_srvpostop_attr(getret
, &at
);
3522 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3523 &uio_buf
[0], sizeof(uio_buf
));
3528 nfsm_reply(NFSX_POSTOPATTR(v3
));
3529 nfsm_srvpostop_attr(getret
, &at
);
3533 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3534 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3537 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3538 off
= uio_offset(auio
);
3541 nfsm_srv_vattr_init(&at
, v3
);
3542 getret
= vnode_getattr(vp
, &at
, &context
);
3549 nfsm_reply(NFSX_POSTOPATTR(v3
));
3550 nfsm_srvpostop_attr(getret
, &at
);
3553 if (uio_resid(auio
) != 0) {
3554 // LP64todo - fix this
3555 siz
-= uio_resid(auio
);
3558 * If nothing read, return eof
3563 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
3566 nfsm_srvpostop_attr(getret
, &at
);
3567 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3568 txdr_hyper(&at
.va_filerev
, tl
);
3571 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3580 * Check for degenerate cases of nothing useful read.
3581 * If so go try again
3585 dp
= (struct direntry
*)cpos
;
3586 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3587 cpos
+= dp
->d_reclen
;
3588 dp
= (struct direntry
*)cpos
;
3591 if (cpos
>= cend
|| nentries
== 0) {
3598 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
3600 len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3601 nfsm_srvpostop_attr(getret
, &at
);
3602 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3603 txdr_hyper(&at
.va_filerev
, tl
);
3605 len
= 2 * NFSX_UNSIGNED
;
3608 be
= bp
+ mbuf_trailingspace(mp
);
3610 /* Loop through the records and build reply */
3611 while (cpos
< cend
&& nentries
> 0) {
3612 if (dp
->d_fileno
!= 0) {
3613 nlen
= dp
->d_namlen
;
3614 if (!v3
&& (nlen
> NFS_MAXNAMLEN
))
3615 nlen
= NFS_MAXNAMLEN
;
3616 rem
= nfsm_rndup(nlen
)-nlen
;
3617 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
3619 len
+= 2 * NFSX_UNSIGNED
;
3625 * Build the directory record xdr from
3626 * the direntry entry.
3630 bp
+= NFSX_UNSIGNED
;
3633 txdr_hyper(&dp
->d_fileno
, &tquad
);
3634 *tl
= tquad
.nfsuquad
[0];
3635 bp
+= NFSX_UNSIGNED
;
3637 *tl
= tquad
.nfsuquad
[1];
3638 bp
+= NFSX_UNSIGNED
;
3640 *tl
= txdr_unsigned(dp
->d_fileno
);
3641 bp
+= NFSX_UNSIGNED
;
3644 *tl
= txdr_unsigned(nlen
);
3645 bp
+= NFSX_UNSIGNED
;
3647 /* And loop around copying the name */
3656 bcopy(cp
, bp
, tsiz
);
3662 /* And null pad to a long boundary */
3663 for (i
= 0; i
< rem
; i
++)
3666 /* Finish off the record with the cookie */
3669 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3670 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3671 txdr_hyper(&dp
->d_seekoff
, &tquad
);
3672 *tl
= tquad
.nfsuquad
[0];
3673 bp
+= NFSX_UNSIGNED
;
3675 *tl
= tquad
.nfsuquad
[1];
3676 bp
+= NFSX_UNSIGNED
;
3678 *tl
= txdr_unsigned(dp
->d_seekoff
);
3679 bp
+= NFSX_UNSIGNED
;
3682 cpos
+= dp
->d_reclen
;
3683 dp
= (struct direntry
*)cpos
;
3688 bp
+= NFSX_UNSIGNED
;
3694 bp
+= NFSX_UNSIGNED
;
3697 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
3699 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
3708 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
3711 u_long fl_nfh
[NFSX_V3FHMAX
/ sizeof (u_long
)];
3715 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
3716 struct nfsrv_descript
*nfsd
;
3717 struct nfssvc_sock
*slp
;
3721 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3722 mbuf_t nam
= nfsd
->nd_nam
;
3723 caddr_t dpos
= nfsd
->nd_dpos
;
3726 struct direntry
*dp
;
3731 mbuf_t mb
, mb2
, mreq
, mp2
;
3732 char *cpos
, *cend
, *cp2
, *rbuf
;
3735 struct nfs_filehandle dnfh
, *nfhp
= (struct nfs_filehandle
*)&fl
.fl_fhsize
;
3736 struct nfs_export
*nx
;
3737 struct nfs_export_options
*nxo
;
3739 char uio_buf
[ UIO_SIZEOF(1) ];
3740 struct vnode_attr va
, at
, *vap
= &va
;
3741 struct nfs_fattr
*fp
;
3742 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3743 int siz
, count
, fullsiz
, eofflag
, dirlen
, nentries
= 0, isdotdot
;
3744 u_quad_t off
, toff
, verf
;
3747 struct vfs_context context
;
3749 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3751 nfsm_srvmtofh(&dnfh
);
3752 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
3753 fxdr_hyper(tl
, &toff
);
3755 fxdr_hyper(tl
, &verf
);
3757 siz
= fxdr_unsigned(int, *tl
++);
3758 count
= fxdr_unsigned(int, *tl
);
3760 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3761 xfer
= NFS_SRVMAXDATA(nfsd
);
3765 if ((error
= nfsrv_fhtovp(&dnfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3766 nfsm_reply(NFSX_UNSIGNED
);
3767 nfsm_srvpostop_attr(getret
, &at
);
3770 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3772 nfsm_reply(NFSX_UNSIGNED
);
3773 nfsm_srvpostop_attr(getret
, &at
);
3776 context
.vc_proc
= procp
;
3777 context
.vc_ucred
= nfsd
->nd_cr
;
3778 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
3779 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3780 nfsm_srv_vattr_init(&at
, 1);
3781 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3782 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3783 error
= NFSERR_BAD_COOKIE
;
3785 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3789 nfsm_reply(NFSX_V3POSTOPATTR
);
3790 nfsm_srvpostop_attr(getret
, &at
);
3793 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3798 nfsm_reply(NFSX_V3POSTOPATTR
);
3799 nfsm_srvpostop_attr(getret
, &at
);
3802 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3803 &uio_buf
[0], sizeof(uio_buf
));
3809 nfsm_reply(NFSX_V3POSTOPATTR
);
3810 nfsm_srvpostop_attr(getret
, &at
);
3814 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3815 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3817 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3818 off
= uio_offset(auio
);
3819 nfsm_srv_vattr_init(&at
, 1);
3820 getret
= vnode_getattr(vp
, &at
, &context
);
3828 nfsm_reply(NFSX_V3POSTOPATTR
);
3829 nfsm_srvpostop_attr(getret
, &at
);
3832 if (uio_resid(auio
) != 0) {
3833 // LP64todo - fix this
3834 siz
-= uio_resid(auio
);
3837 * If nothing read, return eof
3843 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3845 nfsm_srvpostop_attr(getret
, &at
);
3846 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3847 txdr_hyper(&at
.va_filerev
, tl
);
3857 * Check for degenerate cases of nothing useful read.
3858 * If so go try again
3862 dp
= (struct direntry
*)cpos
;
3863 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3864 cpos
+= dp
->d_reclen
;
3865 dp
= (struct direntry
*)cpos
;
3868 if (cpos
>= cend
|| nentries
== 0) {
3875 * Probe one of the directory entries to see if the filesystem
3878 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))) {
3879 if (error
== ENOTSUP
) /* let others get passed back */
3880 error
= NFSERR_NOTSUPP
;
3884 nfsm_reply(NFSX_V3POSTOPATTR
);
3885 nfsm_srvpostop_attr(getret
, &at
);
3890 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3892 nfsm_srvpostop_attr(getret
, &at
);
3893 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3894 txdr_hyper(&at
.va_filerev
, tl
);
3897 be
= bp
+ mbuf_trailingspace(mp
);
3899 /* Loop through the records and build reply */
3900 while (cpos
< cend
&& nentries
> 0) {
3901 if (dp
->d_fileno
!= 0) {
3902 nlen
= dp
->d_namlen
;
3903 rem
= nfsm_rndup(nlen
)-nlen
;
3906 * Got to get the vnode for lookup per entry.
3908 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))
3910 isdotdot
= ((dp
->d_namlen
== 2) &&
3911 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
3912 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, &context
, nfhp
)) {
3913 // XXX file handle is optional, so we should be able to
3914 // XXX return this entry without the file handle
3918 nfsm_srv_vattr_init(vap
, 1);
3919 if (vnode_getattr(nvp
, vap
, &context
)) {
3920 // XXX attributes are optional, so we should be able to
3921 // XXX return this entry without the attributes
3928 * If either the dircount or maxcount will be
3929 * exceeded, get out now. Both of these lengths
3930 * are calculated conservatively, including all
3933 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ nfhp
->nfh_len
+
3935 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3936 if (len
> count
|| dirlen
> fullsiz
) {
3942 * Build the directory record xdr from
3943 * the direntry entry.
3945 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3946 nfsm_srvfillattr(vap
, fp
);
3947 fl
.fl_fhsize
= txdr_unsigned(nfhp
->nfh_len
);
3948 fl
.fl_fhok
= nfs_true
;
3949 fl
.fl_postopok
= nfs_true
;
3950 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3951 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3952 txdr_hyper(&dp
->d_seekoff
, &fl
.fl_off
);
3956 bp
+= NFSX_UNSIGNED
;
3959 txdr_hyper(&dp
->d_fileno
, &tquad
);
3960 *tl
= tquad
.nfsuquad
[0];
3961 bp
+= NFSX_UNSIGNED
;
3963 *tl
= tquad
.nfsuquad
[1];
3964 bp
+= NFSX_UNSIGNED
;
3967 *tl
= txdr_unsigned(nlen
);
3968 bp
+= NFSX_UNSIGNED
;
3970 /* And loop around copying the name */
3975 if ((bp
+ xfer
) > be
)
3979 bcopy(cp
, bp
, tsiz
);
3985 /* And null pad to a long boundary */
3986 for (i
= 0; i
< rem
; i
++)
3990 * Now copy the flrep structure out.
3992 xfer
= sizeof(struct flrep
) - sizeof(fl
.fl_nfh
) + fl
.fl_fhsize
;
3996 if ((bp
+ xfer
) > be
)
4000 bcopy(cp
, bp
, tsiz
);
4008 cpos
+= dp
->d_reclen
;
4009 dp
= (struct direntry
*)cpos
;
4016 bp
+= NFSX_UNSIGNED
;
4022 bp
+= NFSX_UNSIGNED
;
4025 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
4027 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
4036 * nfs commit service
4039 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
4040 struct nfsrv_descript
*nfsd
;
4041 struct nfssvc_sock
*slp
;
4045 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4046 mbuf_t nam
= nfsd
->nd_nam
;
4047 caddr_t dpos
= nfsd
->nd_dpos
;
4048 struct vnode_attr bfor
, aft
;
4050 struct nfs_filehandle nfh
;
4051 struct nfs_export
*nx
;
4052 struct nfs_export_options
*nxo
;
4056 int error
= 0, for_ret
= 1, aft_ret
= 1, count
;
4058 mbuf_t mb
, mb2
, mreq
;
4060 struct vfs_context context
;
4062 nfsm_srvmtofh(&nfh
);
4063 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
4066 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4067 * count parameters, so these arguments are useless (someday maybe).
4069 fxdr_hyper(tl
, &off
);
4071 count
= fxdr_unsigned(int, *tl
);
4072 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4073 nfsm_reply(2 * NFSX_UNSIGNED
);
4074 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4077 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4079 nfsm_reply(2 * NFSX_UNSIGNED
);
4080 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4083 context
.vc_proc
= procp
;
4084 context
.vc_ucred
= nfsd
->nd_cr
;
4086 nfsm_srv_pre_vattr_init(&bfor
, 1);
4087 for_ret
= vnode_getattr(vp
, &bfor
, &context
);
4088 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
4089 nfsm_srv_vattr_init(&aft
, 1);
4090 aft_ret
= vnode_getattr(vp
, &aft
, &context
);
4092 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4093 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4095 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
4096 *tl
++ = txdr_unsigned(boottime_sec());
4097 *tl
= txdr_unsigned(0);
4105 * nfs statfs service
4108 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
4109 struct nfsrv_descript
*nfsd
;
4110 struct nfssvc_sock
*slp
;
4114 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4115 mbuf_t nam
= nfsd
->nd_nam
;
4116 caddr_t dpos
= nfsd
->nd_dpos
;
4118 struct nfs_statfs
*sfp
;
4122 int error
= 0, getret
= 1;
4123 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
4125 mbuf_t mb
, mb2
, mreq
;
4127 struct vnode_attr at
;
4128 struct nfs_filehandle nfh
;
4129 struct nfs_export
*nx
;
4130 struct nfs_export_options
*nxo
;
4133 struct vfs_context context
;
4135 nfsm_srvmtofh(&nfh
);
4136 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4137 nfsm_reply(NFSX_UNSIGNED
);
4138 nfsm_srvpostop_attr(getret
, &at
);
4141 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4143 nfsm_reply(NFSX_UNSIGNED
);
4144 nfsm_srvpostop_attr(getret
, &at
);
4147 context
.vc_proc
= procp
;
4148 context
.vc_ucred
= nfsd
->nd_cr
;
4151 VFSATTR_WANTED(&va
, f_blocks
);
4152 VFSATTR_WANTED(&va
, f_bavail
);
4153 VFSATTR_WANTED(&va
, f_files
);
4154 VFSATTR_WANTED(&va
, f_ffree
);
4155 error
= vfs_getattr(vnode_mount(vp
), &va
, &context
);
4156 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4157 nfsm_srv_vattr_init(&at
, v3
);
4158 getret
= vnode_getattr(vp
, &at
, &context
);
4160 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
4162 nfsm_srvpostop_attr(getret
, &at
);
4165 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
4167 tval
= (u_quad_t
)(va
.f_blocks
* blksize
);
4168 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
4169 tval
= (u_quad_t
)(va
.f_bfree
* blksize
);
4170 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
4171 tval
= (u_quad_t
)(va
.f_bavail
* blksize
);
4172 txdr_hyper(&tval
, &sfp
->sf_abytes
);
4173 txdr_hyper(&va
.f_files
, &sfp
->sf_tfiles
);
4174 txdr_hyper(&va
.f_ffree
, &sfp
->sf_ffiles
);
4175 txdr_hyper(&va
.f_ffree
, &sfp
->sf_afiles
);
4176 sfp
->sf_invarsec
= 0;
4178 sfp
->sf_tsize
= txdr_unsigned(NFS_V2MAXDATA
);
4179 sfp
->sf_bsize
= txdr_unsigned((unsigned)blksize
);
4180 sfp
->sf_blocks
= txdr_unsigned((unsigned)va
.f_blocks
);
4181 sfp
->sf_bfree
= txdr_unsigned((unsigned)va
.f_bfree
);
4182 sfp
->sf_bavail
= txdr_unsigned((unsigned)va
.f_bavail
);
4189 * nfs fsinfo service
4192 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
4193 struct nfsrv_descript
*nfsd
;
4194 struct nfssvc_sock
*slp
;
4198 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4199 mbuf_t nam
= nfsd
->nd_nam
;
4200 caddr_t dpos
= nfsd
->nd_dpos
;
4202 struct nfsv3_fsinfo
*sip
;
4205 int error
= 0, getret
= 1, prefsize
, maxsize
;
4207 mbuf_t mb
, mb2
, mreq
;
4209 struct vnode_attr at
;
4210 struct nfs_filehandle nfh
;
4211 struct nfs_export
*nx
;
4212 struct nfs_export_options
*nxo
;
4213 struct vfs_context context
;
4215 nfsm_srvmtofh(&nfh
);
4216 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4217 nfsm_reply(NFSX_UNSIGNED
);
4218 nfsm_srvpostop_attr(getret
, &at
);
4221 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4223 nfsm_reply(NFSX_UNSIGNED
);
4224 nfsm_srvpostop_attr(getret
, &at
);
4227 context
.vc_proc
= procp
;
4228 context
.vc_ucred
= nfsd
->nd_cr
;
4230 nfsm_srv_vattr_init(&at
, 1);
4231 getret
= vnode_getattr(vp
, &at
, &context
);
4233 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4234 nfsm_srvpostop_attr(getret
, &at
);
4235 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
4239 * There should be file system VFS OP(s) to get this information.
4240 * For now, assume our usual NFS defaults.
4242 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4243 maxsize
= NFS_MAXDGRAMDATA
;
4244 prefsize
= NFS_PREFDGRAMDATA
;
4246 maxsize
= prefsize
= NFS_MAXDATA
;
4247 sip
->fs_rtmax
= txdr_unsigned(maxsize
);
4248 sip
->fs_rtpref
= txdr_unsigned(prefsize
);
4249 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4250 sip
->fs_wtmax
= txdr_unsigned(maxsize
);
4251 sip
->fs_wtpref
= txdr_unsigned(prefsize
);
4252 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4253 sip
->fs_dtpref
= txdr_unsigned(prefsize
);
4254 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
4255 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
4256 sip
->fs_timedelta
.nfsv3_sec
= 0;
4257 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
4258 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
4259 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
4260 NFSV3FSINFO_CANSETTIME
);
4266 * nfs pathconf service
4269 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
4270 struct nfsrv_descript
*nfsd
;
4271 struct nfssvc_sock
*slp
;
4275 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4276 mbuf_t nam
= nfsd
->nd_nam
;
4277 caddr_t dpos
= nfsd
->nd_dpos
;
4279 struct nfsv3_pathconf
*pc
;
4282 int error
= 0, getret
= 1, linkmax
, namemax
;
4283 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4285 mbuf_t mb
, mb2
, mreq
;
4287 struct vnode_attr at
;
4288 struct nfs_filehandle nfh
;
4289 struct nfs_export
*nx
;
4290 struct nfs_export_options
*nxo
;
4291 struct vfs_context context
;
4293 nfsm_srvmtofh(&nfh
);
4294 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4295 nfsm_reply(NFSX_UNSIGNED
);
4296 nfsm_srvpostop_attr(getret
, &at
);
4299 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4301 nfsm_reply(NFSX_UNSIGNED
);
4302 nfsm_srvpostop_attr(getret
, &at
);
4305 context
.vc_proc
= procp
;
4306 context
.vc_ucred
= nfsd
->nd_cr
;
4308 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, &context
);
4310 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, &context
);
4312 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, &context
);
4314 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, &context
);
4316 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, &context
);
4318 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, &context
);
4319 nfsm_srv_vattr_init(&at
, 1);
4320 getret
= vnode_getattr(vp
, &at
, &context
);
4322 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4323 nfsm_srvpostop_attr(getret
, &at
);
4326 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
4328 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
4329 pc
->pc_namemax
= txdr_unsigned(namemax
);
4330 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
4331 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
4332 pc
->pc_caseinsensitive
= txdr_unsigned(!case_sensitive
);
4333 pc
->pc_casepreserving
= txdr_unsigned(case_preserving
);
4340 * Null operation, used by clients to ping server
4345 struct nfsrv_descript
*nfsd
,
4346 struct nfssvc_sock
*slp
,
4347 __unused proc_t procp
,
4350 mbuf_t mrep
= nfsd
->nd_mrep
;
4352 int error
= NFSERR_RETVOID
;
4361 * No operation, used for obsolete procedures
4366 struct nfsrv_descript
*nfsd
,
4367 struct nfssvc_sock
*slp
,
4368 __unused proc_t procp
,
4371 mbuf_t mrep
= nfsd
->nd_mrep
;
4376 if (nfsd
->nd_repstat
)
4377 error
= nfsd
->nd_repstat
;
4379 error
= EPROCUNAVAIL
;
4386 * Perform access checking for vnodes obtained from file handles that would
4387 * refer to files already opened by a Unix client. You cannot just use
4388 * vnode_authorize() for two reasons.
4389 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4390 * 2 - The owner is to be given access irrespective of mode bits so that
4391 * processes that chmod after opening a file don't break. I don't like
4392 * this because it opens a security hole, but since the nfs server opens
4393 * a security hole the size of a barn door anyhow, what the heck.
4395 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4396 * will return EPERM instead of EACCESS. EPERM is always an error.
4403 kauth_action_t action
,
4404 vfs_context_t context
,
4405 struct nfs_export_options
*nxo
,
4408 struct vnode_attr vattr
;
4411 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
4413 * Disallow write attempts on read-only exports;
4414 * unless the file is a socket or a block or character
4415 * device resident on the file system.
4417 if (nxo
->nxo_flags
& NX_READONLY
) {
4418 switch (vnode_vtype(vp
)) {
4419 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
4426 error
= vnode_authorize(vp
, dvp
, action
, context
);
4428 * Allow certain operations for the owner (reads and writes
4429 * on files that are already open). Picking up from FreeBSD.
4431 if (override
&& (error
== EACCES
)) {
4433 VATTR_WANTED(&vattr
, va_uid
);
4434 if ((vnode_getattr(vp
, &vattr
, context
) == 0) &&
4435 (kauth_cred_getuid(vfs_context_ucred(context
)) == vattr
.va_uid
))
4440 #endif /* NFS_NOSERVER */