]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
04c0aee42b42148915dc35d78a91fd63e09d8da6
[apple/xnu.git] / bsd / nfs / nfs_serv.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
51 *
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
62 * SUCH DAMAGE.
63 *
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 $
66 */
67
68 /*
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
75 * nb:
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
78 *
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
83 * a reply.
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.
86 */
87
88 #include <sys/param.h>
89 #include <sys/systm.h>
90 #include <sys/proc.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>
103 #include <sys/ubc.h>
104 #include <sys/vnode_internal.h>
105 #include <sys/uio_internal.h>
106 #include <libkern/OSAtomic.h>
107
108 #include <sys/vm.h>
109 #include <sys/vmparam.h>
110
111 #include <nfs/nfsproto.h>
112 #include <nfs/rpcv2.h>
113 #include <nfs/nfs.h>
114 #include <nfs/xdr_subs.h>
115 #include <nfs/nfsm_subs.h>
116
117 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
118 NFFIFO, NFNON };
119 #ifndef NFS_NOSERVER
120 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
121 NFCHR, NFNON };
122 /* Global vars */
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;
127
128 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
129 int nfsrvw_procrastinate_v3 = 0;
130
131 int nfs_async = 0;
132 #ifdef notyet
133 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
134 SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "");
135 #endif
136
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 *);
139
140 #define THREAD_SAFE_FS(VP) \
141 ((VP)->v_mount ? (VP)->v_mount->mnt_vtable->vfc_threadsafe : 0)
142
143 /*
144 * nfs v3 access service
145 */
146 int
147 nfsrv3_access(nfsd, slp, procp, mrq)
148 struct nfsrv_descript *nfsd;
149 struct nfssvc_sock *slp;
150 proc_t procp;
151 mbuf_t *mrq;
152 {
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;
156 vnode_t vp;
157 struct nfs_filehandle nfh;
158 u_long *tl;
159 long t1;
160 caddr_t bpos;
161 int error = 0, getret;
162 char *cp2;
163 mbuf_t mb, mreq, mb2;
164 struct vnode_attr vattr, *vap = &vattr;
165 u_long nfsmode;
166 kauth_action_t testaction;
167 struct vfs_context context;
168 struct nfs_export *nx;
169 struct nfs_export_options *nxo;
170
171 nfsm_srvmtofh(&nfh);
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);
176 return (0);
177 }
178 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
179 vnode_put(vp);
180 nfsm_reply(NFSX_UNSIGNED);
181 nfsm_srvpostop_attr(1, NULL);
182 return (0);
183 }
184 nfsmode = fxdr_unsigned(u_long, *tl);
185
186 context.vc_proc = procp;
187 context.vc_ucred = nfsd->nd_cr;
188
189 /*
190 * Each NFS mode bit is tested separately.
191 *
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.
196 */
197 if (nfsmode & NFSV3ACCESS_READ) {
198 if (vnode_isdir(vp)) {
199 testaction =
200 KAUTH_VNODE_LIST_DIRECTORY |
201 KAUTH_VNODE_READ_EXTATTRIBUTES;
202 } else {
203 testaction =
204 KAUTH_VNODE_READ_DATA |
205 KAUTH_VNODE_READ_EXTATTRIBUTES;
206 }
207 if (nfsrv_authorize(vp, NULL, testaction, &context, nxo, 0))
208 nfsmode &= ~NFSV3ACCESS_READ;
209 }
210 if ((nfsmode & NFSV3ACCESS_LOOKUP) &&
211 (!vnode_isdir(vp) ||
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)) {
216 testaction =
217 KAUTH_VNODE_ADD_FILE |
218 KAUTH_VNODE_ADD_SUBDIRECTORY |
219 KAUTH_VNODE_DELETE_CHILD;
220 } else {
221 testaction =
222 KAUTH_VNODE_WRITE_DATA;
223 }
224 if (nfsrv_authorize(vp, NULL, testaction, &context, nxo, 0))
225 nfsmode &= ~NFSV3ACCESS_MODIFY;
226 }
227 if (nfsmode & NFSV3ACCESS_EXTEND) {
228 if (vnode_isdir(vp)) {
229 testaction =
230 KAUTH_VNODE_ADD_FILE |
231 KAUTH_VNODE_ADD_SUBDIRECTORY;
232 } else {
233 testaction =
234 KAUTH_VNODE_WRITE_DATA |
235 KAUTH_VNODE_APPEND_DATA;
236 }
237 if (nfsrv_authorize(vp, NULL, testaction, &context, nxo, 0))
238 nfsmode &= ~NFSV3ACCESS_EXTEND;
239 }
240
241 /*
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.
250 */
251
252 if ((nfsmode & NFSV3ACCESS_EXECUTE) &&
253 (vnode_isdir(vp) ||
254 nfsrv_authorize(vp, NULL, KAUTH_VNODE_EXECUTE, &context, nxo, 0)))
255 nfsmode &= ~NFSV3ACCESS_EXECUTE;
256
257 nfsm_srv_vattr_init(vap, 1);
258 getret = vnode_getattr(vp, vap, &context);
259 vnode_put(vp);
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);
264 nfsmout:
265 return (error);
266 }
267
268 /*
269 * nfs getattr service
270 */
271 int
272 nfsrv_getattr(nfsd, slp, procp, mrq)
273 struct nfsrv_descript *nfsd;
274 struct nfssvc_sock *slp;
275 proc_t procp;
276 mbuf_t *mrq;
277 {
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;
284 vnode_t vp;
285 struct nfs_filehandle nfh;
286 u_long *tl;
287 long t1;
288 caddr_t bpos;
289 int error = 0;
290 char *cp2;
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);
296
297 nfsm_srvmtofh(&nfh);
298 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
299 nfsm_reply(0);
300 return (0);
301 }
302 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
303 vnode_put(vp);
304 nfsm_reply(0);
305 return (0);
306 }
307 context.vc_proc = procp;
308 context.vc_ucred = nfsd->nd_cr;
309
310 nfsm_srv_vattr_init(vap, v3);
311 error = vnode_getattr(vp, vap, &context);
312 vnode_put(vp);
313 nfsm_reply(NFSX_FATTR(v3));
314 if (error)
315 return (0);
316 nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(v3));
317 nfsm_srvfillattr(vap, fp);
318 nfsmout:
319 return (error);
320 }
321
322 /*
323 * nfs setattr service
324 */
325 int
326 nfsrv_setattr(nfsd, slp, procp, mrq)
327 struct nfsrv_descript *nfsd;
328 struct nfssvc_sock *slp;
329 proc_t procp;
330 mbuf_t *mrq;
331 {
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;
341 vnode_t vp;
342 struct nfs_filehandle nfh;
343 struct nfs_export *nx;
344 struct nfs_export_options *nxo;
345 u_long *tl;
346 long t1;
347 caddr_t bpos;
348 int error = 0, preat_ret = 1, postat_ret = 1;
349 int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
350 char *cp2;
351 mbuf_t mb, mb2, mreq;
352 struct timespec guard;
353 struct vfs_context context;
354 kauth_action_t action;
355 uid_t saved_uid;
356
357 nfsm_srvmtofh(&nfh);
358 VATTR_INIT(vap);
359 if (v3) {
360 nfsm_srvsattr(vap);
361 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
362 gcheck = fxdr_unsigned(int, *tl);
363 if (gcheck) {
364 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
365 fxdr_nfsv3time(tl, &guard);
366 }
367 } else {
368 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
369 /*
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
375 */
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);
387 }
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);
391 }
392 }
393
394 /*
395 * Save the original credential UID in case they are
396 * mapped and we need to map the IDs in the attributes.
397 */
398 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
399
400 /*
401 * Now that we have all the fields, lets do it.
402 */
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);
406 return (0);
407 }
408 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
409 vnode_put(vp);
410 nfsm_reply(2 * NFSX_UNSIGNED);
411 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &postat);
412 return (0);
413 }
414
415 context.vc_proc = procp;
416 context.vc_ucred = nfsd->nd_cr;
417
418 if (v3) {
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))
426 preat_ret = 1;
427 if (error) {
428 vnode_put(vp);
429 nfsm_reply(NFSX_WCCDATA(v3));
430 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &postat);
431 return (0);
432 }
433 }
434
435 /*
436 * If the credentials were mapped, we should
437 * map the same values in the attributes.
438 */
439 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
440 int ismember;
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));
444 }
445
446 /*
447 * Authorize the attribute changes.
448 */
449 if (((error = vnode_authattr(vp, vap, &action, &context))) ||
450 ((error = nfsrv_authorize(vp, NULL, action, &context, nxo, 0))))
451 goto out;
452 error = vnode_setattr(vp, vap, &context);
453
454 nfsm_srv_vattr_init(&postat, v3);
455 postat_ret = vnode_getattr(vp, &postat, &context);
456 if (!error)
457 error = postat_ret;
458 out:
459 vnode_put(vp);
460 nfsm_reply(NFSX_WCCORFATTR(v3));
461 if (v3) {
462 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &postat);
463 return (0);
464 } else {
465 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
466 nfsm_srvfillattr(&postat, fp);
467 }
468 nfsmout:
469 return (error);
470 }
471
472 /*
473 * nfs lookup rpc
474 */
475 int
476 nfsrv_lookup(nfsd, slp, procp, mrq)
477 struct nfsrv_descript *nfsd;
478 struct nfssvc_sock *slp;
479 proc_t procp;
480 mbuf_t *mrq;
481 {
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;
490 #endif
491 vnode_t vp, dirp = NULL;
492 struct nfs_filehandle dnfh, nfh;
493 struct nfs_export *nx;
494 struct nfs_export_options *nxo;
495 caddr_t cp;
496 u_long *tl;
497 long t1;
498 caddr_t bpos;
499 int error = 0, len, dirattr_ret = 1, isdotdot;
500 int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
501 char *cp2;
502 mbuf_t mb, mb2, mreq;
503 struct vnode_attr va, dirattr, *vap = &va;
504 struct vfs_context context;
505
506 context.vc_proc = procp;
507 context.vc_ucred = nfsd->nd_cr;
508
509 nfsm_srvmtofh(&dnfh);
510 nfsm_srvnamesiz(len, v3);
511
512 pubflag = nfs_ispublicfh(&dnfh);
513
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] == '.'));
518 if (!error)
519 error = nfs_namei(nfsd, &context, &nd, &dnfh, nam, pubflag, &dirp, &nx, &nxo);
520
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) {
525 /*
526 * Setup call to lookup() to see if we can find
527 * the index file. Arguably, this doesn't belong
528 * in a kernel.. Ugh.
529 */
530 ind = nd;
531 ind.ni_pathlen = strlen(nfs_pub.np_index);
532 ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf =
533 nfs_pub.np_index;
534 ind.ni_startdir = nd.ni_vp;
535 ind.ni_usedvp = nd.ni_vp;
536
537 if (!(error = lookup(&ind))) {
538 /*
539 * Found an index file. Get rid of
540 * the old references.
541 */
542 if (dirp)
543 vnode_put(dirp);
544 dirp = nd.ni_vp;
545 vnode_put(nd.ni_startdir);
546 ndp = &ind;
547 } else
548 error = 0;
549 }
550 /*
551 * If the public filehandle was used, check that this lookup
552 * didn't result in a filehandle outside the publicly exported
553 * filesystem.
554 */
555
556 if (!error && vnode_mount(ndp->ni_vp) != nfs_pub.np_mount) {
557 vnode_put(nd.ni_vp);
558 nameidone(&nd);
559 error = EPERM;
560 }
561 }
562 #endif
563
564 if (dirp) {
565 if (v3) {
566 nfsm_srv_vattr_init(&dirattr, v3);
567 dirattr_ret = vnode_getattr(dirp, &dirattr, &context);
568 }
569 vnode_put(dirp);
570 }
571
572 if (error) {
573 nfsm_reply(NFSX_POSTOPATTR(v3));
574 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
575 return (0);
576 }
577 nameidone(&nd);
578
579 vp = ndp->ni_vp;
580 error = nfsrv_vptofh(nx, !v3, (isdotdot ? &dnfh : NULL), vp, &context, &nfh);
581 if (!error) {
582 nfsm_srv_vattr_init(vap, v3);
583 error = vnode_getattr(vp, vap, &context);
584 }
585 vnode_put(vp);
586 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
587 if (error) {
588 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
589 return (0);
590 }
591 nfsm_srvfhtom(&nfh, v3);
592 if (v3) {
593 nfsm_srvpostop_attr(0, vap);
594 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
595 } else {
596 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
597 nfsm_srvfillattr(vap, fp);
598 }
599 nfsmout:
600 return (error);
601 }
602
603 /*
604 * nfs readlink service
605 */
606 int
607 nfsrv_readlink(nfsd, slp, procp, mrq)
608 struct nfsrv_descript *nfsd;
609 struct nfssvc_sock *slp;
610 proc_t procp;
611 mbuf_t *mrq;
612 {
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;
616 mbuf_t mp;
617 u_long *tl;
618 long t1;
619 caddr_t bpos;
620 int error = 0, i, tlen, len, getret = 1;
621 int v3 = (nfsd->nd_flag & ND_NFSV3);
622 char *cp2;
623 mbuf_t mb, mb2, mp2, mp3, mreq;
624 vnode_t vp;
625 struct vnode_attr attr;
626 struct nfs_filehandle nfh;
627 struct nfs_export *nx;
628 struct nfs_export_options *nxo;
629 uio_t uiop = NULL;
630 char uio_buf[ UIO_SIZEOF(4) ];
631 char *uio_bufp = &uio_buf[0];
632 int uio_buflen = UIO_SIZEOF(4);
633 int mblen;
634 struct vfs_context context;
635
636 nfsm_srvmtofh(&nfh);
637 len = 0;
638 i = 0;
639
640 mp2 = mp3 = NULL;
641 vp = NULL;
642 while (len < NFS_MAXPATHLEN) {
643 mp = NULL;
644 if ((error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mp)))
645 goto out;
646 mblen = mbuf_maxlen(mp);
647 mbuf_setlen(mp, mblen);
648 if (len == 0)
649 mp3 = mp2 = mp;
650 else {
651 if ((error = mbuf_setnext(mp2, mp))) {
652 mbuf_free(mp);
653 goto out;
654 }
655 mp2 = mp;
656 }
657 if ((len + mblen) > NFS_MAXPATHLEN) {
658 mbuf_setlen(mp, NFS_MAXPATHLEN - len);
659 len = NFS_MAXPATHLEN;
660 } else
661 len += mblen;
662 i++;
663 }
664 if (i > 4) {
665 uio_buflen = UIO_SIZEOF(i);
666 MALLOC(uio_bufp, char*, uio_buflen, M_TEMP, M_WAITOK);
667 if (!uio_bufp) {
668 error = ENOMEM;
669 mbuf_freem(mp3);
670 nfsm_reply(2 * NFSX_UNSIGNED);
671 nfsm_srvpostop_attr(1, NULL);
672 return (0);
673 }
674 }
675 uiop = uio_createwithbuffer(i, 0, UIO_SYSSPACE, UIO_READ, uio_bufp, uio_buflen);
676 if (!uiop) {
677 error = ENOMEM;
678 mbuf_freem(mp3);
679 if (uio_bufp != &uio_buf[0]) {
680 FREE(uio_bufp, M_TEMP);
681 uio_bufp = &uio_buf[0];
682 }
683 nfsm_reply(2 * NFSX_UNSIGNED);
684 nfsm_srvpostop_attr(1, NULL);
685 return (0);
686 }
687 mp = mp3;
688 while (mp) {
689 uio_addiov(uiop, CAST_USER_ADDR_T((caddr_t)mbuf_data(mp)), mbuf_len(mp));
690 mp = mbuf_next(mp);
691 }
692
693 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
694 mbuf_freem(mp3);
695 if (uio_bufp != &uio_buf[0]) {
696 FREE(uio_bufp, M_TEMP);
697 uio_bufp = &uio_buf[0];
698 }
699 nfsm_reply(2 * NFSX_UNSIGNED);
700 nfsm_srvpostop_attr(1, NULL);
701 return (0);
702 }
703 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
704 vnode_put(vp);
705 mbuf_freem(mp3);
706 if (uio_bufp != &uio_buf[0]) {
707 FREE(uio_bufp, M_TEMP);
708 uio_bufp = &uio_buf[0];
709 }
710 nfsm_reply(2 * NFSX_UNSIGNED);
711 nfsm_srvpostop_attr(1, NULL);
712 return (0);
713 }
714 if (vnode_vtype(vp) != VLNK) {
715 if (v3)
716 error = EINVAL;
717 else
718 error = ENXIO;
719 goto out;
720 }
721
722 context.vc_proc = procp;
723 context.vc_ucred = nfsd->nd_cr;
724
725 if ((error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_READ_DATA, &context, nxo, 0)))
726 goto out;
727 error = VNOP_READLINK(vp, uiop, &context);
728 out:
729 if (vp) {
730 if (v3) {
731 nfsm_srv_vattr_init(&attr, v3);
732 getret = vnode_getattr(vp, &attr, &context);
733 }
734 vnode_put(vp);
735 }
736 if (error) {
737 mbuf_freem(mp3);
738 mp3 = NULL;
739 }
740 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
741 if (v3) {
742 nfsm_srvpostop_attr(getret, &attr);
743 if (error) {
744 if (uio_bufp != &uio_buf[0])
745 FREE(uio_bufp, M_TEMP);
746 return (0);
747 }
748 }
749 if (!error) {
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);
755 }
756 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
757 *tl = txdr_unsigned(len);
758 mbuf_setnext(mb, mp3);
759 }
760 nfsmout:
761 if (uio_bufp != &uio_buf[0])
762 FREE(uio_bufp, M_TEMP);
763 return (error);
764 }
765
766 /*
767 * nfs read service
768 */
769 int
770 nfsrv_read(nfsd, slp, procp, mrq)
771 struct nfsrv_descript *nfsd;
772 struct nfssvc_sock *slp;
773 proc_t procp;
774 mbuf_t *mrq;
775 {
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;
779 mbuf_t m;
780 struct nfs_fattr *fp;
781 u_long *tl;
782 long t1;
783 int i;
784 caddr_t bpos;
785 int error = 0, count, len, left, siz, tlen, getret;
786 int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen, maxlen;
787 char *cp2;
788 mbuf_t mb, mb2, mreq;
789 mbuf_t m2;
790 vnode_t vp;
791 struct nfs_filehandle nfh;
792 struct nfs_export *nx;
793 struct nfs_export_options *nxo;
794 uio_t uiop = NULL;
795 char *uio_bufp = NULL;
796 struct vnode_attr va, *vap = &va;
797 off_t off;
798 char uio_buf[ UIO_SIZEOF(0) ];
799 struct vfs_context context;
800
801 nfsm_srvmtofh(&nfh);
802 if (v3) {
803 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
804 fxdr_hyper(tl, &off);
805 } else {
806 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
807 off = (off_t)fxdr_unsigned(u_long, *tl);
808 }
809 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
810 reqlen = fxdr_unsigned(u_long, *tl);
811 maxlen = NFS_SRVMAXDATA(nfsd);
812 if (reqlen > maxlen)
813 reqlen = maxlen;
814
815 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
816 nfsm_reply(2 * NFSX_UNSIGNED);
817 nfsm_srvpostop_attr(1, NULL);
818 return (0);
819 }
820 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
821 vnode_put(vp);
822 nfsm_reply(2 * NFSX_UNSIGNED);
823 nfsm_srvpostop_attr(1, NULL);
824 return (0);
825 }
826 if (vnode_vtype(vp) != VREG) {
827 if (v3)
828 error = EINVAL;
829 else
830 error = (vnode_vtype(vp) == VDIR) ? EISDIR : EACCES;
831 }
832
833 context.vc_proc = procp;
834 context.vc_ucred = nfsd->nd_cr;
835
836 if (!error) {
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);
839 }
840 nfsm_srv_vattr_init(vap, v3);
841 getret = vnode_getattr(vp, vap, &context);
842 if (!error)
843 error = getret;
844 if (error) {
845 vnode_put(vp);
846 nfsm_reply(NFSX_POSTOPATTR(v3));
847 nfsm_srvpostop_attr(getret, vap);
848 return (0);
849 }
850 if ((u_quad_t)off >= vap->va_data_size)
851 count = 0;
852 else if (((u_quad_t)off + reqlen) > vap->va_data_size)
853 count = nfsm_rndup(vap->va_data_size - off);
854 else
855 count = reqlen;
856 nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(count));
857 if (v3) {
858 nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
859 *tl++ = nfs_true;
860 fp = (struct nfs_fattr *)tl;
861 tl += (NFSX_V3FATTR / sizeof (u_long));
862 } else {
863 nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
864 fp = (struct nfs_fattr *)tl;
865 tl += (NFSX_V2FATTR / sizeof (u_long));
866 }
867 len = left = count;
868 if (count > 0) {
869 /*
870 * Generate the mbuf list with the uio_iov ref. to it.
871 */
872 i = 0;
873 m = m2 = mb;
874 while (left > 0) {
875 siz = min(mbuf_trailingspace(m), left);
876 if (siz > 0) {
877 left -= siz;
878 i++;
879 }
880 if (left > 0) {
881 m = NULL;
882 if ((error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &m)))
883 goto errorexit;
884 mbuf_setnext(m2, m);
885 m2 = m;
886 }
887 }
888 MALLOC(uio_bufp, char *, UIO_SIZEOF(i), M_TEMP, M_WAITOK);
889 if (!uio_bufp) {
890 error = ENOMEM;
891 goto errorexit;
892 }
893 uiop = uio_createwithbuffer(i, off, UIO_SYSSPACE, UIO_READ,
894 uio_bufp, UIO_SIZEOF(i));
895 if (!uiop) {
896 error = ENOMEM;
897 goto errorexit;
898 }
899 m = mb;
900 left = count;
901 i = 0;
902 while (left > 0) {
903 if (m == NULL)
904 panic("nfsrv_read iov");
905 siz = min(mbuf_trailingspace(m), left);
906 if (siz > 0) {
907 tlen = mbuf_len(m);
908 uio_addiov(uiop, CAST_USER_ADDR_T((char *)mbuf_data(m) + tlen), siz);
909 mbuf_setlen(m, tlen + siz);
910 left -= siz;
911 i++;
912 }
913 m = mbuf_next(m);
914 }
915 error = VNOP_READ(vp, uiop, IO_NODELOCKED, &context);
916 off = uio_offset(uiop);
917 errorexit:
918 /*
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.
924 *
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.
928 */
929 nfsm_srv_vattr_init(vap, v3);
930 if (error || (getret = vnode_getattr(vp, vap, &context))) {
931 if (!error)
932 error = getret;
933 mbuf_freem(mreq);
934 vnode_put(vp);
935 nfsm_reply(NFSX_POSTOPATTR(v3));
936 nfsm_srvpostop_attr(getret, vap);
937 if (uio_bufp != NULL) {
938 FREE(uio_bufp, M_TEMP);
939 }
940 return (0);
941 }
942 } else {
943 uiop = uio_createwithbuffer(0, 0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf));
944 if (!uiop) {
945 error = ENOMEM;
946 goto errorexit;
947 }
948 }
949 vnode_put(vp);
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);
956 if (v3) {
957 *tl++ = txdr_unsigned(len);
958 if (len < reqlen)
959 *tl++ = nfs_true;
960 else
961 *tl++ = nfs_false;
962 }
963 *tl = txdr_unsigned(len);
964 nfsmout:
965 if (uio_bufp != NULL) {
966 FREE(uio_bufp, M_TEMP);
967 }
968 return (error);
969 }
970
971 /*
972 * nfs write service
973 */
974 int
975 nfsrv_write(nfsd, slp, procp, mrq)
976 struct nfsrv_descript *nfsd;
977 struct nfssvc_sock *slp;
978 proc_t procp;
979 mbuf_t *mrq;
980 {
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;
984 int i, count;
985 mbuf_t mp;
986 struct nfs_fattr *fp;
987 struct vnode_attr va, forat;
988 struct vnode_attr *vap = &va;
989 u_long *tl;
990 long t1;
991 caddr_t bpos, tpos;
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);
996 char *cp2;
997 mbuf_t mb, mb2, mreq;
998 vnode_t vp;
999 struct nfs_filehandle nfh;
1000 struct nfs_export *nx;
1001 struct nfs_export_options *nxo;
1002 uio_t uiop;
1003 off_t off;
1004 char *uio_bufp = NULL;
1005 struct vfs_context context;
1006
1007 if (mrep == NULL) {
1008 *mrq = NULL;
1009 return (0);
1010 }
1011 nfsm_srvmtofh(&nfh);
1012 if (v3) {
1013 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
1014 fxdr_hyper(tl, &off);
1015 tl += 3;
1016 stable = fxdr_unsigned(int, *tl++);
1017 } else {
1018 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1019 off = (off_t)fxdr_unsigned(u_long, *++tl);
1020 tl += 2;
1021 if (nfs_async)
1022 stable = NFSV3WRITE_UNSTABLE;
1023 }
1024 retlen = len = fxdr_unsigned(long, *tl);
1025 count = i = 0;
1026
1027 /*
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.
1031 */
1032 if (len > 0) {
1033 zeroing = 1;
1034 mp = mrep;
1035 while (mp) {
1036 if (mp == md) {
1037 zeroing = 0;
1038 tpos = mbuf_data(mp);
1039 tlen = mbuf_len(mp);
1040 adjust = dpos - tpos;
1041 tlen -= adjust;
1042 mbuf_setlen(mp, tlen);
1043 if (tlen > 0 && adjust > 0) {
1044 tpos += adjust;
1045 if ((error = mbuf_setdata(mp, tpos, tlen))) {
1046 nfsm_reply(2 * NFSX_UNSIGNED);
1047 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
1048 return (0);
1049 }
1050 }
1051 }
1052 if (zeroing)
1053 mbuf_setlen(mp, 0);
1054 else if ((tlen = mbuf_len(mp)) > 0) {
1055 i += tlen;
1056 if (i > len) {
1057 mbuf_setlen(mp, tlen - (i - len));
1058 zeroing = 1;
1059 }
1060 if (mbuf_len(mp) > 0)
1061 count++;
1062 }
1063 mp = mbuf_next(mp);
1064 }
1065 }
1066 if (len > NFS_MAXDATA || len < 0 || i < len) {
1067 error = EIO;
1068 nfsm_reply(2 * NFSX_UNSIGNED);
1069 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
1070 return (0);
1071 }
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);
1075 return (0);
1076 }
1077 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
1078 vnode_put(vp);
1079 nfsm_reply(2 * NFSX_UNSIGNED);
1080 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
1081 return (0);
1082 }
1083 context.vc_proc = procp;
1084 context.vc_ucred = nfsd->nd_cr;
1085
1086 if (v3) {
1087 nfsm_srv_pre_vattr_init(&forat, v3);
1088 forat_ret = vnode_getattr(vp, &forat, &context);
1089 }
1090 if (vnode_vtype(vp) != VREG) {
1091 if (v3)
1092 error = EINVAL;
1093 else
1094 error = (vnode_vtype(vp) == VDIR) ? EISDIR : EACCES;
1095 }
1096 if (!error) {
1097 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA, &context, nxo, 1);
1098 }
1099 if (error) {
1100 vnode_put(vp);
1101 nfsm_reply(NFSX_WCCDATA(v3));
1102 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
1103 return (0);
1104 }
1105
1106 if (len > 0) {
1107 MALLOC(uio_bufp, char *, UIO_SIZEOF(count), M_TEMP, M_WAITOK);
1108 if (!uio_bufp) {
1109 error = ENOMEM;
1110 vnode_put(vp);
1111 nfsm_reply(NFSX_WCCDATA(v3));
1112 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
1113 return (0);
1114 }
1115 uiop = uio_createwithbuffer(count, off, UIO_SYSSPACE, UIO_WRITE, uio_bufp, UIO_SIZEOF(count));
1116 if (!uiop) {
1117 error = ENOMEM;
1118 vnode_put(vp);
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);
1123 }
1124 return (0);
1125 }
1126 mp = mrep;
1127 while (mp) {
1128 if ((tlen = mbuf_len(mp)) > 0)
1129 uio_addiov(uiop, CAST_USER_ADDR_T((caddr_t)mbuf_data(mp)), tlen);
1130 mp = mbuf_next(mp);
1131 }
1132
1133 /*
1134 * XXX
1135 * The IO_METASYNC flag indicates that all metadata (and not just
1136 * enough to ensure data integrity) mus be written to stable storage
1137 * synchronously.
1138 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1139 */
1140 if (stable == NFSV3WRITE_UNSTABLE)
1141 ioflags = IO_NODELOCKED;
1142 else if (stable == NFSV3WRITE_DATASYNC)
1143 ioflags = (IO_SYNC | IO_NODELOCKED);
1144 else
1145 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1146
1147 error = VNOP_WRITE(vp, uiop, ioflags, &context);
1148 OSAddAtomic(1, (SInt32*)(SInt32*)&nfsstats.srvvop_writes);
1149 }
1150 nfsm_srv_vattr_init(vap, v3);
1151 aftat_ret = vnode_getattr(vp, vap, &context);
1152 vnode_put(vp);
1153 if (!error)
1154 error = aftat_ret;
1155 nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
1156 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
1157 if (v3) {
1158 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
1159 if (error) {
1160 if (uio_bufp != NULL) {
1161 FREE(uio_bufp, M_TEMP);
1162 }
1163 return (0);
1164 }
1165 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1166 *tl++ = txdr_unsigned(retlen);
1167 /*
1168 * If nfs_async is set, then pretend the write was FILESYNC.
1169 */
1170 if (stable == NFSV3WRITE_UNSTABLE && !nfs_async)
1171 *tl++ = txdr_unsigned(stable);
1172 else
1173 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
1174 /* write verifier */
1175 *tl++ = txdr_unsigned(boottime_sec());
1176 *tl = txdr_unsigned(0);
1177 } else {
1178 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1179 nfsm_srvfillattr(vap, fp);
1180 }
1181 nfsmout:
1182 if (uio_bufp != NULL) {
1183 FREE(uio_bufp, M_TEMP);
1184 }
1185 return (error);
1186 }
1187
1188 /*
1189 * NFS write service with write gathering support. Called when
1190 * nfsrvw_procrastinate > 0.
1191 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1192 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1193 * Jan. 1994.
1194 */
1195 int
1196 nfsrv_writegather(ndp, slp, procp, mrq)
1197 struct nfsrv_descript **ndp;
1198 struct nfssvc_sock *slp;
1199 proc_t procp;
1200 mbuf_t *mrq;
1201 {
1202 mbuf_t mp;
1203 struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1204 struct nfs_export *nx;
1205 struct nfs_export_options *nxo;
1206 struct nfs_fattr *fp;
1207 int i;
1208 struct nfsrvw_delayhash *wpp;
1209 kauth_cred_t cred;
1210 struct vnode_attr va, forat;
1211 u_long *tl;
1212 long t1;
1213 caddr_t bpos, dpos, tpos;
1214 int error = 0, len, forat_ret = 1;
1215 int ioflags, aftat_ret = 1, adjust, v3, zeroing, tlen;
1216 char *cp2;
1217 mbuf_t mb, mb2, mreq, mrep, md;
1218 vnode_t vp;
1219 uio_t uiop = NULL;
1220 char *uio_bufp = NULL;
1221 u_quad_t cur_usec;
1222 struct timeval now;
1223 struct vfs_context context;
1224
1225 context.vc_proc = procp;
1226
1227 #ifndef nolint
1228 i = 0;
1229 len = 0;
1230 #endif
1231
1232 *mrq = NULL;
1233 if (*ndp) {
1234 nfsd = *ndp;
1235 *ndp = NULL;
1236 mrep = nfsd->nd_mrep;
1237 md = nfsd->nd_md;
1238 dpos = nfsd->nd_dpos;
1239 cred = nfsd->nd_cr;
1240 context.vc_ucred = cred;
1241 v3 = (nfsd->nd_flag & ND_NFSV3);
1242 LIST_INIT(&nfsd->nd_coalesce);
1243 nfsd->nd_mreq = NULL;
1244 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1245 microuptime(&now);
1246 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1247 nfsd->nd_time = cur_usec +
1248 (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
1249
1250 /*
1251 * Now, get the write header..
1252 */
1253 nfsm_srvmtofh(&nfsd->nd_fh);
1254 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1255 if (v3) {
1256 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
1257 fxdr_hyper(tl, &nfsd->nd_off);
1258 tl += 3;
1259 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1260 } else {
1261 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1262 nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
1263 tl += 2;
1264 if (nfs_async)
1265 nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1266 }
1267 len = fxdr_unsigned(long, *tl);
1268 nfsd->nd_len = len;
1269 nfsd->nd_eoff = nfsd->nd_off + len;
1270
1271 /*
1272 * Trim the header out of the mbuf list and trim off any trailing
1273 * junk so that the mbuf list has only the write data.
1274 */
1275 zeroing = 1;
1276 i = 0;
1277 mp = mrep;
1278 while (mp) {
1279 if (mp == md) {
1280 zeroing = 0;
1281 tpos = mbuf_data(mp);
1282 tlen = mbuf_len(mp);
1283 adjust = dpos - tpos;
1284 tlen -= adjust;
1285 mbuf_setlen(mp, tlen);
1286 if (tlen > 0 && adjust > 0) {
1287 tpos += adjust;
1288 if ((error = mbuf_setdata(mp, tpos, tlen)))
1289 goto nfsmout;
1290 }
1291 }
1292 if (zeroing)
1293 mbuf_setlen(mp, 0);
1294 else {
1295 tlen = mbuf_len(mp);
1296 i += tlen;
1297 if (i > len) {
1298 mbuf_setlen(mp, tlen - (i - len));
1299 zeroing = 1;
1300 }
1301 }
1302 mp = mbuf_next(mp);
1303 }
1304 if (len > NFS_MAXDATA || len < 0 || i < len) {
1305 nfsmout:
1306 mbuf_freem(mrep);
1307 mrep = NULL;
1308 error = EIO;
1309 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1310 if (v3)
1311 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1312 nfsd->nd_mreq = mreq;
1313 nfsd->nd_mrep = NULL;
1314 nfsd->nd_time = 1;
1315 }
1316
1317 /*
1318 * Add this entry to the hash and time queues.
1319 */
1320 lck_mtx_lock(&slp->ns_wgmutex);
1321 owp = NULL;
1322 wp = slp->ns_tq.lh_first;
1323 while (wp && wp->nd_time < nfsd->nd_time) {
1324 owp = wp;
1325 wp = wp->nd_tq.le_next;
1326 }
1327 if (owp) {
1328 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1329 } else {
1330 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1331 }
1332 if (nfsd->nd_mrep) {
1333 wpp = NWDELAYHASH(slp, nfsd->nd_fh.nfh_fid);
1334 owp = NULL;
1335 wp = wpp->lh_first;
1336 while (wp && !nfsrv_fhmatch(&nfsd->nd_fh, &wp->nd_fh)) {
1337 owp = wp;
1338 wp = wp->nd_hash.le_next;
1339 }
1340 while (wp && (wp->nd_off < nfsd->nd_off) &&
1341 nfsrv_fhmatch(&nfsd->nd_fh, &wp->nd_fh)) {
1342 owp = wp;
1343 wp = wp->nd_hash.le_next;
1344 }
1345 if (owp) {
1346 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1347
1348 /*
1349 * Search the hash list for overlapping entries and
1350 * coalesce.
1351 */
1352 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1353 wp = nfsd->nd_hash.le_next;
1354 if (NFSW_SAMECRED(owp, nfsd))
1355 nfsrvw_coalesce(owp, nfsd);
1356 }
1357 } else {
1358 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1359 }
1360 }
1361 } else {
1362 lck_mtx_lock(&slp->ns_wgmutex);
1363 }
1364
1365 /*
1366 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1367 * and generate the associated reply mbuf list(s).
1368 */
1369 loop1:
1370 microuptime(&now);
1371 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1372 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1373 owp = nfsd->nd_tq.le_next;
1374 if (nfsd->nd_time > cur_usec)
1375 break;
1376 if (nfsd->nd_mreq)
1377 continue;
1378 LIST_REMOVE(nfsd, nd_tq);
1379 LIST_REMOVE(nfsd, nd_hash);
1380 mrep = nfsd->nd_mrep;
1381 nfsd->nd_mrep = NULL;
1382 v3 = (nfsd->nd_flag & ND_NFSV3);
1383 forat_ret = aftat_ret = 1;
1384 error = nfsrv_fhtovp(&nfsd->nd_fh, nfsd->nd_nam, TRUE, &vp, &nx, &nxo);
1385 if (!error) {
1386 error = nfsrv_credcheck(nfsd, nx, nxo);
1387 if (error)
1388 vnode_put(vp);
1389 }
1390 cred = nfsd->nd_cr;
1391 context.vc_ucred = cred;
1392 if (!error) {
1393 if (v3) {
1394 nfsm_srv_pre_vattr_init(&forat, v3);
1395 forat_ret = vnode_getattr(vp, &forat, &context);
1396 }
1397 if (vnode_vtype(vp) != VREG) {
1398 if (v3)
1399 error = EINVAL;
1400 else
1401 error = (vnode_vtype(vp) == VDIR) ? EISDIR : EACCES;
1402 }
1403 } else
1404 vp = NULL;
1405 if (!error) {
1406 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA, &context, nxo, 1);
1407 }
1408
1409 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1410 ioflags = IO_NODELOCKED;
1411 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1412 ioflags = (IO_SYNC | IO_NODELOCKED);
1413 else
1414 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1415
1416 if (!error && ((nfsd->nd_eoff - nfsd->nd_off) > 0)) {
1417 mp = mrep;
1418 i = 0;
1419 while (mp) {
1420 if (mbuf_len(mp) > 0)
1421 i++;
1422 mp = mbuf_next(mp);
1423 }
1424
1425 MALLOC(uio_bufp, char *, UIO_SIZEOF(i), M_TEMP, M_WAITOK);
1426 if (uio_bufp)
1427 uiop = uio_createwithbuffer(i, nfsd->nd_off, UIO_SYSSPACE,
1428 UIO_WRITE, uio_bufp, UIO_SIZEOF(i));
1429 if (!uio_bufp || !uiop)
1430 error = ENOMEM;
1431 if (!error) {
1432 mp = mrep;
1433 while (mp) {
1434 if ((tlen = mbuf_len(mp)) > 0)
1435 uio_addiov(uiop, CAST_USER_ADDR_T((caddr_t)mbuf_data(mp)), tlen);
1436 mp = mbuf_next(mp);
1437 }
1438 error = VNOP_WRITE(vp, uiop, ioflags, &context);
1439 OSAddAtomic(1, (SInt32*)&nfsstats.srvvop_writes);
1440 }
1441 if (uio_bufp) {
1442 FREE(uio_bufp, M_TEMP);
1443 uio_bufp = NULL;
1444 }
1445 }
1446 mbuf_freem(mrep);
1447 mrep = NULL;
1448 if (vp) {
1449 nfsm_srv_pre_vattr_init(&va, v3);
1450 aftat_ret = vnode_getattr(vp, &va, &context);
1451 vnode_put(vp);
1452 }
1453
1454 /*
1455 * Loop around generating replies for all write rpcs that have
1456 * now been completed.
1457 */
1458 swp = nfsd;
1459 do {
1460 if (error) {
1461 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1462 if (v3) {
1463 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1464 }
1465 } else {
1466 nfsm_writereply(NFSX_PREOPATTR(v3) +
1467 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1468 NFSX_WRITEVERF(v3), v3);
1469 if (v3) {
1470 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1471 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1472 *tl++ = txdr_unsigned(nfsd->nd_len);
1473 *tl++ = txdr_unsigned(swp->nd_stable);
1474 /* write verifier */
1475 *tl++ = txdr_unsigned(boottime_sec());
1476 *tl = txdr_unsigned(0);
1477 } else {
1478 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1479 nfsm_srvfillattr(&va, fp);
1480 }
1481 }
1482 nfsd->nd_mreq = mreq;
1483 if (nfsd->nd_mrep)
1484 panic("nfsrv_write: nd_mrep not free");
1485
1486 /*
1487 * Done. Put it at the head of the timer queue so that
1488 * the final phase can return the reply.
1489 */
1490 if (nfsd != swp) {
1491 nfsd->nd_time = 1;
1492 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1493 }
1494 nfsd = swp->nd_coalesce.lh_first;
1495 if (nfsd) {
1496 LIST_REMOVE(nfsd, nd_tq);
1497 }
1498 } while (nfsd);
1499 swp->nd_time = 1;
1500 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1501 goto loop1;
1502 }
1503
1504 /*
1505 * Search for a reply to return.
1506 */
1507 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1508 if (nfsd->nd_mreq) {
1509 LIST_REMOVE(nfsd, nd_tq);
1510 *mrq = nfsd->nd_mreq;
1511 *ndp = nfsd;
1512 break;
1513 }
1514 slp->ns_wgtime = slp->ns_tq.lh_first ? slp->ns_tq.lh_first->nd_time : 0;
1515 lck_mtx_unlock(&slp->ns_wgmutex);
1516 return (0);
1517 }
1518
1519 /*
1520 * Coalesce the write request nfsd into owp. To do this we must:
1521 * - remove nfsd from the queues
1522 * - merge nfsd->nd_mrep into owp->nd_mrep
1523 * - update the nd_eoff and nd_stable for owp
1524 * - put nfsd on owp's nd_coalesce list
1525 */
1526 static void
1527 nfsrvw_coalesce(
1528 struct nfsrv_descript *owp,
1529 struct nfsrv_descript *nfsd)
1530 {
1531 int overlap, error;
1532 mbuf_t mp, mpnext;
1533 struct nfsrv_descript *p;
1534
1535 LIST_REMOVE(nfsd, nd_hash);
1536 LIST_REMOVE(nfsd, nd_tq);
1537 if (owp->nd_eoff < nfsd->nd_eoff) {
1538 overlap = owp->nd_eoff - nfsd->nd_off;
1539 if (overlap < 0)
1540 panic("nfsrv_coalesce: bad off");
1541 if (overlap > 0)
1542 mbuf_adj(nfsd->nd_mrep, overlap);
1543 mp = owp->nd_mrep;
1544 while ((mpnext = mbuf_next(mp)))
1545 mp = mpnext;
1546 error = mbuf_setnext(mp, nfsd->nd_mrep);
1547 if (error)
1548 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error);
1549 owp->nd_eoff = nfsd->nd_eoff;
1550 } else {
1551 mbuf_freem(nfsd->nd_mrep);
1552 }
1553 nfsd->nd_mrep = NULL;
1554 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1555 owp->nd_stable = NFSV3WRITE_FILESYNC;
1556 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1557 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1558 owp->nd_stable = NFSV3WRITE_DATASYNC;
1559 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1560
1561 /*
1562 * If nfsd had anything else coalesced into it, transfer them
1563 * to owp, otherwise their replies will never get sent.
1564 */
1565 for (p = nfsd->nd_coalesce.lh_first; p;
1566 p = nfsd->nd_coalesce.lh_first) {
1567 LIST_REMOVE(p, nd_tq);
1568 LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1569 }
1570 }
1571
1572 /*
1573 * Sort the group list in increasing numerical order.
1574 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1575 * that used to be here.)
1576 *
1577 * XXX ILLEGAL
1578 */
1579 void
1580 nfsrvw_sort(list, num)
1581 gid_t *list;
1582 int num;
1583 {
1584 int i, j;
1585 gid_t v;
1586
1587 /* Insertion sort. */
1588 for (i = 1; i < num; i++) {
1589 v = list[i];
1590 /* find correct slot for value v, moving others up */
1591 for (j = i; --j >= 0 && v < list[j];)
1592 list[j + 1] = list[j];
1593 list[j + 1] = v;
1594 }
1595 }
1596
1597 /*
1598 * copy credentials making sure that the result can be compared with bcmp().
1599 *
1600 * NOTE: This function is only intended to operate on a real input
1601 * credential and a template output credential; the template
1602 * ouptut credential is intended to then be used as an argument
1603 * to kauth_cred_create() - AND NEVER REFERENCED OTHERWISE.
1604 */
1605 void
1606 nfsrv_setcred(kauth_cred_t incred, kauth_cred_t outcred)
1607 {
1608 int i;
1609
1610 bzero((caddr_t)outcred, sizeof (*outcred));
1611 outcred->cr_uid = kauth_cred_getuid(incred);
1612 outcred->cr_ngroups = incred->cr_ngroups;
1613 for (i = 0; i < incred->cr_ngroups; i++)
1614 outcred->cr_groups[i] = incred->cr_groups[i];
1615 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1616 }
1617
1618 /*
1619 * nfs create service
1620 * now does a truncate to 0 length via. setattr if it already exists
1621 */
1622 int
1623 nfsrv_create(nfsd, slp, procp, mrq)
1624 struct nfsrv_descript *nfsd;
1625 struct nfssvc_sock *slp;
1626 proc_t procp;
1627 mbuf_t *mrq;
1628 {
1629 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
1630 mbuf_t nam = nfsd->nd_nam;
1631 caddr_t dpos = nfsd->nd_dpos;
1632 struct nfs_fattr *fp;
1633 struct vnode_attr dirfor, diraft, postat;
1634 struct vnode_attr va;
1635 struct vnode_attr *vap = &va;
1636 struct nfsv2_sattr *sp;
1637 u_long *tl;
1638 struct nameidata nd;
1639 caddr_t cp;
1640 long t1;
1641 caddr_t bpos;
1642 int error = 0, rdev, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1643 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1644 char *cp2;
1645 mbuf_t mb, mb2, mreq;
1646 vnode_t vp, dvp, dirp = NULL;
1647 struct nfs_filehandle nfh;
1648 struct nfs_export *nx;
1649 struct nfs_export_options *nxo;
1650 u_quad_t tempsize;
1651 u_char cverf[NFSX_V3CREATEVERF];
1652 struct vfs_context context;
1653 uid_t saved_uid;
1654
1655 context.vc_proc = procp;
1656 context.vc_ucred = nfsd->nd_cr;
1657
1658 /*
1659 * Save the original credential UID in case they are
1660 * mapped and we need to map the IDs in the attributes.
1661 */
1662 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
1663
1664 #ifndef nolint
1665 rdev = 0;
1666 #endif
1667 nd.ni_cnd.cn_nameiop = 0;
1668 vp = dvp = NULL;
1669 nfsm_srvmtofh(&nfh);
1670 nfsm_srvnamesiz(len, v3);
1671
1672 nd.ni_cnd.cn_nameiop = CREATE;
1673 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1674 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
1675 if (!error)
1676 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
1677 if (dirp) {
1678 if (v3) {
1679 nfsm_srv_pre_vattr_init(&dirfor, v3);
1680 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
1681 } else {
1682 vnode_put(dirp);
1683 dirp = NULL;
1684 }
1685 }
1686 if (error) {
1687 nd.ni_cnd.cn_nameiop = 0;
1688 nfsm_reply(NFSX_WCCDATA(v3));
1689 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1690 if (dirp)
1691 vnode_put(dirp);
1692 return (0);
1693 }
1694 dvp = nd.ni_dvp;
1695 vp = nd.ni_vp;
1696
1697 VATTR_INIT(vap);
1698
1699 if (v3) {
1700 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1701 how = fxdr_unsigned(int, *tl);
1702 switch (how) {
1703 case NFSV3CREATE_GUARDED:
1704 if (vp) {
1705 error = EEXIST;
1706 break;
1707 }
1708 case NFSV3CREATE_UNCHECKED:
1709 nfsm_srvsattr(vap);
1710 break;
1711 case NFSV3CREATE_EXCLUSIVE:
1712 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1713 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1714 exclusive_flag = 1;
1715 if (vp == NULL)
1716 VATTR_SET(vap, va_mode, 0);
1717 break;
1718 };
1719 VATTR_SET(vap, va_type, VREG);
1720 } else {
1721 enum vtype v_type;
1722
1723 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1724 v_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1725 if (v_type == VNON)
1726 v_type = VREG;
1727 VATTR_SET(vap, va_type, v_type);
1728 VATTR_SET(vap, va_mode, nfstov_mode(sp->sa_mode));
1729
1730 switch (v_type) {
1731 case VREG:
1732 tsize = fxdr_unsigned(long, sp->sa_size);
1733 if (tsize != -1)
1734 VATTR_SET(vap, va_data_size, (u_quad_t)tsize);
1735 break;
1736 case VCHR:
1737 case VBLK:
1738 case VFIFO:
1739 rdev = fxdr_unsigned(long, sp->sa_size);
1740 break;
1741 default:
1742 break;
1743 };
1744 }
1745
1746 /*
1747 * If it doesn't exist, create it
1748 * otherwise just truncate to 0 length
1749 * should I set the mode too ??
1750 */
1751 if (vp == NULL) {
1752 kauth_acl_t xacl = NULL;
1753
1754 /*
1755 * If the credentials were mapped, we should
1756 * map the same values in the attributes.
1757 */
1758 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
1759 int ismember;
1760 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
1761 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
1762 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
1763 }
1764
1765 /* authorize before creating */
1766 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
1767
1768 /* construct ACL and handle inheritance */
1769 if (!error) {
1770 error = kauth_acl_inherit(dvp,
1771 NULL,
1772 &xacl,
1773 0 /* !isdir */,
1774 &context);
1775
1776 if (!error && xacl != NULL)
1777 VATTR_SET(vap, va_acl, xacl);
1778 }
1779 VATTR_CLEAR_ACTIVE(vap, va_data_size);
1780 VATTR_CLEAR_ACTIVE(vap, va_access_time);
1781
1782 /* validate new-file security information */
1783 if (!error) {
1784 error = vnode_authattr_new(dvp, vap, 0, &context);
1785 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
1786 /*
1787 * Most NFS servers just ignore the UID/GID attributes, so we
1788 * try ignoring them if that'll help the request succeed.
1789 */
1790 VATTR_CLEAR_ACTIVE(vap, va_uid);
1791 VATTR_CLEAR_ACTIVE(vap, va_gid);
1792 error = vnode_authattr_new(dvp, vap, 0, &context);
1793 }
1794 }
1795
1796 if (vap->va_type == VREG || vap->va_type == VSOCK) {
1797
1798 if (!error)
1799 error = VNOP_CREATE(dvp, &vp, &nd.ni_cnd, vap, &context);
1800
1801 if (!error && !VATTR_ALL_SUPPORTED(vap))
1802 /*
1803 * If some of the requested attributes weren't handled by the VNOP,
1804 * use our fallback code.
1805 */
1806 error = vnode_setattr_fallback(vp, vap, &context);
1807
1808 if (xacl != NULL)
1809 kauth_acl_free(xacl);
1810
1811 if (!error) {
1812 if (exclusive_flag) {
1813 exclusive_flag = 0;
1814 VATTR_INIT(vap);
1815 bcopy(cverf, (caddr_t)&vap->va_access_time,
1816 NFSX_V3CREATEVERF);
1817 VATTR_SET_ACTIVE(vap, va_access_time);
1818 // skip authorization, as this is an
1819 // NFS internal implementation detail.
1820 error = vnode_setattr(vp, vap, &context);
1821 }
1822 }
1823
1824 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1825 vap->va_type == VFIFO) {
1826 if (vap->va_type == VCHR && rdev == (int)0xffffffff)
1827 VATTR_SET(vap, va_type, VFIFO);
1828 if (vap->va_type != VFIFO &&
1829 (error = suser(nfsd->nd_cr, (u_short *)0))) {
1830 nfsm_reply(0);
1831 } else
1832 VATTR_SET(vap, va_rdev, (dev_t)rdev);
1833
1834 error = VNOP_MKNOD(dvp, &vp, &nd.ni_cnd, vap, &context);
1835
1836 if (xacl != NULL)
1837 kauth_acl_free(xacl);
1838
1839 if (error) {
1840 nfsm_reply(0);
1841 }
1842 if (vp) {
1843 vnode_recycle(vp);
1844 vnode_put(vp);
1845 vp = NULL;
1846 }
1847 nd.ni_cnd.cn_nameiop = LOOKUP;
1848 nd.ni_cnd.cn_flags &= ~LOCKPARENT;
1849 nd.ni_cnd.cn_context = &context;
1850 nd.ni_startdir = dvp;
1851 nd.ni_usedvp = dvp;
1852 error = lookup(&nd);
1853 if (!error) {
1854 if (nd.ni_cnd.cn_flags & ISSYMLINK)
1855 error = EINVAL;
1856 vp = nd.ni_vp;
1857 }
1858 if (error)
1859 nfsm_reply(0);
1860 } else {
1861 error = ENXIO;
1862 }
1863 /*
1864 * nameidone has to happen before we vnode_put(dvp)
1865 * since it may need to release the fs_nodelock on the dvp
1866 */
1867 nameidone(&nd);
1868 nd.ni_cnd.cn_nameiop = 0;
1869
1870 vnode_put(dvp);
1871 } else {
1872 /*
1873 * nameidone has to happen before we vnode_put(dvp)
1874 * since it may need to release the fs_nodelock on the dvp
1875 */
1876 nameidone(&nd);
1877 nd.ni_cnd.cn_nameiop = 0;
1878
1879 vnode_put(dvp);
1880
1881 if (!error && VATTR_IS_ACTIVE(vap, va_data_size)) {
1882 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA,
1883 &context, nxo, 0);
1884 if (!error) {
1885 tempsize = vap->va_data_size;
1886 VATTR_INIT(vap);
1887 VATTR_SET(vap, va_data_size, tempsize);
1888 error = vnode_setattr(vp, vap, &context);
1889 }
1890 }
1891 }
1892 if (!error) {
1893 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
1894 if (!error) {
1895 nfsm_srv_vattr_init(&postat, v3);
1896 error = vnode_getattr(vp, &postat, &context);
1897 }
1898 }
1899 if (vp)
1900 vnode_put(vp);
1901
1902 if (v3) {
1903 if (exclusive_flag && !error &&
1904 bcmp(cverf, (caddr_t)&postat.va_access_time, NFSX_V3CREATEVERF))
1905 error = EEXIST;
1906 nfsm_srv_vattr_init(&diraft, v3);
1907 diraft_ret = vnode_getattr(dirp, &diraft, &context);
1908 vnode_put(dirp);
1909 dirp = NULL;
1910 }
1911 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1912
1913 if (v3) {
1914 if (!error) {
1915 nfsm_srvpostop_fh(&nfh);
1916 nfsm_srvpostop_attr(0, &postat);
1917 }
1918 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1919 } else {
1920 nfsm_srvfhtom(&nfh, v3);
1921 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1922 nfsm_srvfillattr(&postat, fp);
1923 }
1924 return (0);
1925 nfsmout:
1926 if (nd.ni_cnd.cn_nameiop) {
1927 /*
1928 * nameidone has to happen before we vnode_put(dvp)
1929 * since it may need to release the fs_nodelock on the dvp
1930 */
1931 nameidone(&nd);
1932
1933 if (vp)
1934 vnode_put(vp);
1935 vnode_put(dvp);
1936 }
1937 if (dirp)
1938 vnode_put(dirp);
1939 return (error);
1940 }
1941
1942 /*
1943 * nfs v3 mknod service
1944 */
1945 int
1946 nfsrv_mknod(nfsd, slp, procp, mrq)
1947 struct nfsrv_descript *nfsd;
1948 struct nfssvc_sock *slp;
1949 proc_t procp;
1950 mbuf_t *mrq;
1951 {
1952 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
1953 mbuf_t nam = nfsd->nd_nam;
1954 caddr_t dpos = nfsd->nd_dpos;
1955 struct vnode_attr dirfor, diraft, postat;
1956 struct vnode_attr va;
1957 struct vnode_attr *vap = &va;
1958 u_long *tl;
1959 struct nameidata nd;
1960 long t1;
1961 caddr_t bpos;
1962 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1963 u_long major, minor;
1964 enum vtype vtyp;
1965 char *cp2;
1966 mbuf_t mb, mb2, mreq;
1967 vnode_t vp, dvp, dirp = NULL;
1968 struct nfs_filehandle nfh;
1969 struct nfs_export *nx;
1970 struct nfs_export_options *nxo;
1971 struct vfs_context hacked_context; /* XXX should we have this? */
1972 struct vfs_context context;
1973 uid_t saved_uid;
1974 kauth_acl_t xacl = NULL;
1975
1976 context.vc_proc = procp;
1977 context.vc_ucred = nfsd->nd_cr;
1978
1979 /*
1980 * Save the original credential UID in case they are
1981 * mapped and we need to map the IDs in the attributes.
1982 */
1983 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
1984
1985 vp = dvp = NULL;
1986 nd.ni_cnd.cn_nameiop = 0;
1987 nfsm_srvmtofh(&nfh);
1988 nfsm_srvnamesiz(len, 1);
1989
1990 nd.ni_cnd.cn_nameiop = CREATE;
1991 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1992 error = nfsm_path_mbuftond(&md, &dpos, 1, FALSE, &len, &nd);
1993 if (!error)
1994 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
1995 if (dirp) {
1996 nfsm_srv_pre_vattr_init(&dirfor, 1);
1997 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
1998 }
1999 if (error) {
2000 nd.ni_cnd.cn_nameiop = 0;
2001 nfsm_reply(NFSX_WCCDATA(1));
2002 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2003 if (dirp)
2004 vnode_put(dirp);
2005 return (0);
2006 }
2007 dvp = nd.ni_dvp;
2008 vp = nd.ni_vp;
2009
2010 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2011 vtyp = nfsv3tov_type(*tl);
2012 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
2013 error = NFSERR_BADTYPE;
2014 goto out;
2015 }
2016 VATTR_INIT(vap);
2017 nfsm_srvsattr(vap);
2018
2019 if (vtyp == VCHR || vtyp == VBLK) {
2020 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2021 major = fxdr_unsigned(u_long, *tl++);
2022 minor = fxdr_unsigned(u_long, *tl);
2023 VATTR_SET(vap, va_rdev, makedev(major, minor));
2024 }
2025
2026 /*
2027 * If it doesn't exist, create it.
2028 */
2029 if (vp) {
2030 error = EEXIST;
2031 goto out;
2032 }
2033 VATTR_SET(vap, va_type, vtyp);
2034
2035 /*
2036 * If the credentials were mapped, we should
2037 * map the same values in the attributes.
2038 */
2039 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
2040 int ismember;
2041 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
2042 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
2043 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
2044 }
2045
2046 /* authorize before creating */
2047 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2048
2049 /* construct ACL and handle inheritance */
2050 if (!error) {
2051 error = kauth_acl_inherit(dvp,
2052 NULL,
2053 &xacl,
2054 0 /* !isdir */,
2055 &context);
2056
2057 if (!error && xacl != NULL)
2058 VATTR_SET(vap, va_acl, xacl);
2059 }
2060 VATTR_CLEAR_ACTIVE(vap, va_data_size);
2061 VATTR_CLEAR_ACTIVE(vap, va_access_time);
2062
2063 /* validate new-file security information */
2064 if (!error) {
2065 error = vnode_authattr_new(dvp, vap, 0, &context);
2066 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
2067 /*
2068 * Most NFS servers just ignore the UID/GID attributes, so we
2069 * try ignoring them if that'll help the request succeed.
2070 */
2071 VATTR_CLEAR_ACTIVE(vap, va_uid);
2072 VATTR_CLEAR_ACTIVE(vap, va_gid);
2073 error = vnode_authattr_new(dvp, vap, 0, &context);
2074 }
2075 }
2076
2077 if (vtyp == VSOCK) {
2078 error = VNOP_CREATE(dvp, &vp, &nd.ni_cnd, vap, &context);
2079
2080 if (!error && !VATTR_ALL_SUPPORTED(vap))
2081 /*
2082 * If some of the requested attributes weren't handled by the VNOP,
2083 * use our fallback code.
2084 */
2085 error = vnode_setattr_fallback(vp, vap, &context);
2086 } else {
2087 if (vtyp != VFIFO && (error = suser(nfsd->nd_cr, (u_short *)0))) {
2088 goto out1;
2089 }
2090 if ((error = VNOP_MKNOD(dvp, &vp, &nd.ni_cnd, vap, &context))) {
2091 goto out1;
2092 }
2093 if (vp) {
2094 vnode_recycle(vp);
2095 vnode_put(vp);
2096 vp = NULL;
2097 }
2098 hacked_context.vc_proc = procp;
2099 hacked_context.vc_ucred = kauth_cred_proc_ref(procp);
2100
2101 nd.ni_cnd.cn_nameiop = LOOKUP;
2102 nd.ni_cnd.cn_flags &= ~LOCKPARENT;
2103 nd.ni_cnd.cn_context = &hacked_context;
2104 nd.ni_startdir = dvp;
2105 nd.ni_usedvp = dvp;
2106 error = lookup(&nd);
2107 if (!error) {
2108 vp = nd.ni_vp;
2109 if (nd.ni_cnd.cn_flags & ISSYMLINK)
2110 error = EINVAL;
2111 }
2112 kauth_cred_unref(&hacked_context.vc_ucred);
2113 }
2114 out1:
2115 if (xacl != NULL)
2116 kauth_acl_free(xacl);
2117 out:
2118 /*
2119 * nameidone has to happen before we vnode_put(dvp)
2120 * since it may need to release the fs_nodelock on the dvp
2121 */
2122 nameidone(&nd);
2123 nd.ni_cnd.cn_nameiop = 0;
2124
2125 vnode_put(dvp);
2126
2127 if (!error) {
2128 error = nfsrv_vptofh(nx, 0, NULL, vp, &context, &nfh);
2129 if (!error) {
2130 nfsm_srv_vattr_init(&postat, 1);
2131 error = vnode_getattr(vp, &postat, &context);
2132 }
2133 }
2134 if (vp)
2135 vnode_put(vp);
2136
2137 nfsm_srv_vattr_init(&diraft, 1);
2138 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2139 vnode_put(dirp);
2140 dirp = NULL;
2141
2142 nfsm_reply(NFSX_SRVFH(1, &nfh) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2143 if (!error) {
2144 nfsm_srvpostop_fh(&nfh);
2145 nfsm_srvpostop_attr(0, &postat);
2146 }
2147 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2148 return (0);
2149 nfsmout:
2150 if (nd.ni_cnd.cn_nameiop) {
2151 /*
2152 * nameidone has to happen before we vnode_put(dvp)
2153 * since it may need to release the fs_nodelock on the dvp
2154 */
2155 nameidone(&nd);
2156
2157 if (vp)
2158 vnode_put(vp);
2159 vnode_put(dvp);
2160 }
2161 if (dirp)
2162 vnode_put(dirp);
2163 return (error);
2164 }
2165
2166 /*
2167 * nfs remove service
2168 */
2169 int
2170 nfsrv_remove(nfsd, slp, procp, mrq)
2171 struct nfsrv_descript *nfsd;
2172 struct nfssvc_sock *slp;
2173 proc_t procp;
2174 mbuf_t *mrq;
2175 {
2176 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2177 mbuf_t nam = nfsd->nd_nam;
2178 caddr_t dpos = nfsd->nd_dpos;
2179 struct nameidata nd;
2180 u_long *tl;
2181 long t1;
2182 caddr_t bpos;
2183 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2184 int v3 = (nfsd->nd_flag & ND_NFSV3);
2185 char *cp2;
2186 mbuf_t mb, mreq;
2187 vnode_t vp, dvp, dirp = NULL;
2188 struct vnode_attr dirfor, diraft;
2189 struct nfs_filehandle nfh;
2190 struct nfs_export *nx;
2191 struct nfs_export_options *nxo;
2192 struct vfs_context context;
2193
2194 context.vc_proc = procp;
2195 context.vc_ucred = nfsd->nd_cr;
2196
2197 dvp = vp = NULL;
2198 nfsm_srvmtofh(&nfh);
2199 nfsm_srvnamesiz(len, v3);
2200
2201 nd.ni_cnd.cn_nameiop = DELETE;
2202 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2203 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2204 if (!error)
2205 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2206 if (dirp) {
2207 if (v3) {
2208 nfsm_srv_pre_vattr_init(&dirfor, v3);
2209 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2210 } else {
2211 vnode_put(dirp);
2212 dirp = NULL;
2213 }
2214 }
2215 if (!error) {
2216 dvp = nd.ni_dvp;
2217 vp = nd.ni_vp;
2218
2219 if (vnode_vtype(vp) == VDIR)
2220 error = EPERM; /* POSIX */
2221 else if (vnode_isvroot(vp))
2222 /*
2223 * The root of a mounted filesystem cannot be deleted.
2224 */
2225 error = EBUSY;
2226 else
2227 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
2228
2229 if (!error)
2230 error = VNOP_REMOVE(dvp, vp, &nd.ni_cnd, 0, &context);
2231
2232 /*
2233 * nameidone has to happen before we vnode_put(dvp)
2234 * since it may need to release the fs_nodelock on the dvp
2235 */
2236 nameidone(&nd);
2237
2238 vnode_put(vp);
2239 vnode_put(dvp);
2240 }
2241 if (dirp) {
2242 nfsm_srv_vattr_init(&diraft, v3);
2243 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2244 vnode_put(dirp);
2245 }
2246 nfsm_reply(NFSX_WCCDATA(v3));
2247 if (v3) {
2248 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2249 return (0);
2250 }
2251 nfsmout:
2252 return (error);
2253 }
2254
2255 /*
2256 * nfs rename service
2257 */
2258 int
2259 nfsrv_rename(nfsd, slp, procp, mrq)
2260 struct nfsrv_descript *nfsd;
2261 struct nfssvc_sock *slp;
2262 proc_t procp;
2263 mbuf_t *mrq;
2264 {
2265 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2266 mbuf_t nam = nfsd->nd_nam;
2267 caddr_t dpos = nfsd->nd_dpos;
2268 kauth_cred_t saved_cred = NULL;
2269 u_long *tl;
2270 long t1;
2271 caddr_t bpos;
2272 int error = 0, fromlen, tolen;
2273 int fdirfor_ret = 1, fdiraft_ret = 1;
2274 int tdirfor_ret = 1, tdiraft_ret = 1;
2275 int v3 = (nfsd->nd_flag & ND_NFSV3);
2276 char *cp2, *frompath = NULL, *topath = NULL;
2277 mbuf_t mb, mreq;
2278 struct nameidata fromnd, tond;
2279 vnode_t fvp, tvp, tdvp, fdvp, fdirp = NULL;
2280 vnode_t tdirp = NULL;
2281 struct vnode_attr fdirfor, fdiraft, tdirfor, tdiraft;
2282 struct nfs_filehandle fnfh, tnfh;
2283 struct nfs_export *fnx, *tnx;
2284 struct nfs_export_options *fnxo, *tnxo;
2285 enum vtype fvtype, tvtype;
2286 int holding_mntlock;
2287 mount_t locked_mp;
2288 struct vfs_context context;
2289
2290 context.vc_proc = procp;
2291 context.vc_ucred = nfsd->nd_cr;
2292
2293 #ifndef nolint
2294 fvp = (vnode_t)0;
2295 #endif
2296
2297 /*
2298 * these need to be set before
2299 * calling any nfsm_xxxx macros
2300 * since they may take us out
2301 * through the error path
2302 */
2303 holding_mntlock = 0;
2304 fvp = tvp = NULL;
2305 fdvp = tdvp = NULL;
2306 locked_mp = NULL;
2307
2308 nfsm_srvmtofh(&fnfh);
2309 nfsm_srvnamesiz(fromlen, v3);
2310 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &fromlen, &fromnd);
2311 if (error) {
2312 nfsm_reply(0);
2313 return (0);
2314 }
2315 frompath = fromnd.ni_cnd.cn_pnbuf;
2316 nfsm_srvmtofh(&tnfh);
2317 nfsm_strsiz(tolen, NFS_MAXNAMLEN, v3);
2318 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &tolen, &tond);
2319 if (error) {
2320 nfsm_reply(0);
2321 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2322 return (0);
2323 }
2324 topath = tond.ni_cnd.cn_pnbuf;
2325
2326 /*
2327 * Remember our original uid so that we can reset cr_uid before
2328 * the second nfs_namei() call, in case it is remapped.
2329 */
2330 saved_cred = nfsd->nd_cr;
2331 kauth_cred_ref(saved_cred);
2332 retry:
2333 fromnd.ni_cnd.cn_nameiop = DELETE;
2334 fromnd.ni_cnd.cn_flags = WANTPARENT;
2335
2336 fromnd.ni_cnd.cn_pnbuf = frompath;
2337 frompath = NULL;
2338 fromnd.ni_cnd.cn_pnlen = MAXPATHLEN;
2339 fromnd.ni_cnd.cn_flags |= HASBUF;
2340
2341 error = nfs_namei(nfsd, &context, &fromnd, &fnfh, nam, FALSE, &fdirp, &fnx, &fnxo);
2342 if (error)
2343 goto out;
2344 fdvp = fromnd.ni_dvp;
2345 fvp = fromnd.ni_vp;
2346
2347 if (fdirp) {
2348 if (v3) {
2349 nfsm_srv_pre_vattr_init(&fdirfor, v3);
2350 fdirfor_ret = vnode_getattr(fdirp, &fdirfor, &context);
2351 } else {
2352 vnode_put(fdirp);
2353 fdirp = NULL;
2354 }
2355 }
2356 fvtype = vnode_vtype(fvp);
2357
2358 /* reset credential if it was remapped */
2359 if (nfsd->nd_cr != saved_cred) {
2360 kauth_cred_ref(saved_cred);
2361 kauth_cred_unref(&nfsd->nd_cr);
2362 nfsd->nd_cr = saved_cred;
2363 }
2364
2365 tond.ni_cnd.cn_nameiop = RENAME;
2366 tond.ni_cnd.cn_flags = WANTPARENT;
2367
2368 tond.ni_cnd.cn_pnbuf = topath;
2369 topath = NULL;
2370 tond.ni_cnd.cn_pnlen = MAXPATHLEN;
2371 tond.ni_cnd.cn_flags |= HASBUF;
2372
2373 if (fvtype == VDIR)
2374 tond.ni_cnd.cn_flags |= WILLBEDIR;
2375
2376 error = nfs_namei(nfsd, &context, &tond, &tnfh, nam, FALSE, &tdirp, &tnx, &tnxo);
2377 if (error) {
2378 /*
2379 * Translate error code for rename("dir1", "dir2/.").
2380 */
2381 if (error == EISDIR && fvtype == VDIR) {
2382 if (v3)
2383 error = EINVAL;
2384 else
2385 error = ENOTEMPTY;
2386 }
2387 goto out;
2388 }
2389 tdvp = tond.ni_dvp;
2390 tvp = tond.ni_vp;
2391
2392 if (tdirp) {
2393 if (v3) {
2394 nfsm_srv_pre_vattr_init(&tdirfor, v3);
2395 tdirfor_ret = vnode_getattr(tdirp, &tdirfor, &context);
2396 } else {
2397 vnode_put(tdirp);
2398 tdirp = NULL;
2399 }
2400 }
2401
2402 if (tvp != NULL) {
2403 tvtype = vnode_vtype(tvp);
2404
2405 if (fvtype == VDIR && tvtype != VDIR) {
2406 if (v3)
2407 error = EEXIST;
2408 else
2409 error = EISDIR;
2410 goto out;
2411 } else if (fvtype != VDIR && tvtype == VDIR) {
2412 if (v3)
2413 error = EEXIST;
2414 else
2415 error = ENOTDIR;
2416 goto out;
2417 }
2418 if (tvtype == VDIR && vnode_mountedhere(tvp)) {
2419 if (v3)
2420 error = EXDEV;
2421 else
2422 error = ENOTEMPTY;
2423 goto out;
2424 }
2425 }
2426 if (fvp == tdvp) {
2427 if (v3)
2428 error = EINVAL;
2429 else
2430 error = ENOTEMPTY;
2431 goto out;
2432 }
2433
2434 /*
2435 * Authorization.
2436 *
2437 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2438 * the node is moving between directories and we need rights to remove from the
2439 * old and add to the new.
2440 *
2441 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2442 *
2443 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2444 * implement the deferred-inherit bit.
2445 */
2446 {
2447 int moving = 0;
2448
2449 error = 0;
2450 if ((tvp != NULL) && vnode_isdir(tvp)) {
2451 if (tvp != fdvp)
2452 moving = 1;
2453 } else if (tdvp != fdvp) {
2454 moving = 1;
2455 }
2456 if (moving) {
2457 /* moving out of fdvp, must have delete rights */
2458 if ((error = nfsrv_authorize(fvp, fdvp, KAUTH_VNODE_DELETE, &context, fnxo, 0)) != 0)
2459 goto auth_exit;
2460 /* moving into tdvp or tvp, must have rights to add */
2461 if ((error = nfsrv_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
2462 NULL,
2463 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2464 &context, tnxo, 0)) != 0)
2465 goto auth_exit;
2466 } else {
2467 /* node staying in same directory, must be allowed to add new name */
2468 if ((error = nfsrv_authorize(fdvp, NULL,
2469 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2470 &context, fnxo, 0)) != 0)
2471 goto auth_exit;
2472 }
2473 /* overwriting tvp */
2474 if ((tvp != NULL) && !vnode_isdir(tvp) &&
2475 ((error = nfsrv_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, &context, tnxo, 0)) != 0))
2476 goto auth_exit;
2477
2478 /* XXX more checks? */
2479
2480 auth_exit:
2481 /* authorization denied */
2482 if (error != 0)
2483 goto out;
2484 }
2485
2486 if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
2487 (tvp && (vnode_mount(fvp) != vnode_mount(tvp)))) {
2488 if (v3)
2489 error = EXDEV;
2490 else
2491 error = ENOTEMPTY;
2492 goto out;
2493 }
2494 /*
2495 * The following edge case is caught here:
2496 * (to cannot be a descendent of from)
2497 *
2498 * o fdvp
2499 * /
2500 * /
2501 * o fvp
2502 * \
2503 * \
2504 * o tdvp
2505 * /
2506 * /
2507 * o tvp
2508 */
2509 if (tdvp->v_parent == fvp) {
2510 if (v3)
2511 error = EXDEV;
2512 else
2513 error = ENOTEMPTY;
2514 goto out;
2515 }
2516 if (fvtype == VDIR && vnode_mountedhere(fvp)) {
2517 if (v3)
2518 error = EXDEV;
2519 else
2520 error = ENOTEMPTY;
2521 goto out;
2522 }
2523 /*
2524 * If source is the same as the destination (that is the
2525 * same vnode) then there is nothing to do...
2526 * EXCEPT if the underlying file system supports case
2527 * insensitivity and is case preserving. In this case
2528 * the file system needs to handle the special case of
2529 * getting the same vnode as target (fvp) and source (tvp).
2530 *
2531 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2532 * and _PC_CASE_PRESERVING can have this exception, and they need to
2533 * handle the special case of getting the same vnode as target and
2534 * source. NOTE: Then the target is unlocked going into vnop_rename,
2535 * so not to cause locking problems. There is a single reference on tvp.
2536 *
2537 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2538 * that correct behaviour then is just to remove the source (link)
2539 */
2540 if ((fvp == tvp) && (fdvp == tdvp)) {
2541 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2542 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2543 fromnd.ni_cnd.cn_namelen)) {
2544 goto out;
2545 }
2546 }
2547
2548 if (holding_mntlock && vnode_mount(fvp) != locked_mp) {
2549 /*
2550 * we're holding a reference and lock
2551 * on locked_mp, but it no longer matches
2552 * what we want to do... so drop our hold
2553 */
2554 mount_unlock_renames(locked_mp);
2555 mount_drop(locked_mp, 0);
2556 holding_mntlock = 0;
2557 }
2558 if (tdvp != fdvp && fvtype == VDIR) {
2559 /*
2560 * serialize renames that re-shape
2561 * the tree... if holding_mntlock is
2562 * set, then we're ready to go...
2563 * otherwise we
2564 * first need to drop the iocounts
2565 * we picked up, second take the
2566 * lock to serialize the access,
2567 * then finally start the lookup
2568 * process over with the lock held
2569 */
2570 if (!holding_mntlock) {
2571 /*
2572 * need to grab a reference on
2573 * the mount point before we
2574 * drop all the iocounts... once
2575 * the iocounts are gone, the mount
2576 * could follow
2577 */
2578 locked_mp = vnode_mount(fvp);
2579 mount_ref(locked_mp, 0);
2580
2581 /* make a copy of to path to pass to nfs_namei() again */
2582 MALLOC_ZONE(topath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2583 if (topath)
2584 bcopy(tond.ni_cnd.cn_pnbuf, topath, tolen + 1);
2585
2586 /*
2587 * nameidone has to happen before we vnode_put(tdvp)
2588 * since it may need to release the fs_nodelock on the tdvp
2589 */
2590 nameidone(&tond);
2591
2592 if (tvp)
2593 vnode_put(tvp);
2594 vnode_put(tdvp);
2595
2596 /* make a copy of from path to pass to nfs_namei() again */
2597 MALLOC_ZONE(frompath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2598 if (frompath)
2599 bcopy(fromnd.ni_cnd.cn_pnbuf, frompath, fromlen + 1);
2600
2601 /*
2602 * nameidone has to happen before we vnode_put(fdvp)
2603 * since it may need to release the fs_nodelock on the fdvp
2604 */
2605 nameidone(&fromnd);
2606
2607 vnode_put(fvp);
2608 vnode_put(fdvp);
2609
2610 if (fdirp) {
2611 vnode_put(fdirp);
2612 fdirp = NULL;
2613 }
2614 if (tdirp) {
2615 vnode_put(tdirp);
2616 tdirp = NULL;
2617 }
2618 mount_lock_renames(locked_mp);
2619 holding_mntlock = 1;
2620
2621 fvp = tvp = NULL;
2622 fdvp = tdvp = NULL;
2623
2624 fdirfor_ret = tdirfor_ret = 1;
2625
2626 if (!topath || !frompath) {
2627 /* we couldn't allocate a path, so bail */
2628 error = ENOMEM;
2629 goto out;
2630 }
2631
2632 goto retry;
2633 }
2634 } else {
2635 /*
2636 * when we dropped the iocounts to take
2637 * the lock, we allowed the identity of
2638 * the various vnodes to change... if they did,
2639 * we may no longer be dealing with a rename
2640 * that reshapes the tree... once we're holding
2641 * the iocounts, the vnodes can't change type
2642 * so we're free to drop the lock at this point
2643 * and continue on
2644 */
2645 if (holding_mntlock) {
2646 mount_unlock_renames(locked_mp);
2647 mount_drop(locked_mp, 0);
2648 holding_mntlock = 0;
2649 }
2650 }
2651
2652 // save these off so we can later verify that fvp is the same
2653 char *oname;
2654 vnode_t oparent;
2655 oname = fvp->v_name;
2656 oparent = fvp->v_parent;
2657
2658 error = VNOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2659 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd, &context);
2660 /*
2661 * fix up name & parent pointers. note that we first
2662 * check that fvp has the same name/parent pointers it
2663 * had before the rename call... this is a 'weak' check
2664 * at best...
2665 */
2666 if (oname == fvp->v_name && oparent == fvp->v_parent) {
2667 int update_flags;
2668 update_flags = VNODE_UPDATE_NAME;
2669 if (fdvp != tdvp)
2670 update_flags |= VNODE_UPDATE_PARENT;
2671 vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
2672 }
2673 out:
2674 if (holding_mntlock) {
2675 mount_unlock_renames(locked_mp);
2676 mount_drop(locked_mp, 0);
2677 holding_mntlock = 0;
2678 }
2679 if (tdvp) {
2680 /*
2681 * nameidone has to happen before we vnode_put(tdvp)
2682 * since it may need to release the fs_nodelock on the tdvp
2683 */
2684 nameidone(&tond);
2685 if (tvp)
2686 vnode_put(tvp);
2687 vnode_put(tdvp);
2688
2689 tdvp = NULL;
2690 }
2691 if (fdvp) {
2692 /*
2693 * nameidone has to happen before we vnode_put(fdvp)
2694 * since it may need to release the fs_nodelock on the fdvp
2695 */
2696 nameidone(&fromnd);
2697
2698 if (fvp)
2699 vnode_put(fvp);
2700 vnode_put(fdvp);
2701
2702 fdvp = NULL;
2703 }
2704 if (fdirp) {
2705 nfsm_srv_vattr_init(&fdiraft, v3);
2706 fdiraft_ret = vnode_getattr(fdirp, &fdiraft, &context);
2707 vnode_put(fdirp);
2708 fdirp = NULL;
2709 }
2710 if (tdirp) {
2711 nfsm_srv_vattr_init(&tdiraft, v3);
2712 tdiraft_ret = vnode_getattr(tdirp, &tdiraft, &context);
2713 vnode_put(tdirp);
2714 tdirp = NULL;
2715 }
2716 nfsm_reply(2 * NFSX_WCCDATA(v3));
2717 if (v3) {
2718 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2719 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2720 }
2721 if (frompath)
2722 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2723 if (topath)
2724 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2725 if (saved_cred)
2726 kauth_cred_unref(&saved_cred);
2727 return (0);
2728
2729 nfsmout:
2730 if (holding_mntlock) {
2731 mount_unlock_renames(locked_mp);
2732 mount_drop(locked_mp, 0);
2733 }
2734 if (tdvp) {
2735 /*
2736 * nameidone has to happen before we vnode_put(tdvp)
2737 * since it may need to release the fs_nodelock on the tdvp
2738 */
2739 nameidone(&tond);
2740
2741 if (tvp)
2742 vnode_put(tvp);
2743 vnode_put(tdvp);
2744 }
2745 if (fdvp) {
2746 /*
2747 * nameidone has to happen before we vnode_put(fdvp)
2748 * since it may need to release the fs_nodelock on the fdvp
2749 */
2750 nameidone(&fromnd);
2751
2752 if (fvp)
2753 vnode_put(fvp);
2754 vnode_put(fdvp);
2755 }
2756 if (fdirp)
2757 vnode_put(fdirp);
2758 if (tdirp)
2759 vnode_put(tdirp);
2760 if (frompath)
2761 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2762 if (topath)
2763 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2764 if (saved_cred)
2765 kauth_cred_unref(&saved_cred);
2766 return (error);
2767 }
2768
2769 /*
2770 * nfs link service
2771 */
2772 int
2773 nfsrv_link(nfsd, slp, procp, mrq)
2774 struct nfsrv_descript *nfsd;
2775 struct nfssvc_sock *slp;
2776 proc_t procp;
2777 mbuf_t *mrq;
2778 {
2779 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2780 mbuf_t nam = nfsd->nd_nam;
2781 caddr_t dpos = nfsd->nd_dpos;
2782 struct nameidata nd;
2783 u_long *tl;
2784 long t1;
2785 caddr_t bpos;
2786 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2787 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2788 char *cp2;
2789 mbuf_t mb, mreq;
2790 vnode_t vp, xp, dvp, dirp = NULL;
2791 struct vnode_attr dirfor, diraft, at;
2792 struct nfs_filehandle nfh, dnfh;
2793 struct nfs_export *nx;
2794 struct nfs_export_options *nxo;
2795 struct vfs_context context;
2796
2797 vp = xp = dvp = NULL;
2798 nfsm_srvmtofh(&nfh);
2799 nfsm_srvmtofh(&dnfh);
2800 nfsm_srvnamesiz(len, v3);
2801 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
2802 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2803 nfsm_srvpostop_attr(getret, &at);
2804 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2805 return (0);
2806 }
2807 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
2808 vnode_put(vp);
2809 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2810 nfsm_srvpostop_attr(getret, &at);
2811 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2812 return (0);
2813 }
2814
2815 /* we're not allowed to link to directories... */
2816 if (vnode_vtype(vp) == VDIR) {
2817 error = EPERM; /* POSIX */
2818 goto out1;
2819 }
2820
2821 context.vc_proc = procp;
2822 context.vc_ucred = nfsd->nd_cr;
2823
2824 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2825 if ((error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LINKTARGET, &context, nxo, 0)) != 0)
2826 goto out1;
2827
2828 nd.ni_cnd.cn_nameiop = CREATE;
2829 nd.ni_cnd.cn_flags = LOCKPARENT;
2830 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2831 if (!error)
2832 error = nfs_namei(nfsd, &context, &nd, &dnfh, nam, FALSE, &dirp, &nx, &nxo);
2833 if (dirp) {
2834 if (v3) {
2835 nfsm_srv_pre_vattr_init(&dirfor, v3);
2836 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2837 } else {
2838 vnode_put(dirp);
2839 dirp = NULL;
2840 }
2841 }
2842 if (error)
2843 goto out1;
2844 dvp = nd.ni_dvp;
2845 xp = nd.ni_vp;
2846
2847 if (xp != NULL)
2848 error = EEXIST;
2849 else if (vnode_mount(vp) != vnode_mount(dvp))
2850 error = EXDEV;
2851 else
2852 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2853
2854 if (!error)
2855 error = VNOP_LINK(vp, dvp, &nd.ni_cnd, &context);
2856
2857 /*
2858 * nameidone has to happen before we vnode_put(dvp)
2859 * since it may need to release the fs_nodelock on the dvp
2860 */
2861 nameidone(&nd);
2862
2863 if (xp)
2864 vnode_put(xp);
2865 vnode_put(dvp);
2866 out1:
2867 if (v3) {
2868 nfsm_srv_vattr_init(&at, v3);
2869 getret = vnode_getattr(vp, &at, &context);
2870 }
2871 if (dirp) {
2872 nfsm_srv_vattr_init(&diraft, v3);
2873 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2874 vnode_put(dirp);
2875 }
2876 vnode_put(vp);
2877
2878 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2879 if (v3) {
2880 nfsm_srvpostop_attr(getret, &at);
2881 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2882 return (0);
2883 }
2884 nfsmout:
2885 return (error);
2886 }
2887
2888 /*
2889 * nfs symbolic link service
2890 */
2891 int
2892 nfsrv_symlink(nfsd, slp, procp, mrq)
2893 struct nfsrv_descript *nfsd;
2894 struct nfssvc_sock *slp;
2895 proc_t procp;
2896 mbuf_t *mrq;
2897 {
2898 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2899 mbuf_t nam = nfsd->nd_nam;
2900 caddr_t dpos = nfsd->nd_dpos;
2901 struct vnode_attr dirfor, diraft, postat;
2902 struct nameidata nd;
2903 struct vnode_attr va;
2904 struct vnode_attr *vap = &va;
2905 u_long *tl;
2906 long t1;
2907 struct nfsv2_sattr *sp;
2908 char *bpos, *linkdata = NULL, *cp2;
2909 int error = 0, len, linkdatalen;
2910 int dirfor_ret = 1, diraft_ret = 1;
2911 int v3 = (nfsd->nd_flag & ND_NFSV3);
2912 mbuf_t mb, mreq, mb2;
2913 vnode_t vp, dvp, dirp = NULL;
2914 struct nfs_filehandle nfh;
2915 struct nfs_export *nx;
2916 struct nfs_export_options *nxo;
2917 uio_t auio;
2918 char uio_buf[ UIO_SIZEOF(1) ];
2919 struct vfs_context context;
2920 uid_t saved_uid;
2921
2922 context.vc_proc = procp;
2923 context.vc_ucred = nfsd->nd_cr;
2924
2925 /*
2926 * Save the original credential UID in case they are
2927 * mapped and we need to map the IDs in the attributes.
2928 */
2929 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
2930
2931 nd.ni_cnd.cn_nameiop = 0;
2932 vp = dvp = NULL;
2933 nfsm_srvmtofh(&nfh);
2934 nfsm_srvnamesiz(len, v3);
2935
2936 nd.ni_cnd.cn_nameiop = CREATE;
2937 nd.ni_cnd.cn_flags = LOCKPARENT;
2938 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2939 if (!error)
2940 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2941 if (dirp) {
2942 if (v3) {
2943 nfsm_srv_pre_vattr_init(&dirfor, v3);
2944 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2945 } else {
2946 vnode_put(dirp);
2947 dirp = NULL;
2948 }
2949 }
2950 if (error) {
2951 nd.ni_cnd.cn_nameiop = 0;
2952 goto out1;
2953 }
2954 dvp = nd.ni_dvp;
2955 vp = nd.ni_vp;
2956
2957 VATTR_INIT(vap);
2958 if (v3)
2959 nfsm_srvsattr(vap);
2960 nfsm_strsiz(linkdatalen, NFS_MAXPATHLEN, v3);
2961 MALLOC(linkdata, caddr_t, linkdatalen + 1, M_TEMP, M_WAITOK);
2962 if (!linkdata) {
2963 nameidone(&nd);
2964 nd.ni_cnd.cn_nameiop = 0;
2965 vnode_put(nd.ni_dvp);
2966 vnode_put(nd.ni_vp);
2967 error = ENOMEM;
2968 goto out;
2969 }
2970 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
2971 &uio_buf[0], sizeof(uio_buf));
2972 if (!auio) {
2973 nameidone(&nd);
2974 nd.ni_cnd.cn_nameiop = 0;
2975 vnode_put(nd.ni_dvp);
2976 vnode_put(nd.ni_vp);
2977 error = ENOMEM;
2978 goto out;
2979 }
2980 uio_addiov(auio, CAST_USER_ADDR_T(linkdata), linkdatalen);
2981 nfsm_mtouio(auio, linkdatalen);
2982 if (!v3) {
2983 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2984 VATTR_SET(vap, va_mode, fxdr_unsigned(u_short, sp->sa_mode));
2985 }
2986 *(linkdata + linkdatalen) = '\0';
2987 if (vp) {
2988 error = EEXIST;
2989 goto out;
2990 }
2991
2992 /*
2993 * If the credentials were mapped, we should
2994 * map the same values in the attributes.
2995 */
2996 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
2997 int ismember;
2998 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
2999 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3000 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3001 }
3002 VATTR_SET(vap, va_type, VLNK);
3003 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3004 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3005
3006 /* authorize before creating */
3007 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
3008
3009 /* validate given attributes */
3010 if (!error) {
3011 error = vnode_authattr_new(dvp, vap, 0, &context);
3012 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3013 /*
3014 * Most NFS servers just ignore the UID/GID attributes, so we
3015 * try ignoring them if that'll help the request succeed.
3016 */
3017 VATTR_CLEAR_ACTIVE(vap, va_uid);
3018 VATTR_CLEAR_ACTIVE(vap, va_gid);
3019 error = vnode_authattr_new(dvp, vap, 0, &context);
3020 }
3021 }
3022 if (!error)
3023 error = VNOP_SYMLINK(dvp, &vp, &nd.ni_cnd, vap, linkdata, &context);
3024
3025 if (!error && v3) {
3026 if (vp == NULL) {
3027 nd.ni_cnd.cn_nameiop = LOOKUP;
3028 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
3029 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
3030 nd.ni_cnd.cn_context = &context;
3031 nd.ni_startdir = dvp;
3032 nd.ni_usedvp = dvp;
3033 error = lookup(&nd);
3034 if (!error)
3035 vp = nd.ni_vp;
3036 }
3037 if (!error) {
3038 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3039 if (!error) {
3040 nfsm_srv_vattr_init(&postat, v3);
3041 error = vnode_getattr(vp, &postat, &context);
3042 }
3043 }
3044 }
3045 out:
3046 /*
3047 * nameidone has to happen before we vnode_put(dvp)
3048 * since it may need to release the fs_nodelock on the dvp
3049 */
3050 nameidone(&nd);
3051 nd.ni_cnd.cn_nameiop = 0;
3052
3053 if (vp)
3054 vnode_put(vp);
3055 vnode_put(dvp);
3056 out1:
3057 if (linkdata)
3058 FREE(linkdata, M_TEMP);
3059 if (dirp) {
3060 nfsm_srv_vattr_init(&diraft, v3);
3061 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3062 vnode_put(dirp);
3063 }
3064 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3065 if (v3) {
3066 if (!error) {
3067 nfsm_srvpostop_fh(&nfh);
3068 nfsm_srvpostop_attr(0, &postat);
3069 }
3070 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3071 }
3072 return (0);
3073 nfsmout:
3074 if (nd.ni_cnd.cn_nameiop) {
3075 /*
3076 * nameidone has to happen before we vnode_put(dvp)
3077 * since it may need to release the fs_nodelock on the dvp
3078 */
3079 nameidone(&nd);
3080
3081 if (vp)
3082 vnode_put(vp);
3083 vnode_put(dvp);
3084 }
3085 if (dirp)
3086 vnode_put(dirp);
3087 if (linkdata)
3088 FREE(linkdata, M_TEMP);
3089 return (error);
3090 }
3091
3092 /*
3093 * nfs mkdir service
3094 */
3095 int
3096 nfsrv_mkdir(nfsd, slp, procp, mrq)
3097 struct nfsrv_descript *nfsd;
3098 struct nfssvc_sock *slp;
3099 proc_t procp;
3100 mbuf_t *mrq;
3101 {
3102 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3103 mbuf_t nam = nfsd->nd_nam;
3104 caddr_t dpos = nfsd->nd_dpos;
3105 struct vnode_attr dirfor, diraft, postat;
3106 struct vnode_attr va;
3107 struct vnode_attr *vap = &va;
3108 struct nfs_fattr *fp;
3109 struct nameidata nd;
3110 caddr_t cp;
3111 u_long *tl;
3112 long t1;
3113 caddr_t bpos;
3114 int error = 0, len;
3115 int dirfor_ret = 1, diraft_ret = 1;
3116 int v3 = (nfsd->nd_flag & ND_NFSV3);
3117 char *cp2;
3118 mbuf_t mb, mb2, mreq;
3119 vnode_t vp, dvp, dirp = NULL;
3120 struct nfs_filehandle nfh;
3121 struct nfs_export *nx;
3122 struct nfs_export_options *nxo;
3123 struct vfs_context context;
3124 uid_t saved_uid;
3125 kauth_acl_t xacl = NULL;
3126
3127 context.vc_proc = procp;
3128 context.vc_ucred = nfsd->nd_cr;
3129
3130 /*
3131 * Save the original credential UID in case they are
3132 * mapped and we need to map the IDs in the attributes.
3133 */
3134 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
3135
3136 nd.ni_cnd.cn_nameiop = 0;
3137 vp = dvp = NULL;
3138 nfsm_srvmtofh(&nfh);
3139 nfsm_srvnamesiz(len, v3);
3140
3141 nd.ni_cnd.cn_nameiop = CREATE;
3142 nd.ni_cnd.cn_flags = LOCKPARENT;
3143 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3144 if (!error)
3145 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3146 if (dirp) {
3147 if (v3) {
3148 nfsm_srv_pre_vattr_init(&dirfor, v3);
3149 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3150 } else {
3151 vnode_put(dirp);
3152 dirp = NULL;
3153 }
3154 }
3155 if (error) {
3156 nd.ni_cnd.cn_nameiop = 0;
3157 nfsm_reply(NFSX_WCCDATA(v3));
3158 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3159 if (dirp)
3160 vnode_put(dirp);
3161 return (0);
3162 }
3163 dvp = nd.ni_dvp;
3164 vp = nd.ni_vp;
3165
3166 VATTR_INIT(vap);
3167 if (v3) {
3168 nfsm_srvsattr(vap);
3169 } else {
3170 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
3171 VATTR_SET(vap, va_mode, nfstov_mode(*tl++));
3172 }
3173 VATTR_SET(vap, va_type, VDIR);
3174
3175 if (vp != NULL) {
3176 /*
3177 * nameidone has to happen before we vnode_put(dvp)
3178 * since it may need to release the fs_nodelock on the dvp
3179 */
3180 nameidone(&nd);
3181
3182 vnode_put(dvp);
3183 vnode_put(vp);
3184 error = EEXIST;
3185 goto out;
3186 }
3187
3188 /*
3189 * If the credentials were mapped, we should
3190 * map the same values in the attributes.
3191 */
3192 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
3193 int ismember;
3194 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
3195 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3196 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3197 }
3198
3199 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, &context, nxo, 0);
3200
3201 /* construct ACL and handle inheritance */
3202 if (!error) {
3203 error = kauth_acl_inherit(dvp,
3204 NULL,
3205 &xacl, /* isdir */
3206 1,
3207 &context);
3208
3209 if (!error && xacl != NULL)
3210 VATTR_SET(vap, va_acl, xacl);
3211 }
3212 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3213 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3214
3215 /* validate new-file security information */
3216 if (!error) {
3217 error = vnode_authattr_new(dvp, vap, 0, &context);
3218 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3219 /*
3220 * Most NFS servers just ignore the UID/GID attributes, so we
3221 * try ignoring them if that'll help the request succeed.
3222 */
3223 VATTR_CLEAR_ACTIVE(vap, va_uid);
3224 VATTR_CLEAR_ACTIVE(vap, va_gid);
3225 error = vnode_authattr_new(dvp, vap, 0, &context);
3226 }
3227 }
3228
3229 if (!error)
3230 error = VNOP_MKDIR(dvp, &vp, &nd.ni_cnd, vap, &context);
3231
3232 if (!error && !VATTR_ALL_SUPPORTED(vap))
3233 /*
3234 * If some of the requested attributes weren't handled by the VNOP,
3235 * use our fallback code.
3236 */
3237 error = vnode_setattr_fallback(vp, vap, &context);
3238
3239 if (xacl != NULL)
3240 kauth_acl_free(xacl);
3241
3242 if (!error) {
3243 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3244 if (!error) {
3245 nfsm_srv_vattr_init(&postat, v3);
3246 error = vnode_getattr(vp, &postat, &context);
3247 }
3248 vnode_put(vp);
3249 vp = NULL;
3250 }
3251 /*
3252 * nameidone has to happen before we vnode_put(dvp)
3253 * since it may need to release the fs_nodelock on the dvp
3254 */
3255 nameidone(&nd);
3256
3257 vnode_put(dvp);
3258 out:
3259 nd.ni_cnd.cn_nameiop = 0;
3260
3261 if (dirp) {
3262 nfsm_srv_vattr_init(&diraft, v3);
3263 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3264 vnode_put(dirp);
3265 }
3266 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3267 if (v3) {
3268 if (!error) {
3269 nfsm_srvpostop_fh(&nfh);
3270 nfsm_srvpostop_attr(0, &postat);
3271 }
3272 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3273 } else {
3274 nfsm_srvfhtom(&nfh, v3);
3275 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
3276 nfsm_srvfillattr(&postat, fp);
3277 }
3278 return (0);
3279 nfsmout:
3280 if (nd.ni_cnd.cn_nameiop) {
3281 /*
3282 * nameidone has to happen before we vnode_put(dvp)
3283 * since it may need to release the fs_nodelock on the dvp
3284 */
3285 nameidone(&nd);
3286 vnode_put(dvp);
3287 if (vp)
3288 vnode_put(vp);
3289 }
3290 if (dirp)
3291 vnode_put(dirp);
3292 return (error);
3293 }
3294
3295 /*
3296 * nfs rmdir service
3297 */
3298 int
3299 nfsrv_rmdir(nfsd, slp, procp, mrq)
3300 struct nfsrv_descript *nfsd;
3301 struct nfssvc_sock *slp;
3302 proc_t procp;
3303 mbuf_t *mrq;
3304 {
3305 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3306 mbuf_t nam = nfsd->nd_nam;
3307 caddr_t dpos = nfsd->nd_dpos;
3308 u_long *tl;
3309 long t1;
3310 caddr_t bpos;
3311 int error = 0, len;
3312 int dirfor_ret = 1, diraft_ret = 1;
3313 int v3 = (nfsd->nd_flag & ND_NFSV3);
3314 char *cp2;
3315 mbuf_t mb, mreq;
3316 vnode_t vp, dvp, dirp = NULL;
3317 struct vnode_attr dirfor, diraft;
3318 struct nfs_filehandle nfh;
3319 struct nfs_export *nx;
3320 struct nfs_export_options *nxo;
3321 struct nameidata nd;
3322 struct vfs_context context;
3323
3324 context.vc_proc = procp;
3325 context.vc_ucred = nfsd->nd_cr;
3326
3327 vp = dvp = NULL;
3328 nfsm_srvmtofh(&nfh);
3329 nfsm_srvnamesiz(len, v3);
3330
3331 nd.ni_cnd.cn_nameiop = DELETE;
3332 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
3333 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3334 if (!error)
3335 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3336 if (dirp) {
3337 if (v3) {
3338 nfsm_srv_pre_vattr_init(&dirfor, v3);
3339 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3340 } else {
3341 vnode_put(dirp);
3342 dirp = NULL;
3343 }
3344 }
3345 if (error) {
3346 nfsm_reply(NFSX_WCCDATA(v3));
3347 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3348 if (dirp)
3349 vnode_put(dirp);
3350 return (0);
3351 }
3352 dvp = nd.ni_dvp;
3353 vp = nd.ni_vp;
3354
3355 if (vnode_vtype(vp) != VDIR) {
3356 error = ENOTDIR;
3357 goto out;
3358 }
3359 /*
3360 * No rmdir "." please.
3361 */
3362 if (dvp == vp) {
3363 error = EINVAL;
3364 goto out;
3365 }
3366 /*
3367 * The root of a mounted filesystem cannot be deleted.
3368 */
3369 if (vnode_isvroot(vp))
3370 error = EBUSY;
3371 if (!error)
3372 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
3373 if (!error)
3374 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, &context);
3375 out:
3376 /*
3377 * nameidone has to happen before we vnode_put(dvp)
3378 * since it may need to release the fs_nodelock on the dvp
3379 */
3380 nameidone(&nd);
3381
3382 vnode_put(dvp);
3383 vnode_put(vp);
3384
3385 if (dirp) {
3386 nfsm_srv_vattr_init(&diraft, v3);
3387 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3388 vnode_put(dirp);
3389 }
3390 nfsm_reply(NFSX_WCCDATA(v3));
3391 if (v3) {
3392 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3393 return (0);
3394 }
3395 nfsmout:
3396 return (error);
3397 }
3398
3399 /*
3400 * nfs readdir service
3401 * - mallocs what it thinks is enough to read
3402 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3403 * - calls VNOP_READDIR()
3404 * - loops around building the reply
3405 * if the output generated exceeds count break out of loop
3406 * The nfsm_clget macro is used here so that the reply will be packed
3407 * tightly in mbuf clusters.
3408 * - it only knows that it has encountered eof when the VNOP_READDIR()
3409 * reads nothing
3410 * - as such one readdir rpc will return eof false although you are there
3411 * and then the next will return eof
3412 * - it trims out records with d_fileno == 0
3413 * this doesn't matter for Unix clients, but they might confuse clients
3414 * for other os'.
3415 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3416 * than requested, but this may not apply to all filesystems. For
3417 * example, client NFS does not { although it is never remote mounted
3418 * anyhow }
3419 * The alternate call nfsrv_readdirplus() does lookups as well.
3420 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3421 * are supposed to cover. For readdir, the count is the total number of
3422 * bytes included in everything from the directory's postopattr through
3423 * the EOF flag. For readdirplus, the maxcount is the same, and the
3424 * dircount includes all that except for the entry attributes and handles.
3425 */
3426
3427 int
3428 nfsrv_readdir(nfsd, slp, procp, mrq)
3429 struct nfsrv_descript *nfsd;
3430 struct nfssvc_sock *slp;
3431 proc_t procp;
3432 mbuf_t *mrq;
3433 {
3434 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3435 mbuf_t nam = nfsd->nd_nam;
3436 caddr_t dpos = nfsd->nd_dpos;
3437 char *bp, *be;
3438 mbuf_t mp;
3439 struct direntry *dp;
3440 caddr_t cp;
3441 u_long *tl;
3442 long t1;
3443 caddr_t bpos;
3444 mbuf_t mb, mb2, mreq, mp2;
3445 char *cpos, *cend, *cp2, *rbuf;
3446 vnode_t vp;
3447 struct vnode_attr at;
3448 struct nfs_filehandle nfh;
3449 struct nfs_export *nx;
3450 struct nfs_export_options *nxo;
3451 uio_t auio;
3452 char uio_buf[ UIO_SIZEOF(1) ];
3453 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3454 int siz, count, fullsiz, eofflag, nentries = 0;
3455 int v3 = (nfsd->nd_flag & ND_NFSV3);
3456 u_quad_t off, toff, verf;
3457 nfsuint64 tquad;
3458 int vnopflag;
3459 struct vfs_context context;
3460
3461 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3462
3463 nfsm_srvmtofh(&nfh);
3464 if (v3) {
3465 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
3466 fxdr_hyper(tl, &toff);
3467 tl += 2;
3468 fxdr_hyper(tl, &verf);
3469 tl += 2;
3470 } else {
3471 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
3472 toff = fxdr_unsigned(u_quad_t, *tl++);
3473 }
3474 off = toff;
3475 count = fxdr_unsigned(int, *tl);
3476 siz = ((count + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3477 xfer = NFS_SRVMAXDATA(nfsd);
3478 if (siz > xfer)
3479 siz = xfer;
3480 fullsiz = siz;
3481 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
3482 nfsm_reply(NFSX_UNSIGNED);
3483 nfsm_srvpostop_attr(getret, &at);
3484 return (0);
3485 }
3486 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3487 vnode_put(vp);
3488 nfsm_reply(NFSX_UNSIGNED);
3489 nfsm_srvpostop_attr(getret, &at);
3490 return (0);
3491 }
3492 context.vc_proc = procp;
3493 context.vc_ucred = nfsd->nd_cr;
3494 if (!v3 || (nxo->nxo_flags & NX_32BITCLIENTS))
3495 vnopflag |= VNODE_READDIR_SEEKOFF32;
3496 if (v3) {
3497 nfsm_srv_vattr_init(&at, v3);
3498 error = getret = vnode_getattr(vp, &at, &context);
3499 if (!error && toff && verf && verf != at.va_filerev)
3500 error = NFSERR_BAD_COOKIE;
3501 }
3502 if (!error)
3503 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3504 if (error) {
3505 vnode_put(vp);
3506 nfsm_reply(NFSX_POSTOPATTR(v3));
3507 nfsm_srvpostop_attr(getret, &at);
3508 return (0);
3509 }
3510 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3511 if (!rbuf) {
3512 error = ENOMEM;
3513 vnode_put(vp);
3514 nfsm_reply(NFSX_POSTOPATTR(v3));
3515 nfsm_srvpostop_attr(getret, &at);
3516 return (0);
3517 }
3518 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3519 &uio_buf[0], sizeof(uio_buf));
3520 if (!auio) {
3521 error = ENOMEM;
3522 FREE(rbuf, M_TEMP);
3523 vnode_put(vp);
3524 nfsm_reply(NFSX_POSTOPATTR(v3));
3525 nfsm_srvpostop_attr(getret, &at);
3526 return (0);
3527 }
3528 again:
3529 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3530 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3531
3532 eofflag = 0;
3533 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3534 off = uio_offset(auio);
3535
3536 if (v3) {
3537 nfsm_srv_vattr_init(&at, v3);
3538 getret = vnode_getattr(vp, &at, &context);
3539 if (!error)
3540 error = getret;
3541 }
3542 if (error) {
3543 vnode_put(vp);
3544 FREE(rbuf, M_TEMP);
3545 nfsm_reply(NFSX_POSTOPATTR(v3));
3546 nfsm_srvpostop_attr(getret, &at);
3547 return (0);
3548 }
3549 if (uio_resid(auio) != 0) {
3550 // LP64todo - fix this
3551 siz -= uio_resid(auio);
3552
3553 /*
3554 * If nothing read, return eof
3555 * rpc reply
3556 */
3557 if (siz == 0) {
3558 vnode_put(vp);
3559 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
3560 2 * NFSX_UNSIGNED);
3561 if (v3) {
3562 nfsm_srvpostop_attr(getret, &at);
3563 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3564 txdr_hyper(&at.va_filerev, tl);
3565 tl += 2;
3566 } else
3567 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3568 *tl++ = nfs_false;
3569 *tl = nfs_true;
3570 FREE(rbuf, M_TEMP);
3571 return (0);
3572 }
3573 }
3574
3575 /*
3576 * Check for degenerate cases of nothing useful read.
3577 * If so go try again
3578 */
3579 cpos = rbuf;
3580 cend = rbuf + siz;
3581 dp = (struct direntry *)cpos;
3582 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3583 cpos += dp->d_reclen;
3584 dp = (struct direntry *)cpos;
3585 nentries--;
3586 }
3587 if (cpos >= cend || nentries == 0) {
3588 toff = off;
3589 siz = fullsiz;
3590 goto again;
3591 }
3592
3593 vnode_put(vp);
3594 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
3595 if (v3) {
3596 len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3597 nfsm_srvpostop_attr(getret, &at);
3598 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3599 txdr_hyper(&at.va_filerev, tl);
3600 } else
3601 len = 2 * NFSX_UNSIGNED;
3602 mp = mp2 = mb;
3603 bp = bpos;
3604 be = bp + mbuf_trailingspace(mp);
3605
3606 /* Loop through the records and build reply */
3607 while (cpos < cend && nentries > 0) {
3608 if (dp->d_fileno != 0) {
3609 nlen = dp->d_namlen;
3610 if (!v3 && (nlen > NFS_MAXNAMLEN))
3611 nlen = NFS_MAXNAMLEN;
3612 rem = nfsm_rndup(nlen)-nlen;
3613 len += (4 * NFSX_UNSIGNED + nlen + rem);
3614 if (v3)
3615 len += 2 * NFSX_UNSIGNED;
3616 if (len > count) {
3617 eofflag = 0;
3618 break;
3619 }
3620 /*
3621 * Build the directory record xdr from
3622 * the direntry entry.
3623 */
3624 nfsm_clget;
3625 *tl = nfs_true;
3626 bp += NFSX_UNSIGNED;
3627 nfsm_clget;
3628 if (v3) {
3629 txdr_hyper(&dp->d_fileno, &tquad);
3630 *tl = tquad.nfsuquad[0];
3631 bp += NFSX_UNSIGNED;
3632 nfsm_clget;
3633 *tl = tquad.nfsuquad[1];
3634 bp += NFSX_UNSIGNED;
3635 } else {
3636 *tl = txdr_unsigned(dp->d_fileno);
3637 bp += NFSX_UNSIGNED;
3638 }
3639 nfsm_clget;
3640 *tl = txdr_unsigned(nlen);
3641 bp += NFSX_UNSIGNED;
3642
3643 /* And loop around copying the name */
3644 xfer = nlen;
3645 cp = dp->d_name;
3646 while (xfer > 0) {
3647 nfsm_clget;
3648 if ((bp+xfer) > be)
3649 tsiz = be-bp;
3650 else
3651 tsiz = xfer;
3652 bcopy(cp, bp, tsiz);
3653 bp += tsiz;
3654 xfer -= tsiz;
3655 if (xfer > 0)
3656 cp += tsiz;
3657 }
3658 /* And null pad to a long boundary */
3659 for (i = 0; i < rem; i++)
3660 *bp++ = '\0';
3661
3662 /* Finish off the record with the cookie */
3663 nfsm_clget;
3664 if (v3) {
3665 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3666 dp->d_seekoff &= 0x00000000ffffffffULL;
3667 txdr_hyper(&dp->d_seekoff, &tquad);
3668 *tl = tquad.nfsuquad[0];
3669 bp += NFSX_UNSIGNED;
3670 nfsm_clget;
3671 *tl = tquad.nfsuquad[1];
3672 bp += NFSX_UNSIGNED;
3673 } else {
3674 *tl = txdr_unsigned(dp->d_seekoff);
3675 bp += NFSX_UNSIGNED;
3676 }
3677 }
3678 cpos += dp->d_reclen;
3679 dp = (struct direntry *)cpos;
3680 nentries--;
3681 }
3682 nfsm_clget;
3683 *tl = nfs_false;
3684 bp += NFSX_UNSIGNED;
3685 nfsm_clget;
3686 if (eofflag)
3687 *tl = nfs_true;
3688 else
3689 *tl = nfs_false;
3690 bp += NFSX_UNSIGNED;
3691 if (mp != mb) {
3692 if (bp < be)
3693 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
3694 } else
3695 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
3696 FREE(rbuf, M_TEMP);
3697 nfsmout:
3698 return (error);
3699 }
3700
3701 struct flrep {
3702 nfsuint64 fl_off;
3703 u_long fl_postopok;
3704 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
3705 u_long fl_fhok;
3706 u_long fl_fhsize;
3707 u_long fl_nfh[NFSX_V3FHMAX / sizeof (u_long)];
3708 };
3709
3710 int
3711 nfsrv_readdirplus(nfsd, slp, procp, mrq)
3712 struct nfsrv_descript *nfsd;
3713 struct nfssvc_sock *slp;
3714 proc_t procp;
3715 mbuf_t *mrq;
3716 {
3717 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3718 mbuf_t nam = nfsd->nd_nam;
3719 caddr_t dpos = nfsd->nd_dpos;
3720 char *bp, *be;
3721 mbuf_t mp;
3722 struct direntry *dp;
3723 caddr_t cp;
3724 u_long *tl;
3725 long t1;
3726 caddr_t bpos;
3727 mbuf_t mb, mb2, mreq, mp2;
3728 char *cpos, *cend, *cp2, *rbuf;
3729 vnode_t vp, nvp;
3730 struct flrep fl;
3731 struct nfs_filehandle dnfh, *nfhp = (struct nfs_filehandle *)&fl.fl_fhsize;
3732 u_long fhsize;
3733 struct nfs_export *nx;
3734 struct nfs_export_options *nxo;
3735 uio_t auio;
3736 char uio_buf[ UIO_SIZEOF(1) ];
3737 struct vnode_attr va, at, *vap = &va;
3738 struct nfs_fattr *fp;
3739 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3740 int siz, count, fullsiz, eofflag, dirlen, nentries = 0, isdotdot;
3741 u_quad_t off, toff, verf;
3742 nfsuint64 tquad;
3743 int vnopflag;
3744 struct vfs_context context;
3745
3746 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3747 vp = NULL;
3748 nfsm_srvmtofh(&dnfh);
3749 nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
3750 fxdr_hyper(tl, &toff);
3751 tl += 2;
3752 fxdr_hyper(tl, &verf);
3753 tl += 2;
3754 siz = fxdr_unsigned(int, *tl++);
3755 count = fxdr_unsigned(int, *tl);
3756 off = toff;
3757 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3758 xfer = NFS_SRVMAXDATA(nfsd);
3759 if (siz > xfer)
3760 siz = xfer;
3761 fullsiz = siz;
3762 if ((error = nfsrv_fhtovp(&dnfh, nam, TRUE, &vp, &nx, &nxo))) {
3763 nfsm_reply(NFSX_UNSIGNED);
3764 nfsm_srvpostop_attr(getret, &at);
3765 return (0);
3766 }
3767 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3768 vnode_put(vp);
3769 nfsm_reply(NFSX_UNSIGNED);
3770 nfsm_srvpostop_attr(getret, &at);
3771 return (0);
3772 }
3773 context.vc_proc = procp;
3774 context.vc_ucred = nfsd->nd_cr;
3775 if (nxo->nxo_flags & NX_32BITCLIENTS)
3776 vnopflag |= VNODE_READDIR_SEEKOFF32;
3777 nfsm_srv_vattr_init(&at, 1);
3778 error = getret = vnode_getattr(vp, &at, &context);
3779 if (!error && toff && verf && verf != at.va_filerev)
3780 error = NFSERR_BAD_COOKIE;
3781 if (!error)
3782 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3783 if (error) {
3784 vnode_put(vp);
3785 vp = NULL;
3786 nfsm_reply(NFSX_V3POSTOPATTR);
3787 nfsm_srvpostop_attr(getret, &at);
3788 return (0);
3789 }
3790 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3791 if (!rbuf) {
3792 error = ENOMEM;
3793 vnode_put(vp);
3794 vp = NULL;
3795 nfsm_reply(NFSX_V3POSTOPATTR);
3796 nfsm_srvpostop_attr(getret, &at);
3797 return (0);
3798 }
3799 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3800 &uio_buf[0], sizeof(uio_buf));
3801 if (!auio) {
3802 error = ENOMEM;
3803 FREE(rbuf, M_TEMP);
3804 vnode_put(vp);
3805 vp = NULL;
3806 nfsm_reply(NFSX_V3POSTOPATTR);
3807 nfsm_srvpostop_attr(getret, &at);
3808 return (0);
3809 }
3810 again:
3811 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3812 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3813 eofflag = 0;
3814 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3815 off = uio_offset(auio);
3816 nfsm_srv_vattr_init(&at, 1);
3817 getret = vnode_getattr(vp, &at, &context);
3818
3819 if (!error)
3820 error = getret;
3821 if (error) {
3822 vnode_put(vp);
3823 vp = NULL;
3824 FREE(rbuf, M_TEMP);
3825 nfsm_reply(NFSX_V3POSTOPATTR);
3826 nfsm_srvpostop_attr(getret, &at);
3827 return (0);
3828 }
3829 if (uio_resid(auio) != 0) {
3830 // LP64todo - fix this
3831 siz -= uio_resid(auio);
3832
3833 /*
3834 * If nothing read, return eof
3835 * rpc reply
3836 */
3837 if (siz == 0) {
3838 vnode_put(vp);
3839 vp = NULL;
3840 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3841 2 * NFSX_UNSIGNED);
3842 nfsm_srvpostop_attr(getret, &at);
3843 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3844 txdr_hyper(&at.va_filerev, tl);
3845 tl += 2;
3846 *tl++ = nfs_false;
3847 *tl = nfs_true;
3848 FREE(rbuf, M_TEMP);
3849 return (0);
3850 }
3851 }
3852
3853 /*
3854 * Check for degenerate cases of nothing useful read.
3855 * If so go try again
3856 */
3857 cpos = rbuf;
3858 cend = rbuf + siz;
3859 dp = (struct direntry *)cpos;
3860 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3861 cpos += dp->d_reclen;
3862 dp = (struct direntry *)cpos;
3863 nentries--;
3864 }
3865 if (cpos >= cend || nentries == 0) {
3866 toff = off;
3867 siz = fullsiz;
3868 goto again;
3869 }
3870
3871 /*
3872 * Probe one of the directory entries to see if the filesystem
3873 * supports VGET.
3874 */
3875 if ((error = VFS_VGET(vnode_mount(vp), (ino64_t)dp->d_fileno, &nvp, &context))) {
3876 if (error == ENOTSUP) /* let others get passed back */
3877 error = NFSERR_NOTSUPP;
3878 vnode_put(vp);
3879 vp = NULL;
3880 FREE(rbuf, M_TEMP);
3881 nfsm_reply(NFSX_V3POSTOPATTR);
3882 nfsm_srvpostop_attr(getret, &at);
3883 return (0);
3884 }
3885 vnode_put(nvp);
3886
3887 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3888 nfsm_reply(count);
3889 nfsm_srvpostop_attr(getret, &at);
3890 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3891 txdr_hyper(&at.va_filerev, tl);
3892 mp = mp2 = mb;
3893 bp = bpos;
3894 be = bp + mbuf_trailingspace(mp);
3895
3896 /* Loop through the records and build reply */
3897 while (cpos < cend && nentries > 0) {
3898 if (dp->d_fileno != 0) {
3899 nlen = dp->d_namlen;
3900 rem = nfsm_rndup(nlen)-nlen;
3901
3902 /*
3903 * Got to get the vnode for lookup per entry.
3904 */
3905 if (VFS_VGET(vnode_mount(vp), (ino64_t)dp->d_fileno, &nvp, &context))
3906 goto invalid;
3907 isdotdot = ((dp->d_namlen == 2) &&
3908 (dp->d_name[0] == '.') && (dp->d_name[1] == '.'));
3909 if (nfsrv_vptofh(nx, 0, (isdotdot ? &dnfh : NULL), nvp, &context, nfhp)) {
3910 // XXX file handle is optional, so we should be able to
3911 // XXX return this entry without the file handle
3912 vnode_put(nvp);
3913 goto invalid;
3914 }
3915 nfsm_srv_vattr_init(vap, 1);
3916 if (vnode_getattr(nvp, vap, &context)) {
3917 // XXX attributes are optional, so we should be able to
3918 // XXX return this entry without the attributes
3919 vnode_put(nvp);
3920 goto invalid;
3921 }
3922 vnode_put(nvp);
3923
3924 /*
3925 * If either the dircount or maxcount will be
3926 * exceeded, get out now. Both of these lengths
3927 * are calculated conservatively, including all
3928 * XDR overheads.
3929 */
3930 len += (8 * NFSX_UNSIGNED + nlen + rem + nfhp->nfh_len +
3931 NFSX_V3POSTOPATTR);
3932 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3933 if (len > count || dirlen > fullsiz) {
3934 eofflag = 0;
3935 break;
3936 }
3937
3938 /*
3939 * Build the directory record xdr from
3940 * the direntry entry.
3941 */
3942 fp = (struct nfs_fattr *)&fl.fl_fattr;
3943 nfsm_srvfillattr(vap, fp);
3944 fhsize = nfhp->nfh_len;
3945 fl.fl_fhsize = txdr_unsigned(fhsize);
3946 fl.fl_fhok = nfs_true;
3947 fl.fl_postopok = nfs_true;
3948 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3949 dp->d_seekoff &= 0x00000000ffffffffULL;
3950 txdr_hyper(&dp->d_seekoff, &fl.fl_off);
3951
3952 nfsm_clget;
3953 *tl = nfs_true;
3954 bp += NFSX_UNSIGNED;
3955
3956 nfsm_clget;
3957 txdr_hyper(&dp->d_fileno, &tquad);
3958 *tl = tquad.nfsuquad[0];
3959 bp += NFSX_UNSIGNED;
3960 nfsm_clget;
3961 *tl = tquad.nfsuquad[1];
3962 bp += NFSX_UNSIGNED;
3963
3964 nfsm_clget;
3965 *tl = txdr_unsigned(nlen);
3966 bp += NFSX_UNSIGNED;
3967
3968 /* And loop around copying the name */
3969 xfer = nlen;
3970 cp = dp->d_name;
3971 while (xfer > 0) {
3972 nfsm_clget;
3973 if ((bp + xfer) > be)
3974 tsiz = be - bp;
3975 else
3976 tsiz = xfer;
3977 bcopy(cp, bp, tsiz);
3978 bp += tsiz;
3979 xfer -= tsiz;
3980 if (xfer > 0)
3981 cp += tsiz;
3982 }
3983 /* And null pad to a long boundary */
3984 for (i = 0; i < rem; i++)
3985 *bp++ = '\0';
3986
3987 /*
3988 * Now copy the flrep structure out.
3989 */
3990 xfer = sizeof(struct flrep) - sizeof(fl.fl_nfh) + fhsize;
3991 cp = (caddr_t)&fl;
3992 while (xfer > 0) {
3993 nfsm_clget;
3994 if ((bp + xfer) > be)
3995 tsiz = be - bp;
3996 else
3997 tsiz = xfer;
3998 bcopy(cp, bp, tsiz);
3999 bp += tsiz;
4000 xfer -= tsiz;
4001 if (xfer > 0)
4002 cp += tsiz;
4003 }
4004 }
4005 invalid:
4006 cpos += dp->d_reclen;
4007 dp = (struct direntry *)cpos;
4008 nentries--;
4009 }
4010 vnode_put(vp);
4011 vp = NULL;
4012 nfsm_clget;
4013 *tl = nfs_false;
4014 bp += NFSX_UNSIGNED;
4015 nfsm_clget;
4016 if (eofflag)
4017 *tl = nfs_true;
4018 else
4019 *tl = nfs_false;
4020 bp += NFSX_UNSIGNED;
4021 if (mp != mb) {
4022 if (bp < be)
4023 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
4024 } else
4025 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
4026 FREE(rbuf, M_TEMP);
4027 nfsmout:
4028 if (vp)
4029 vnode_put(vp);
4030 return (error);
4031 }
4032
4033 /*
4034 * nfs commit service
4035 */
4036 int
4037 nfsrv_commit(nfsd, slp, procp, mrq)
4038 struct nfsrv_descript *nfsd;
4039 struct nfssvc_sock *slp;
4040 proc_t procp;
4041 mbuf_t *mrq;
4042 {
4043 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4044 mbuf_t nam = nfsd->nd_nam;
4045 caddr_t dpos = nfsd->nd_dpos;
4046 struct vnode_attr bfor, aft;
4047 vnode_t vp;
4048 struct nfs_filehandle nfh;
4049 struct nfs_export *nx;
4050 struct nfs_export_options *nxo;
4051 u_long *tl;
4052 long t1;
4053 caddr_t bpos;
4054 int error = 0, for_ret = 1, aft_ret = 1, count;
4055 char *cp2;
4056 mbuf_t mb, mb2, mreq;
4057 u_quad_t off;
4058 struct vfs_context context;
4059
4060 nfsm_srvmtofh(&nfh);
4061 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
4062
4063 /*
4064 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4065 * count parameters, so these arguments are useless (someday maybe).
4066 */
4067 fxdr_hyper(tl, &off);
4068 tl += 2;
4069 count = fxdr_unsigned(int, *tl);
4070 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4071 nfsm_reply(2 * NFSX_UNSIGNED);
4072 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4073 return (0);
4074 }
4075 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4076 vnode_put(vp);
4077 nfsm_reply(2 * NFSX_UNSIGNED);
4078 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4079 return (0);
4080 }
4081 context.vc_proc = procp;
4082 context.vc_ucred = nfsd->nd_cr;
4083
4084 nfsm_srv_pre_vattr_init(&bfor, 1);
4085 for_ret = vnode_getattr(vp, &bfor, &context);
4086 error = VNOP_FSYNC(vp, MNT_WAIT, &context);
4087 nfsm_srv_vattr_init(&aft, 1);
4088 aft_ret = vnode_getattr(vp, &aft, &context);
4089 vnode_put(vp);
4090 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
4091 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4092 if (!error) {
4093 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
4094 *tl++ = txdr_unsigned(boottime_sec());
4095 *tl = txdr_unsigned(0);
4096 } else
4097 return (0);
4098 nfsmout:
4099 return (error);
4100 }
4101
4102 /*
4103 * nfs statfs service
4104 */
4105 int
4106 nfsrv_statfs(nfsd, slp, procp, mrq)
4107 struct nfsrv_descript *nfsd;
4108 struct nfssvc_sock *slp;
4109 proc_t procp;
4110 mbuf_t *mrq;
4111 {
4112 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4113 mbuf_t nam = nfsd->nd_nam;
4114 caddr_t dpos = nfsd->nd_dpos;
4115 struct vfs_attr va;
4116 struct nfs_statfs *sfp;
4117 u_long *tl;
4118 long t1;
4119 caddr_t bpos;
4120 int error = 0, getret = 1;
4121 int v3 = (nfsd->nd_flag & ND_NFSV3);
4122 char *cp2;
4123 mbuf_t mb, mb2, mreq;
4124 vnode_t vp;
4125 struct vnode_attr at;
4126 struct nfs_filehandle nfh;
4127 struct nfs_export *nx;
4128 struct nfs_export_options *nxo;
4129 u_quad_t tval;
4130 off_t blksize;
4131 struct vfs_context context;
4132
4133 nfsm_srvmtofh(&nfh);
4134 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4135 nfsm_reply(NFSX_UNSIGNED);
4136 nfsm_srvpostop_attr(getret, &at);
4137 return (0);
4138 }
4139 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4140 vnode_put(vp);
4141 nfsm_reply(NFSX_UNSIGNED);
4142 nfsm_srvpostop_attr(getret, &at);
4143 return (0);
4144 }
4145 context.vc_proc = procp;
4146 context.vc_ucred = nfsd->nd_cr;
4147
4148 VFSATTR_INIT(&va);
4149 VFSATTR_WANTED(&va, f_blocks);
4150 VFSATTR_WANTED(&va, f_bavail);
4151 VFSATTR_WANTED(&va, f_files);
4152 VFSATTR_WANTED(&va, f_ffree);
4153 error = vfs_getattr(vnode_mount(vp), &va, &context);
4154 blksize = vnode_mount(vp)->mnt_vfsstat.f_bsize;
4155 nfsm_srv_vattr_init(&at, v3);
4156 getret = vnode_getattr(vp, &at, &context);
4157 vnode_put(vp);
4158 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
4159 if (v3)
4160 nfsm_srvpostop_attr(getret, &at);
4161 if (error)
4162 return (0);
4163 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
4164 if (v3) {
4165 tval = (u_quad_t)(va.f_blocks * blksize);
4166 txdr_hyper(&tval, &sfp->sf_tbytes);
4167 tval = (u_quad_t)(va.f_bfree * blksize);
4168 txdr_hyper(&tval, &sfp->sf_fbytes);
4169 tval = (u_quad_t)(va.f_bavail * blksize);
4170 txdr_hyper(&tval, &sfp->sf_abytes);
4171 txdr_hyper(&va.f_files, &sfp->sf_tfiles);
4172 txdr_hyper(&va.f_ffree, &sfp->sf_ffiles);
4173 txdr_hyper(&va.f_ffree, &sfp->sf_afiles);
4174 sfp->sf_invarsec = 0;
4175 } else {
4176 sfp->sf_tsize = txdr_unsigned(NFS_V2MAXDATA);
4177 sfp->sf_bsize = txdr_unsigned((unsigned)blksize);
4178 sfp->sf_blocks = txdr_unsigned((unsigned)va.f_blocks);
4179 sfp->sf_bfree = txdr_unsigned((unsigned)va.f_bfree);
4180 sfp->sf_bavail = txdr_unsigned((unsigned)va.f_bavail);
4181 }
4182 nfsmout:
4183 return (error);
4184 }
4185
4186 /*
4187 * nfs fsinfo service
4188 */
4189 int
4190 nfsrv_fsinfo(nfsd, slp, procp, mrq)
4191 struct nfsrv_descript *nfsd;
4192 struct nfssvc_sock *slp;
4193 proc_t procp;
4194 mbuf_t *mrq;
4195 {
4196 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4197 mbuf_t nam = nfsd->nd_nam;
4198 caddr_t dpos = nfsd->nd_dpos;
4199 u_long *tl;
4200 struct nfsv3_fsinfo *sip;
4201 long t1;
4202 caddr_t bpos;
4203 int error = 0, getret = 1, prefsize, maxsize;
4204 char *cp2;
4205 mbuf_t mb, mb2, mreq;
4206 vnode_t vp;
4207 struct vnode_attr at;
4208 struct nfs_filehandle nfh;
4209 struct nfs_export *nx;
4210 struct nfs_export_options *nxo;
4211 struct vfs_context context;
4212
4213 nfsm_srvmtofh(&nfh);
4214 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4215 nfsm_reply(NFSX_UNSIGNED);
4216 nfsm_srvpostop_attr(getret, &at);
4217 return (0);
4218 }
4219 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4220 vnode_put(vp);
4221 nfsm_reply(NFSX_UNSIGNED);
4222 nfsm_srvpostop_attr(getret, &at);
4223 return (0);
4224 }
4225 context.vc_proc = procp;
4226 context.vc_ucred = nfsd->nd_cr;
4227
4228 nfsm_srv_vattr_init(&at, 1);
4229 getret = vnode_getattr(vp, &at, &context);
4230 vnode_put(vp);
4231 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
4232 nfsm_srvpostop_attr(getret, &at);
4233 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
4234
4235 /*
4236 * XXX
4237 * There should be file system VFS OP(s) to get this information.
4238 * For now, assume our usual NFS defaults.
4239 */
4240 if (slp->ns_sotype == SOCK_DGRAM) {
4241 maxsize = NFS_MAXDGRAMDATA;
4242 prefsize = NFS_PREFDGRAMDATA;
4243 } else
4244 maxsize = prefsize = NFS_MAXDATA;
4245 sip->fs_rtmax = txdr_unsigned(maxsize);
4246 sip->fs_rtpref = txdr_unsigned(prefsize);
4247 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
4248 sip->fs_wtmax = txdr_unsigned(maxsize);
4249 sip->fs_wtpref = txdr_unsigned(prefsize);
4250 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
4251 sip->fs_dtpref = txdr_unsigned(prefsize);
4252 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
4253 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
4254 sip->fs_timedelta.nfsv3_sec = 0;
4255 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
4256 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
4257 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
4258 NFSV3FSINFO_CANSETTIME);
4259 nfsmout:
4260 return (error);
4261 }
4262
4263 /*
4264 * nfs pathconf service
4265 */
4266 int
4267 nfsrv_pathconf(nfsd, slp, procp, mrq)
4268 struct nfsrv_descript *nfsd;
4269 struct nfssvc_sock *slp;
4270 proc_t procp;
4271 mbuf_t *mrq;
4272 {
4273 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4274 mbuf_t nam = nfsd->nd_nam;
4275 caddr_t dpos = nfsd->nd_dpos;
4276 u_long *tl;
4277 struct nfsv3_pathconf *pc;
4278 long t1;
4279 caddr_t bpos;
4280 int error = 0, getret = 1, linkmax, namemax;
4281 int chownres, notrunc, case_sensitive, case_preserving;
4282 char *cp2;
4283 mbuf_t mb, mb2, mreq;
4284 vnode_t vp;
4285 struct vnode_attr at;
4286 struct nfs_filehandle nfh;
4287 struct nfs_export *nx;
4288 struct nfs_export_options *nxo;
4289 struct vfs_context context;
4290
4291 nfsm_srvmtofh(&nfh);
4292 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4293 nfsm_reply(NFSX_UNSIGNED);
4294 nfsm_srvpostop_attr(getret, &at);
4295 return (0);
4296 }
4297 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4298 vnode_put(vp);
4299 nfsm_reply(NFSX_UNSIGNED);
4300 nfsm_srvpostop_attr(getret, &at);
4301 return (0);
4302 }
4303 context.vc_proc = procp;
4304 context.vc_ucred = nfsd->nd_cr;
4305
4306 error = VNOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax, &context);
4307 if (!error)
4308 error = VNOP_PATHCONF(vp, _PC_NAME_MAX, &namemax, &context);
4309 if (!error)
4310 error = VNOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres, &context);
4311 if (!error)
4312 error = VNOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc, &context);
4313 if (!error)
4314 error = VNOP_PATHCONF(vp, _PC_CASE_SENSITIVE, &case_sensitive, &context);
4315 if (!error)
4316 error = VNOP_PATHCONF(vp, _PC_CASE_PRESERVING, &case_preserving, &context);
4317 nfsm_srv_vattr_init(&at, 1);
4318 getret = vnode_getattr(vp, &at, &context);
4319 vnode_put(vp);
4320 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
4321 nfsm_srvpostop_attr(getret, &at);
4322 if (error)
4323 return (0);
4324 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
4325
4326 pc->pc_linkmax = txdr_unsigned(linkmax);
4327 pc->pc_namemax = txdr_unsigned(namemax);
4328 pc->pc_notrunc = txdr_unsigned(notrunc);
4329 pc->pc_chownrestricted = txdr_unsigned(chownres);
4330 pc->pc_caseinsensitive = txdr_unsigned(!case_sensitive);
4331 pc->pc_casepreserving = txdr_unsigned(case_preserving);
4332
4333 nfsmout:
4334 return (error);
4335 }
4336
4337 /*
4338 * Null operation, used by clients to ping server
4339 */
4340 /* ARGSUSED */
4341 int
4342 nfsrv_null(
4343 struct nfsrv_descript *nfsd,
4344 struct nfssvc_sock *slp,
4345 __unused proc_t procp,
4346 mbuf_t *mrq)
4347 {
4348 mbuf_t mrep = nfsd->nd_mrep;
4349 caddr_t bpos;
4350 int error = NFSERR_RETVOID;
4351 mbuf_t mb, mreq;
4352
4353 nfsm_reply(0);
4354 nfsmout:
4355 return (0);
4356 }
4357
4358 /*
4359 * No operation, used for obsolete procedures
4360 */
4361 /* ARGSUSED */
4362 int
4363 nfsrv_noop(
4364 struct nfsrv_descript *nfsd,
4365 struct nfssvc_sock *slp,
4366 __unused proc_t procp,
4367 mbuf_t *mrq)
4368 {
4369 mbuf_t mrep = nfsd->nd_mrep;
4370 caddr_t bpos;
4371 int error;
4372 mbuf_t mb, mreq;
4373
4374 if (nfsd->nd_repstat)
4375 error = nfsd->nd_repstat;
4376 else
4377 error = EPROCUNAVAIL;
4378 nfsm_reply(0);
4379 nfsmout:
4380 return (0);
4381 }
4382
4383 /*
4384 * Perform access checking for vnodes obtained from file handles that would
4385 * refer to files already opened by a Unix client. You cannot just use
4386 * vnode_authorize() for two reasons.
4387 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4388 * 2 - The owner is to be given access irrespective of mode bits so that
4389 * processes that chmod after opening a file don't break. I don't like
4390 * this because it opens a security hole, but since the nfs server opens
4391 * a security hole the size of a barn door anyhow, what the heck.
4392 *
4393 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4394 * will return EPERM instead of EACCESS. EPERM is always an error.
4395 */
4396
4397 static int
4398 nfsrv_authorize(
4399 vnode_t vp,
4400 vnode_t dvp,
4401 kauth_action_t action,
4402 vfs_context_t context,
4403 struct nfs_export_options *nxo,
4404 int override)
4405 {
4406 struct vnode_attr vattr;
4407 int error;
4408
4409 if (action & KAUTH_VNODE_WRITE_RIGHTS) {
4410 /*
4411 * Disallow write attempts on read-only exports;
4412 * unless the file is a socket or a block or character
4413 * device resident on the file system.
4414 */
4415 if (nxo->nxo_flags & NX_READONLY) {
4416 switch (vnode_vtype(vp)) {
4417 case VREG: case VDIR: case VLNK: case VCPLX:
4418 return (EROFS);
4419 default:
4420 break;
4421 }
4422 }
4423 }
4424 error = vnode_authorize(vp, dvp, action, context);
4425 /*
4426 * Allow certain operations for the owner (reads and writes
4427 * on files that are already open). Picking up from FreeBSD.
4428 */
4429 if (override && (error == EACCES)) {
4430 VATTR_INIT(&vattr);
4431 VATTR_WANTED(&vattr, va_uid);
4432 if ((vnode_getattr(vp, &vattr, context) == 0) &&
4433 (kauth_cred_getuid(vfs_context_ucred(context)) == vattr.va_uid))
4434 error = 0;
4435 }
4436 return error;
4437 }
4438 #endif /* NFS_NOSERVER */
4439