]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
8e808500ddf7b48eb460b67a885513973e0ed156
[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_unref(&nfsd->nd_cr);
2361 /*
2362 * consume reference taken above
2363 */
2364 nfsd->nd_cr = saved_cred;
2365 saved_cred = NULL;
2366 }
2367
2368 tond.ni_cnd.cn_nameiop = RENAME;
2369 tond.ni_cnd.cn_flags = WANTPARENT;
2370
2371 tond.ni_cnd.cn_pnbuf = topath;
2372 topath = NULL;
2373 tond.ni_cnd.cn_pnlen = MAXPATHLEN;
2374 tond.ni_cnd.cn_flags |= HASBUF;
2375
2376 if (fvtype == VDIR)
2377 tond.ni_cnd.cn_flags |= WILLBEDIR;
2378
2379 error = nfs_namei(nfsd, &context, &tond, &tnfh, nam, FALSE, &tdirp, &tnx, &tnxo);
2380 if (error) {
2381 /*
2382 * Translate error code for rename("dir1", "dir2/.").
2383 */
2384 if (error == EISDIR && fvtype == VDIR) {
2385 if (v3)
2386 error = EINVAL;
2387 else
2388 error = ENOTEMPTY;
2389 }
2390 goto out;
2391 }
2392 tdvp = tond.ni_dvp;
2393 tvp = tond.ni_vp;
2394
2395 if (tdirp) {
2396 if (v3) {
2397 nfsm_srv_pre_vattr_init(&tdirfor, v3);
2398 tdirfor_ret = vnode_getattr(tdirp, &tdirfor, &context);
2399 } else {
2400 vnode_put(tdirp);
2401 tdirp = NULL;
2402 }
2403 }
2404
2405 if (tvp != NULL) {
2406 tvtype = vnode_vtype(tvp);
2407
2408 if (fvtype == VDIR && tvtype != VDIR) {
2409 if (v3)
2410 error = EEXIST;
2411 else
2412 error = EISDIR;
2413 goto out;
2414 } else if (fvtype != VDIR && tvtype == VDIR) {
2415 if (v3)
2416 error = EEXIST;
2417 else
2418 error = ENOTDIR;
2419 goto out;
2420 }
2421 if (tvtype == VDIR && vnode_mountedhere(tvp)) {
2422 if (v3)
2423 error = EXDEV;
2424 else
2425 error = ENOTEMPTY;
2426 goto out;
2427 }
2428 }
2429 if (fvp == tdvp) {
2430 if (v3)
2431 error = EINVAL;
2432 else
2433 error = ENOTEMPTY;
2434 goto out;
2435 }
2436
2437 /*
2438 * Authorization.
2439 *
2440 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2441 * the node is moving between directories and we need rights to remove from the
2442 * old and add to the new.
2443 *
2444 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2445 *
2446 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2447 * implement the deferred-inherit bit.
2448 */
2449 {
2450 int moving = 0;
2451
2452 error = 0;
2453 if ((tvp != NULL) && vnode_isdir(tvp)) {
2454 if (tvp != fdvp)
2455 moving = 1;
2456 } else if (tdvp != fdvp) {
2457 moving = 1;
2458 }
2459 if (moving) {
2460 /* moving out of fdvp, must have delete rights */
2461 if ((error = nfsrv_authorize(fvp, fdvp, KAUTH_VNODE_DELETE, &context, fnxo, 0)) != 0)
2462 goto auth_exit;
2463 /* moving into tdvp or tvp, must have rights to add */
2464 if ((error = nfsrv_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
2465 NULL,
2466 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2467 &context, tnxo, 0)) != 0)
2468 goto auth_exit;
2469 } else {
2470 /* node staying in same directory, must be allowed to add new name */
2471 if ((error = nfsrv_authorize(fdvp, NULL,
2472 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2473 &context, fnxo, 0)) != 0)
2474 goto auth_exit;
2475 }
2476 /* overwriting tvp */
2477 if ((tvp != NULL) && !vnode_isdir(tvp) &&
2478 ((error = nfsrv_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, &context, tnxo, 0)) != 0))
2479 goto auth_exit;
2480
2481 /* XXX more checks? */
2482
2483 auth_exit:
2484 /* authorization denied */
2485 if (error != 0)
2486 goto out;
2487 }
2488
2489 if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
2490 (tvp && (vnode_mount(fvp) != vnode_mount(tvp)))) {
2491 if (v3)
2492 error = EXDEV;
2493 else
2494 error = ENOTEMPTY;
2495 goto out;
2496 }
2497 /*
2498 * The following edge case is caught here:
2499 * (to cannot be a descendent of from)
2500 *
2501 * o fdvp
2502 * /
2503 * /
2504 * o fvp
2505 * \
2506 * \
2507 * o tdvp
2508 * /
2509 * /
2510 * o tvp
2511 */
2512 if (tdvp->v_parent == fvp) {
2513 if (v3)
2514 error = EXDEV;
2515 else
2516 error = ENOTEMPTY;
2517 goto out;
2518 }
2519 if (fvtype == VDIR && vnode_mountedhere(fvp)) {
2520 if (v3)
2521 error = EXDEV;
2522 else
2523 error = ENOTEMPTY;
2524 goto out;
2525 }
2526 /*
2527 * If source is the same as the destination (that is the
2528 * same vnode) then there is nothing to do...
2529 * EXCEPT if the underlying file system supports case
2530 * insensitivity and is case preserving. In this case
2531 * the file system needs to handle the special case of
2532 * getting the same vnode as target (fvp) and source (tvp).
2533 *
2534 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2535 * and _PC_CASE_PRESERVING can have this exception, and they need to
2536 * handle the special case of getting the same vnode as target and
2537 * source. NOTE: Then the target is unlocked going into vnop_rename,
2538 * so not to cause locking problems. There is a single reference on tvp.
2539 *
2540 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2541 * that correct behaviour then is just to remove the source (link)
2542 */
2543 if ((fvp == tvp) && (fdvp == tdvp)) {
2544 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2545 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2546 fromnd.ni_cnd.cn_namelen)) {
2547 goto out;
2548 }
2549 }
2550
2551 if (holding_mntlock && vnode_mount(fvp) != locked_mp) {
2552 /*
2553 * we're holding a reference and lock
2554 * on locked_mp, but it no longer matches
2555 * what we want to do... so drop our hold
2556 */
2557 mount_unlock_renames(locked_mp);
2558 mount_drop(locked_mp, 0);
2559 holding_mntlock = 0;
2560 }
2561 if (tdvp != fdvp && fvtype == VDIR) {
2562 /*
2563 * serialize renames that re-shape
2564 * the tree... if holding_mntlock is
2565 * set, then we're ready to go...
2566 * otherwise we
2567 * first need to drop the iocounts
2568 * we picked up, second take the
2569 * lock to serialize the access,
2570 * then finally start the lookup
2571 * process over with the lock held
2572 */
2573 if (!holding_mntlock) {
2574 /*
2575 * need to grab a reference on
2576 * the mount point before we
2577 * drop all the iocounts... once
2578 * the iocounts are gone, the mount
2579 * could follow
2580 */
2581 locked_mp = vnode_mount(fvp);
2582 mount_ref(locked_mp, 0);
2583
2584 /* make a copy of to path to pass to nfs_namei() again */
2585 MALLOC_ZONE(topath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2586 if (topath)
2587 bcopy(tond.ni_cnd.cn_pnbuf, topath, tolen + 1);
2588
2589 /*
2590 * nameidone has to happen before we vnode_put(tdvp)
2591 * since it may need to release the fs_nodelock on the tdvp
2592 */
2593 nameidone(&tond);
2594
2595 if (tvp)
2596 vnode_put(tvp);
2597 vnode_put(tdvp);
2598
2599 /* make a copy of from path to pass to nfs_namei() again */
2600 MALLOC_ZONE(frompath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2601 if (frompath)
2602 bcopy(fromnd.ni_cnd.cn_pnbuf, frompath, fromlen + 1);
2603
2604 /*
2605 * nameidone has to happen before we vnode_put(fdvp)
2606 * since it may need to release the fs_nodelock on the fdvp
2607 */
2608 nameidone(&fromnd);
2609
2610 vnode_put(fvp);
2611 vnode_put(fdvp);
2612
2613 if (fdirp) {
2614 vnode_put(fdirp);
2615 fdirp = NULL;
2616 }
2617 if (tdirp) {
2618 vnode_put(tdirp);
2619 tdirp = NULL;
2620 }
2621 mount_lock_renames(locked_mp);
2622 holding_mntlock = 1;
2623
2624 fvp = tvp = NULL;
2625 fdvp = tdvp = NULL;
2626
2627 fdirfor_ret = tdirfor_ret = 1;
2628
2629 if (!topath || !frompath) {
2630 /* we couldn't allocate a path, so bail */
2631 error = ENOMEM;
2632 goto out;
2633 }
2634
2635 goto retry;
2636 }
2637 } else {
2638 /*
2639 * when we dropped the iocounts to take
2640 * the lock, we allowed the identity of
2641 * the various vnodes to change... if they did,
2642 * we may no longer be dealing with a rename
2643 * that reshapes the tree... once we're holding
2644 * the iocounts, the vnodes can't change type
2645 * so we're free to drop the lock at this point
2646 * and continue on
2647 */
2648 if (holding_mntlock) {
2649 mount_unlock_renames(locked_mp);
2650 mount_drop(locked_mp, 0);
2651 holding_mntlock = 0;
2652 }
2653 }
2654
2655 // save these off so we can later verify that fvp is the same
2656 char *oname;
2657 vnode_t oparent;
2658 oname = fvp->v_name;
2659 oparent = fvp->v_parent;
2660
2661 error = VNOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2662 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd, &context);
2663 /*
2664 * fix up name & parent pointers. note that we first
2665 * check that fvp has the same name/parent pointers it
2666 * had before the rename call... this is a 'weak' check
2667 * at best...
2668 */
2669 if (oname == fvp->v_name && oparent == fvp->v_parent) {
2670 int update_flags;
2671 update_flags = VNODE_UPDATE_NAME;
2672 if (fdvp != tdvp)
2673 update_flags |= VNODE_UPDATE_PARENT;
2674 vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
2675 }
2676 out:
2677 if (holding_mntlock) {
2678 mount_unlock_renames(locked_mp);
2679 mount_drop(locked_mp, 0);
2680 holding_mntlock = 0;
2681 }
2682 if (tdvp) {
2683 /*
2684 * nameidone has to happen before we vnode_put(tdvp)
2685 * since it may need to release the fs_nodelock on the tdvp
2686 */
2687 nameidone(&tond);
2688 if (tvp)
2689 vnode_put(tvp);
2690 vnode_put(tdvp);
2691
2692 tdvp = NULL;
2693 }
2694 if (fdvp) {
2695 /*
2696 * nameidone has to happen before we vnode_put(fdvp)
2697 * since it may need to release the fs_nodelock on the fdvp
2698 */
2699 nameidone(&fromnd);
2700
2701 if (fvp)
2702 vnode_put(fvp);
2703 vnode_put(fdvp);
2704
2705 fdvp = NULL;
2706 }
2707 if (fdirp) {
2708 nfsm_srv_vattr_init(&fdiraft, v3);
2709 fdiraft_ret = vnode_getattr(fdirp, &fdiraft, &context);
2710 vnode_put(fdirp);
2711 fdirp = NULL;
2712 }
2713 if (tdirp) {
2714 nfsm_srv_vattr_init(&tdiraft, v3);
2715 tdiraft_ret = vnode_getattr(tdirp, &tdiraft, &context);
2716 vnode_put(tdirp);
2717 tdirp = NULL;
2718 }
2719 nfsm_reply(2 * NFSX_WCCDATA(v3));
2720 if (v3) {
2721 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2722 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2723 }
2724 if (frompath)
2725 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2726 if (topath)
2727 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2728 if (saved_cred)
2729 kauth_cred_unref(&saved_cred);
2730 return (0);
2731
2732 nfsmout:
2733 if (holding_mntlock) {
2734 mount_unlock_renames(locked_mp);
2735 mount_drop(locked_mp, 0);
2736 }
2737 if (tdvp) {
2738 /*
2739 * nameidone has to happen before we vnode_put(tdvp)
2740 * since it may need to release the fs_nodelock on the tdvp
2741 */
2742 nameidone(&tond);
2743
2744 if (tvp)
2745 vnode_put(tvp);
2746 vnode_put(tdvp);
2747 }
2748 if (fdvp) {
2749 /*
2750 * nameidone has to happen before we vnode_put(fdvp)
2751 * since it may need to release the fs_nodelock on the fdvp
2752 */
2753 nameidone(&fromnd);
2754
2755 if (fvp)
2756 vnode_put(fvp);
2757 vnode_put(fdvp);
2758 }
2759 if (fdirp)
2760 vnode_put(fdirp);
2761 if (tdirp)
2762 vnode_put(tdirp);
2763 if (frompath)
2764 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2765 if (topath)
2766 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2767 if (saved_cred)
2768 kauth_cred_unref(&saved_cred);
2769 return (error);
2770 }
2771
2772 /*
2773 * nfs link service
2774 */
2775 int
2776 nfsrv_link(nfsd, slp, procp, mrq)
2777 struct nfsrv_descript *nfsd;
2778 struct nfssvc_sock *slp;
2779 proc_t procp;
2780 mbuf_t *mrq;
2781 {
2782 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2783 mbuf_t nam = nfsd->nd_nam;
2784 caddr_t dpos = nfsd->nd_dpos;
2785 struct nameidata nd;
2786 u_long *tl;
2787 long t1;
2788 caddr_t bpos;
2789 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2790 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2791 char *cp2;
2792 mbuf_t mb, mreq;
2793 vnode_t vp, xp, dvp, dirp = NULL;
2794 struct vnode_attr dirfor, diraft, at;
2795 struct nfs_filehandle nfh, dnfh;
2796 struct nfs_export *nx;
2797 struct nfs_export_options *nxo;
2798 struct vfs_context context;
2799
2800 vp = xp = dvp = NULL;
2801 nfsm_srvmtofh(&nfh);
2802 nfsm_srvmtofh(&dnfh);
2803 nfsm_srvnamesiz(len, v3);
2804 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
2805 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2806 nfsm_srvpostop_attr(getret, &at);
2807 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2808 return (0);
2809 }
2810 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
2811 vnode_put(vp);
2812 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2813 nfsm_srvpostop_attr(getret, &at);
2814 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2815 return (0);
2816 }
2817
2818 /* we're not allowed to link to directories... */
2819 if (vnode_vtype(vp) == VDIR) {
2820 error = EPERM; /* POSIX */
2821 goto out1;
2822 }
2823
2824 context.vc_proc = procp;
2825 context.vc_ucred = nfsd->nd_cr;
2826
2827 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2828 if ((error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LINKTARGET, &context, nxo, 0)) != 0)
2829 goto out1;
2830
2831 nd.ni_cnd.cn_nameiop = CREATE;
2832 nd.ni_cnd.cn_flags = LOCKPARENT;
2833 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2834 if (!error)
2835 error = nfs_namei(nfsd, &context, &nd, &dnfh, nam, FALSE, &dirp, &nx, &nxo);
2836 if (dirp) {
2837 if (v3) {
2838 nfsm_srv_pre_vattr_init(&dirfor, v3);
2839 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2840 } else {
2841 vnode_put(dirp);
2842 dirp = NULL;
2843 }
2844 }
2845 if (error)
2846 goto out1;
2847 dvp = nd.ni_dvp;
2848 xp = nd.ni_vp;
2849
2850 if (xp != NULL)
2851 error = EEXIST;
2852 else if (vnode_mount(vp) != vnode_mount(dvp))
2853 error = EXDEV;
2854 else
2855 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2856
2857 if (!error)
2858 error = VNOP_LINK(vp, dvp, &nd.ni_cnd, &context);
2859
2860 /*
2861 * nameidone has to happen before we vnode_put(dvp)
2862 * since it may need to release the fs_nodelock on the dvp
2863 */
2864 nameidone(&nd);
2865
2866 if (xp)
2867 vnode_put(xp);
2868 vnode_put(dvp);
2869 out1:
2870 if (v3) {
2871 nfsm_srv_vattr_init(&at, v3);
2872 getret = vnode_getattr(vp, &at, &context);
2873 }
2874 if (dirp) {
2875 nfsm_srv_vattr_init(&diraft, v3);
2876 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2877 vnode_put(dirp);
2878 }
2879 vnode_put(vp);
2880
2881 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2882 if (v3) {
2883 nfsm_srvpostop_attr(getret, &at);
2884 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2885 return (0);
2886 }
2887 nfsmout:
2888 return (error);
2889 }
2890
2891 /*
2892 * nfs symbolic link service
2893 */
2894 int
2895 nfsrv_symlink(nfsd, slp, procp, mrq)
2896 struct nfsrv_descript *nfsd;
2897 struct nfssvc_sock *slp;
2898 proc_t procp;
2899 mbuf_t *mrq;
2900 {
2901 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2902 mbuf_t nam = nfsd->nd_nam;
2903 caddr_t dpos = nfsd->nd_dpos;
2904 struct vnode_attr dirfor, diraft, postat;
2905 struct nameidata nd;
2906 struct vnode_attr va;
2907 struct vnode_attr *vap = &va;
2908 u_long *tl;
2909 long t1;
2910 struct nfsv2_sattr *sp;
2911 char *bpos, *linkdata = NULL, *cp2;
2912 int error = 0, len, linkdatalen;
2913 int dirfor_ret = 1, diraft_ret = 1;
2914 int v3 = (nfsd->nd_flag & ND_NFSV3);
2915 mbuf_t mb, mreq, mb2;
2916 vnode_t vp, dvp, dirp = NULL;
2917 struct nfs_filehandle nfh;
2918 struct nfs_export *nx;
2919 struct nfs_export_options *nxo;
2920 uio_t auio;
2921 char uio_buf[ UIO_SIZEOF(1) ];
2922 struct vfs_context context;
2923 uid_t saved_uid;
2924
2925 context.vc_proc = procp;
2926 context.vc_ucred = nfsd->nd_cr;
2927
2928 /*
2929 * Save the original credential UID in case they are
2930 * mapped and we need to map the IDs in the attributes.
2931 */
2932 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
2933
2934 nd.ni_cnd.cn_nameiop = 0;
2935 vp = dvp = NULL;
2936 nfsm_srvmtofh(&nfh);
2937 nfsm_srvnamesiz(len, v3);
2938
2939 nd.ni_cnd.cn_nameiop = CREATE;
2940 nd.ni_cnd.cn_flags = LOCKPARENT;
2941 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2942 if (!error)
2943 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2944 if (dirp) {
2945 if (v3) {
2946 nfsm_srv_pre_vattr_init(&dirfor, v3);
2947 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2948 } else {
2949 vnode_put(dirp);
2950 dirp = NULL;
2951 }
2952 }
2953 if (error) {
2954 nd.ni_cnd.cn_nameiop = 0;
2955 goto out1;
2956 }
2957 dvp = nd.ni_dvp;
2958 vp = nd.ni_vp;
2959
2960 VATTR_INIT(vap);
2961 if (v3)
2962 nfsm_srvsattr(vap);
2963 nfsm_strsiz(linkdatalen, NFS_MAXPATHLEN, v3);
2964 MALLOC(linkdata, caddr_t, linkdatalen + 1, M_TEMP, M_WAITOK);
2965 if (!linkdata) {
2966 nameidone(&nd);
2967 nd.ni_cnd.cn_nameiop = 0;
2968 vnode_put(nd.ni_dvp);
2969 vnode_put(nd.ni_vp);
2970 error = ENOMEM;
2971 goto out;
2972 }
2973 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
2974 &uio_buf[0], sizeof(uio_buf));
2975 if (!auio) {
2976 nameidone(&nd);
2977 nd.ni_cnd.cn_nameiop = 0;
2978 vnode_put(nd.ni_dvp);
2979 vnode_put(nd.ni_vp);
2980 error = ENOMEM;
2981 goto out;
2982 }
2983 uio_addiov(auio, CAST_USER_ADDR_T(linkdata), linkdatalen);
2984 nfsm_mtouio(auio, linkdatalen);
2985 if (!v3) {
2986 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2987 VATTR_SET(vap, va_mode, fxdr_unsigned(u_short, sp->sa_mode));
2988 }
2989 *(linkdata + linkdatalen) = '\0';
2990 if (vp) {
2991 error = EEXIST;
2992 goto out;
2993 }
2994
2995 /*
2996 * If the credentials were mapped, we should
2997 * map the same values in the attributes.
2998 */
2999 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
3000 int ismember;
3001 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
3002 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3003 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3004 }
3005 VATTR_SET(vap, va_type, VLNK);
3006 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3007 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3008
3009 /* authorize before creating */
3010 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
3011
3012 /* validate given attributes */
3013 if (!error) {
3014 error = vnode_authattr_new(dvp, vap, 0, &context);
3015 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3016 /*
3017 * Most NFS servers just ignore the UID/GID attributes, so we
3018 * try ignoring them if that'll help the request succeed.
3019 */
3020 VATTR_CLEAR_ACTIVE(vap, va_uid);
3021 VATTR_CLEAR_ACTIVE(vap, va_gid);
3022 error = vnode_authattr_new(dvp, vap, 0, &context);
3023 }
3024 }
3025 if (!error)
3026 error = VNOP_SYMLINK(dvp, &vp, &nd.ni_cnd, vap, linkdata, &context);
3027
3028 if (!error && v3) {
3029 if (vp == NULL) {
3030 nd.ni_cnd.cn_nameiop = LOOKUP;
3031 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
3032 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
3033 nd.ni_cnd.cn_context = &context;
3034 nd.ni_startdir = dvp;
3035 nd.ni_usedvp = dvp;
3036 error = lookup(&nd);
3037 if (!error)
3038 vp = nd.ni_vp;
3039 }
3040 if (!error) {
3041 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3042 if (!error) {
3043 nfsm_srv_vattr_init(&postat, v3);
3044 error = vnode_getattr(vp, &postat, &context);
3045 }
3046 }
3047 }
3048 out:
3049 /*
3050 * nameidone has to happen before we vnode_put(dvp)
3051 * since it may need to release the fs_nodelock on the dvp
3052 */
3053 nameidone(&nd);
3054 nd.ni_cnd.cn_nameiop = 0;
3055
3056 if (vp)
3057 vnode_put(vp);
3058 vnode_put(dvp);
3059 out1:
3060 if (linkdata)
3061 FREE(linkdata, M_TEMP);
3062 if (dirp) {
3063 nfsm_srv_vattr_init(&diraft, v3);
3064 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3065 vnode_put(dirp);
3066 }
3067 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3068 if (v3) {
3069 if (!error) {
3070 nfsm_srvpostop_fh(&nfh);
3071 nfsm_srvpostop_attr(0, &postat);
3072 }
3073 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3074 }
3075 return (0);
3076 nfsmout:
3077 if (nd.ni_cnd.cn_nameiop) {
3078 /*
3079 * nameidone has to happen before we vnode_put(dvp)
3080 * since it may need to release the fs_nodelock on the dvp
3081 */
3082 nameidone(&nd);
3083
3084 if (vp)
3085 vnode_put(vp);
3086 vnode_put(dvp);
3087 }
3088 if (dirp)
3089 vnode_put(dirp);
3090 if (linkdata)
3091 FREE(linkdata, M_TEMP);
3092 return (error);
3093 }
3094
3095 /*
3096 * nfs mkdir service
3097 */
3098 int
3099 nfsrv_mkdir(nfsd, slp, procp, mrq)
3100 struct nfsrv_descript *nfsd;
3101 struct nfssvc_sock *slp;
3102 proc_t procp;
3103 mbuf_t *mrq;
3104 {
3105 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3106 mbuf_t nam = nfsd->nd_nam;
3107 caddr_t dpos = nfsd->nd_dpos;
3108 struct vnode_attr dirfor, diraft, postat;
3109 struct vnode_attr va;
3110 struct vnode_attr *vap = &va;
3111 struct nfs_fattr *fp;
3112 struct nameidata nd;
3113 caddr_t cp;
3114 u_long *tl;
3115 long t1;
3116 caddr_t bpos;
3117 int error = 0, len;
3118 int dirfor_ret = 1, diraft_ret = 1;
3119 int v3 = (nfsd->nd_flag & ND_NFSV3);
3120 char *cp2;
3121 mbuf_t mb, mb2, mreq;
3122 vnode_t vp, dvp, dirp = NULL;
3123 struct nfs_filehandle nfh;
3124 struct nfs_export *nx;
3125 struct nfs_export_options *nxo;
3126 struct vfs_context context;
3127 uid_t saved_uid;
3128 kauth_acl_t xacl = NULL;
3129
3130 context.vc_proc = procp;
3131 context.vc_ucred = nfsd->nd_cr;
3132
3133 /*
3134 * Save the original credential UID in case they are
3135 * mapped and we need to map the IDs in the attributes.
3136 */
3137 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
3138
3139 nd.ni_cnd.cn_nameiop = 0;
3140 vp = dvp = NULL;
3141 nfsm_srvmtofh(&nfh);
3142 nfsm_srvnamesiz(len, v3);
3143
3144 nd.ni_cnd.cn_nameiop = CREATE;
3145 nd.ni_cnd.cn_flags = LOCKPARENT;
3146 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3147 if (!error)
3148 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3149 if (dirp) {
3150 if (v3) {
3151 nfsm_srv_pre_vattr_init(&dirfor, v3);
3152 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3153 } else {
3154 vnode_put(dirp);
3155 dirp = NULL;
3156 }
3157 }
3158 if (error) {
3159 nd.ni_cnd.cn_nameiop = 0;
3160 nfsm_reply(NFSX_WCCDATA(v3));
3161 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3162 if (dirp)
3163 vnode_put(dirp);
3164 return (0);
3165 }
3166 dvp = nd.ni_dvp;
3167 vp = nd.ni_vp;
3168
3169 VATTR_INIT(vap);
3170 if (v3) {
3171 nfsm_srvsattr(vap);
3172 } else {
3173 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
3174 VATTR_SET(vap, va_mode, nfstov_mode(*tl++));
3175 }
3176 VATTR_SET(vap, va_type, VDIR);
3177
3178 if (vp != NULL) {
3179 /*
3180 * nameidone has to happen before we vnode_put(dvp)
3181 * since it may need to release the fs_nodelock on the dvp
3182 */
3183 nameidone(&nd);
3184
3185 vnode_put(dvp);
3186 vnode_put(vp);
3187 error = EEXIST;
3188 goto out;
3189 }
3190
3191 /*
3192 * If the credentials were mapped, we should
3193 * map the same values in the attributes.
3194 */
3195 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
3196 int ismember;
3197 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
3198 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3199 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3200 }
3201
3202 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, &context, nxo, 0);
3203
3204 /* construct ACL and handle inheritance */
3205 if (!error) {
3206 error = kauth_acl_inherit(dvp,
3207 NULL,
3208 &xacl, /* isdir */
3209 1,
3210 &context);
3211
3212 if (!error && xacl != NULL)
3213 VATTR_SET(vap, va_acl, xacl);
3214 }
3215 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3216 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3217
3218 /* validate new-file security information */
3219 if (!error) {
3220 error = vnode_authattr_new(dvp, vap, 0, &context);
3221 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3222 /*
3223 * Most NFS servers just ignore the UID/GID attributes, so we
3224 * try ignoring them if that'll help the request succeed.
3225 */
3226 VATTR_CLEAR_ACTIVE(vap, va_uid);
3227 VATTR_CLEAR_ACTIVE(vap, va_gid);
3228 error = vnode_authattr_new(dvp, vap, 0, &context);
3229 }
3230 }
3231
3232 if (!error)
3233 error = VNOP_MKDIR(dvp, &vp, &nd.ni_cnd, vap, &context);
3234
3235 if (!error && !VATTR_ALL_SUPPORTED(vap))
3236 /*
3237 * If some of the requested attributes weren't handled by the VNOP,
3238 * use our fallback code.
3239 */
3240 error = vnode_setattr_fallback(vp, vap, &context);
3241
3242 if (xacl != NULL)
3243 kauth_acl_free(xacl);
3244
3245 if (!error) {
3246 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3247 if (!error) {
3248 nfsm_srv_vattr_init(&postat, v3);
3249 error = vnode_getattr(vp, &postat, &context);
3250 }
3251 vnode_put(vp);
3252 vp = NULL;
3253 }
3254 /*
3255 * nameidone has to happen before we vnode_put(dvp)
3256 * since it may need to release the fs_nodelock on the dvp
3257 */
3258 nameidone(&nd);
3259
3260 vnode_put(dvp);
3261 out:
3262 nd.ni_cnd.cn_nameiop = 0;
3263
3264 if (dirp) {
3265 nfsm_srv_vattr_init(&diraft, v3);
3266 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3267 vnode_put(dirp);
3268 }
3269 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3270 if (v3) {
3271 if (!error) {
3272 nfsm_srvpostop_fh(&nfh);
3273 nfsm_srvpostop_attr(0, &postat);
3274 }
3275 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3276 } else {
3277 nfsm_srvfhtom(&nfh, v3);
3278 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
3279 nfsm_srvfillattr(&postat, fp);
3280 }
3281 return (0);
3282 nfsmout:
3283 if (nd.ni_cnd.cn_nameiop) {
3284 /*
3285 * nameidone has to happen before we vnode_put(dvp)
3286 * since it may need to release the fs_nodelock on the dvp
3287 */
3288 nameidone(&nd);
3289 vnode_put(dvp);
3290 if (vp)
3291 vnode_put(vp);
3292 }
3293 if (dirp)
3294 vnode_put(dirp);
3295 return (error);
3296 }
3297
3298 /*
3299 * nfs rmdir service
3300 */
3301 int
3302 nfsrv_rmdir(nfsd, slp, procp, mrq)
3303 struct nfsrv_descript *nfsd;
3304 struct nfssvc_sock *slp;
3305 proc_t procp;
3306 mbuf_t *mrq;
3307 {
3308 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3309 mbuf_t nam = nfsd->nd_nam;
3310 caddr_t dpos = nfsd->nd_dpos;
3311 u_long *tl;
3312 long t1;
3313 caddr_t bpos;
3314 int error = 0, len;
3315 int dirfor_ret = 1, diraft_ret = 1;
3316 int v3 = (nfsd->nd_flag & ND_NFSV3);
3317 char *cp2;
3318 mbuf_t mb, mreq;
3319 vnode_t vp, dvp, dirp = NULL;
3320 struct vnode_attr dirfor, diraft;
3321 struct nfs_filehandle nfh;
3322 struct nfs_export *nx;
3323 struct nfs_export_options *nxo;
3324 struct nameidata nd;
3325 struct vfs_context context;
3326
3327 context.vc_proc = procp;
3328 context.vc_ucred = nfsd->nd_cr;
3329
3330 vp = dvp = NULL;
3331 nfsm_srvmtofh(&nfh);
3332 nfsm_srvnamesiz(len, v3);
3333
3334 nd.ni_cnd.cn_nameiop = DELETE;
3335 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
3336 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3337 if (!error)
3338 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3339 if (dirp) {
3340 if (v3) {
3341 nfsm_srv_pre_vattr_init(&dirfor, v3);
3342 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3343 } else {
3344 vnode_put(dirp);
3345 dirp = NULL;
3346 }
3347 }
3348 if (error) {
3349 nfsm_reply(NFSX_WCCDATA(v3));
3350 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3351 if (dirp)
3352 vnode_put(dirp);
3353 return (0);
3354 }
3355 dvp = nd.ni_dvp;
3356 vp = nd.ni_vp;
3357
3358 if (vnode_vtype(vp) != VDIR) {
3359 error = ENOTDIR;
3360 goto out;
3361 }
3362 /*
3363 * No rmdir "." please.
3364 */
3365 if (dvp == vp) {
3366 error = EINVAL;
3367 goto out;
3368 }
3369 /*
3370 * The root of a mounted filesystem cannot be deleted.
3371 */
3372 if (vnode_isvroot(vp))
3373 error = EBUSY;
3374 if (!error)
3375 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
3376 if (!error)
3377 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, &context);
3378 out:
3379 /*
3380 * nameidone has to happen before we vnode_put(dvp)
3381 * since it may need to release the fs_nodelock on the dvp
3382 */
3383 nameidone(&nd);
3384
3385 vnode_put(dvp);
3386 vnode_put(vp);
3387
3388 if (dirp) {
3389 nfsm_srv_vattr_init(&diraft, v3);
3390 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3391 vnode_put(dirp);
3392 }
3393 nfsm_reply(NFSX_WCCDATA(v3));
3394 if (v3) {
3395 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3396 return (0);
3397 }
3398 nfsmout:
3399 return (error);
3400 }
3401
3402 /*
3403 * nfs readdir service
3404 * - mallocs what it thinks is enough to read
3405 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3406 * - calls VNOP_READDIR()
3407 * - loops around building the reply
3408 * if the output generated exceeds count break out of loop
3409 * The nfsm_clget macro is used here so that the reply will be packed
3410 * tightly in mbuf clusters.
3411 * - it only knows that it has encountered eof when the VNOP_READDIR()
3412 * reads nothing
3413 * - as such one readdir rpc will return eof false although you are there
3414 * and then the next will return eof
3415 * - it trims out records with d_fileno == 0
3416 * this doesn't matter for Unix clients, but they might confuse clients
3417 * for other os'.
3418 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3419 * than requested, but this may not apply to all filesystems. For
3420 * example, client NFS does not { although it is never remote mounted
3421 * anyhow }
3422 * The alternate call nfsrv_readdirplus() does lookups as well.
3423 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3424 * are supposed to cover. For readdir, the count is the total number of
3425 * bytes included in everything from the directory's postopattr through
3426 * the EOF flag. For readdirplus, the maxcount is the same, and the
3427 * dircount includes all that except for the entry attributes and handles.
3428 */
3429
3430 int
3431 nfsrv_readdir(nfsd, slp, procp, mrq)
3432 struct nfsrv_descript *nfsd;
3433 struct nfssvc_sock *slp;
3434 proc_t procp;
3435 mbuf_t *mrq;
3436 {
3437 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3438 mbuf_t nam = nfsd->nd_nam;
3439 caddr_t dpos = nfsd->nd_dpos;
3440 char *bp, *be;
3441 mbuf_t mp;
3442 struct direntry *dp;
3443 caddr_t cp;
3444 u_long *tl;
3445 long t1;
3446 caddr_t bpos;
3447 mbuf_t mb, mb2, mreq, mp2;
3448 char *cpos, *cend, *cp2, *rbuf;
3449 vnode_t vp;
3450 struct vnode_attr at;
3451 struct nfs_filehandle nfh;
3452 struct nfs_export *nx;
3453 struct nfs_export_options *nxo;
3454 uio_t auio;
3455 char uio_buf[ UIO_SIZEOF(1) ];
3456 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3457 int siz, count, fullsiz, eofflag, nentries = 0;
3458 int v3 = (nfsd->nd_flag & ND_NFSV3);
3459 u_quad_t off, toff, verf;
3460 nfsuint64 tquad;
3461 int vnopflag;
3462 struct vfs_context context;
3463
3464 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3465
3466 nfsm_srvmtofh(&nfh);
3467 if (v3) {
3468 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
3469 fxdr_hyper(tl, &toff);
3470 tl += 2;
3471 fxdr_hyper(tl, &verf);
3472 tl += 2;
3473 } else {
3474 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
3475 toff = fxdr_unsigned(u_quad_t, *tl++);
3476 }
3477 off = toff;
3478 count = fxdr_unsigned(int, *tl);
3479 siz = ((count + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3480 xfer = NFS_SRVMAXDATA(nfsd);
3481 if (siz > xfer)
3482 siz = xfer;
3483 fullsiz = siz;
3484 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
3485 nfsm_reply(NFSX_UNSIGNED);
3486 nfsm_srvpostop_attr(getret, &at);
3487 return (0);
3488 }
3489 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3490 vnode_put(vp);
3491 nfsm_reply(NFSX_UNSIGNED);
3492 nfsm_srvpostop_attr(getret, &at);
3493 return (0);
3494 }
3495 context.vc_proc = procp;
3496 context.vc_ucred = nfsd->nd_cr;
3497 if (!v3 || (nxo->nxo_flags & NX_32BITCLIENTS))
3498 vnopflag |= VNODE_READDIR_SEEKOFF32;
3499 if (v3) {
3500 nfsm_srv_vattr_init(&at, v3);
3501 error = getret = vnode_getattr(vp, &at, &context);
3502 if (!error && toff && verf && verf != at.va_filerev)
3503 error = NFSERR_BAD_COOKIE;
3504 }
3505 if (!error)
3506 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3507 if (error) {
3508 vnode_put(vp);
3509 nfsm_reply(NFSX_POSTOPATTR(v3));
3510 nfsm_srvpostop_attr(getret, &at);
3511 return (0);
3512 }
3513 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3514 if (!rbuf) {
3515 error = ENOMEM;
3516 vnode_put(vp);
3517 nfsm_reply(NFSX_POSTOPATTR(v3));
3518 nfsm_srvpostop_attr(getret, &at);
3519 return (0);
3520 }
3521 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3522 &uio_buf[0], sizeof(uio_buf));
3523 if (!auio) {
3524 error = ENOMEM;
3525 FREE(rbuf, M_TEMP);
3526 vnode_put(vp);
3527 nfsm_reply(NFSX_POSTOPATTR(v3));
3528 nfsm_srvpostop_attr(getret, &at);
3529 return (0);
3530 }
3531 again:
3532 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3533 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3534
3535 eofflag = 0;
3536 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3537 off = uio_offset(auio);
3538
3539 if (v3) {
3540 nfsm_srv_vattr_init(&at, v3);
3541 getret = vnode_getattr(vp, &at, &context);
3542 if (!error)
3543 error = getret;
3544 }
3545 if (error) {
3546 vnode_put(vp);
3547 FREE(rbuf, M_TEMP);
3548 nfsm_reply(NFSX_POSTOPATTR(v3));
3549 nfsm_srvpostop_attr(getret, &at);
3550 return (0);
3551 }
3552 if (uio_resid(auio) != 0) {
3553 // LP64todo - fix this
3554 siz -= uio_resid(auio);
3555
3556 /*
3557 * If nothing read, return eof
3558 * rpc reply
3559 */
3560 if (siz == 0) {
3561 vnode_put(vp);
3562 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
3563 2 * NFSX_UNSIGNED);
3564 if (v3) {
3565 nfsm_srvpostop_attr(getret, &at);
3566 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3567 txdr_hyper(&at.va_filerev, tl);
3568 tl += 2;
3569 } else
3570 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3571 *tl++ = nfs_false;
3572 *tl = nfs_true;
3573 FREE(rbuf, M_TEMP);
3574 return (0);
3575 }
3576 }
3577
3578 /*
3579 * Check for degenerate cases of nothing useful read.
3580 * If so go try again
3581 */
3582 cpos = rbuf;
3583 cend = rbuf + siz;
3584 dp = (struct direntry *)cpos;
3585 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3586 cpos += dp->d_reclen;
3587 dp = (struct direntry *)cpos;
3588 nentries--;
3589 }
3590 if (cpos >= cend || nentries == 0) {
3591 toff = off;
3592 siz = fullsiz;
3593 goto again;
3594 }
3595
3596 vnode_put(vp);
3597 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
3598 if (v3) {
3599 len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3600 nfsm_srvpostop_attr(getret, &at);
3601 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3602 txdr_hyper(&at.va_filerev, tl);
3603 } else
3604 len = 2 * NFSX_UNSIGNED;
3605 mp = mp2 = mb;
3606 bp = bpos;
3607 be = bp + mbuf_trailingspace(mp);
3608
3609 /* Loop through the records and build reply */
3610 while (cpos < cend && nentries > 0) {
3611 if (dp->d_fileno != 0) {
3612 nlen = dp->d_namlen;
3613 if (!v3 && (nlen > NFS_MAXNAMLEN))
3614 nlen = NFS_MAXNAMLEN;
3615 rem = nfsm_rndup(nlen)-nlen;
3616 len += (4 * NFSX_UNSIGNED + nlen + rem);
3617 if (v3)
3618 len += 2 * NFSX_UNSIGNED;
3619 if (len > count) {
3620 eofflag = 0;
3621 break;
3622 }
3623 /*
3624 * Build the directory record xdr from
3625 * the direntry entry.
3626 */
3627 nfsm_clget;
3628 *tl = nfs_true;
3629 bp += NFSX_UNSIGNED;
3630 nfsm_clget;
3631 if (v3) {
3632 txdr_hyper(&dp->d_fileno, &tquad);
3633 *tl = tquad.nfsuquad[0];
3634 bp += NFSX_UNSIGNED;
3635 nfsm_clget;
3636 *tl = tquad.nfsuquad[1];
3637 bp += NFSX_UNSIGNED;
3638 } else {
3639 *tl = txdr_unsigned(dp->d_fileno);
3640 bp += NFSX_UNSIGNED;
3641 }
3642 nfsm_clget;
3643 *tl = txdr_unsigned(nlen);
3644 bp += NFSX_UNSIGNED;
3645
3646 /* And loop around copying the name */
3647 xfer = nlen;
3648 cp = dp->d_name;
3649 while (xfer > 0) {
3650 nfsm_clget;
3651 if ((bp+xfer) > be)
3652 tsiz = be-bp;
3653 else
3654 tsiz = xfer;
3655 bcopy(cp, bp, tsiz);
3656 bp += tsiz;
3657 xfer -= tsiz;
3658 if (xfer > 0)
3659 cp += tsiz;
3660 }
3661 /* And null pad to a long boundary */
3662 for (i = 0; i < rem; i++)
3663 *bp++ = '\0';
3664
3665 /* Finish off the record with the cookie */
3666 nfsm_clget;
3667 if (v3) {
3668 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3669 dp->d_seekoff &= 0x00000000ffffffffULL;
3670 txdr_hyper(&dp->d_seekoff, &tquad);
3671 *tl = tquad.nfsuquad[0];
3672 bp += NFSX_UNSIGNED;
3673 nfsm_clget;
3674 *tl = tquad.nfsuquad[1];
3675 bp += NFSX_UNSIGNED;
3676 } else {
3677 *tl = txdr_unsigned(dp->d_seekoff);
3678 bp += NFSX_UNSIGNED;
3679 }
3680 }
3681 cpos += dp->d_reclen;
3682 dp = (struct direntry *)cpos;
3683 nentries--;
3684 }
3685 nfsm_clget;
3686 *tl = nfs_false;
3687 bp += NFSX_UNSIGNED;
3688 nfsm_clget;
3689 if (eofflag)
3690 *tl = nfs_true;
3691 else
3692 *tl = nfs_false;
3693 bp += NFSX_UNSIGNED;
3694 if (mp != mb) {
3695 if (bp < be)
3696 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
3697 } else
3698 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
3699 FREE(rbuf, M_TEMP);
3700 nfsmout:
3701 return (error);
3702 }
3703
3704 struct flrep {
3705 nfsuint64 fl_off;
3706 u_long fl_postopok;
3707 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
3708 u_long fl_fhok;
3709 u_long fl_fhsize;
3710 u_long fl_nfh[NFSX_V3FHMAX / sizeof (u_long)];
3711 };
3712
3713 int
3714 nfsrv_readdirplus(nfsd, slp, procp, mrq)
3715 struct nfsrv_descript *nfsd;
3716 struct nfssvc_sock *slp;
3717 proc_t procp;
3718 mbuf_t *mrq;
3719 {
3720 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3721 mbuf_t nam = nfsd->nd_nam;
3722 caddr_t dpos = nfsd->nd_dpos;
3723 char *bp, *be;
3724 mbuf_t mp;
3725 struct direntry *dp;
3726 caddr_t cp;
3727 u_long *tl;
3728 long t1;
3729 caddr_t bpos;
3730 mbuf_t mb, mb2, mreq, mp2;
3731 char *cpos, *cend, *cp2, *rbuf;
3732 vnode_t vp, nvp;
3733 struct flrep fl;
3734 struct nfs_filehandle dnfh, *nfhp = (struct nfs_filehandle *)&fl.fl_fhsize;
3735 u_long fhsize;
3736 struct nfs_export *nx;
3737 struct nfs_export_options *nxo;
3738 uio_t auio;
3739 char uio_buf[ UIO_SIZEOF(1) ];
3740 struct vnode_attr va, at, *vap = &va;
3741 struct nfs_fattr *fp;
3742 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3743 int siz, count, fullsiz, eofflag, dirlen, nentries = 0, isdotdot;
3744 u_quad_t off, toff, verf;
3745 nfsuint64 tquad;
3746 int vnopflag;
3747 struct vfs_context context;
3748
3749 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3750 vp = NULL;
3751 nfsm_srvmtofh(&dnfh);
3752 nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
3753 fxdr_hyper(tl, &toff);
3754 tl += 2;
3755 fxdr_hyper(tl, &verf);
3756 tl += 2;
3757 siz = fxdr_unsigned(int, *tl++);
3758 count = fxdr_unsigned(int, *tl);
3759 off = toff;
3760 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3761 xfer = NFS_SRVMAXDATA(nfsd);
3762 if (siz > xfer)
3763 siz = xfer;
3764 fullsiz = siz;
3765 if ((error = nfsrv_fhtovp(&dnfh, nam, TRUE, &vp, &nx, &nxo))) {
3766 nfsm_reply(NFSX_UNSIGNED);
3767 nfsm_srvpostop_attr(getret, &at);
3768 return (0);
3769 }
3770 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3771 vnode_put(vp);
3772 nfsm_reply(NFSX_UNSIGNED);
3773 nfsm_srvpostop_attr(getret, &at);
3774 return (0);
3775 }
3776 context.vc_proc = procp;
3777 context.vc_ucred = nfsd->nd_cr;
3778 if (nxo->nxo_flags & NX_32BITCLIENTS)
3779 vnopflag |= VNODE_READDIR_SEEKOFF32;
3780 nfsm_srv_vattr_init(&at, 1);
3781 error = getret = vnode_getattr(vp, &at, &context);
3782 if (!error && toff && verf && verf != at.va_filerev)
3783 error = NFSERR_BAD_COOKIE;
3784 if (!error)
3785 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3786 if (error) {
3787 vnode_put(vp);
3788 vp = NULL;
3789 nfsm_reply(NFSX_V3POSTOPATTR);
3790 nfsm_srvpostop_attr(getret, &at);
3791 return (0);
3792 }
3793 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3794 if (!rbuf) {
3795 error = ENOMEM;
3796 vnode_put(vp);
3797 vp = NULL;
3798 nfsm_reply(NFSX_V3POSTOPATTR);
3799 nfsm_srvpostop_attr(getret, &at);
3800 return (0);
3801 }
3802 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3803 &uio_buf[0], sizeof(uio_buf));
3804 if (!auio) {
3805 error = ENOMEM;
3806 FREE(rbuf, M_TEMP);
3807 vnode_put(vp);
3808 vp = NULL;
3809 nfsm_reply(NFSX_V3POSTOPATTR);
3810 nfsm_srvpostop_attr(getret, &at);
3811 return (0);
3812 }
3813 again:
3814 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3815 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3816 eofflag = 0;
3817 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3818 off = uio_offset(auio);
3819 nfsm_srv_vattr_init(&at, 1);
3820 getret = vnode_getattr(vp, &at, &context);
3821
3822 if (!error)
3823 error = getret;
3824 if (error) {
3825 vnode_put(vp);
3826 vp = NULL;
3827 FREE(rbuf, M_TEMP);
3828 nfsm_reply(NFSX_V3POSTOPATTR);
3829 nfsm_srvpostop_attr(getret, &at);
3830 return (0);
3831 }
3832 if (uio_resid(auio) != 0) {
3833 // LP64todo - fix this
3834 siz -= uio_resid(auio);
3835
3836 /*
3837 * If nothing read, return eof
3838 * rpc reply
3839 */
3840 if (siz == 0) {
3841 vnode_put(vp);
3842 vp = NULL;
3843 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3844 2 * NFSX_UNSIGNED);
3845 nfsm_srvpostop_attr(getret, &at);
3846 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3847 txdr_hyper(&at.va_filerev, tl);
3848 tl += 2;
3849 *tl++ = nfs_false;
3850 *tl = nfs_true;
3851 FREE(rbuf, M_TEMP);
3852 return (0);
3853 }
3854 }
3855
3856 /*
3857 * Check for degenerate cases of nothing useful read.
3858 * If so go try again
3859 */
3860 cpos = rbuf;
3861 cend = rbuf + siz;
3862 dp = (struct direntry *)cpos;
3863 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3864 cpos += dp->d_reclen;
3865 dp = (struct direntry *)cpos;
3866 nentries--;
3867 }
3868 if (cpos >= cend || nentries == 0) {
3869 toff = off;
3870 siz = fullsiz;
3871 goto again;
3872 }
3873
3874 /*
3875 * Probe one of the directory entries to see if the filesystem
3876 * supports VGET.
3877 */
3878 if ((error = VFS_VGET(vnode_mount(vp), (ino64_t)dp->d_fileno, &nvp, &context))) {
3879 if (error == ENOTSUP) /* let others get passed back */
3880 error = NFSERR_NOTSUPP;
3881 vnode_put(vp);
3882 vp = NULL;
3883 FREE(rbuf, M_TEMP);
3884 nfsm_reply(NFSX_V3POSTOPATTR);
3885 nfsm_srvpostop_attr(getret, &at);
3886 return (0);
3887 }
3888 vnode_put(nvp);
3889
3890 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3891 nfsm_reply(count);
3892 nfsm_srvpostop_attr(getret, &at);
3893 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3894 txdr_hyper(&at.va_filerev, tl);
3895 mp = mp2 = mb;
3896 bp = bpos;
3897 be = bp + mbuf_trailingspace(mp);
3898
3899 /* Loop through the records and build reply */
3900 while (cpos < cend && nentries > 0) {
3901 if (dp->d_fileno != 0) {
3902 nlen = dp->d_namlen;
3903 rem = nfsm_rndup(nlen)-nlen;
3904
3905 /*
3906 * Got to get the vnode for lookup per entry.
3907 */
3908 if (VFS_VGET(vnode_mount(vp), (ino64_t)dp->d_fileno, &nvp, &context))
3909 goto invalid;
3910 isdotdot = ((dp->d_namlen == 2) &&
3911 (dp->d_name[0] == '.') && (dp->d_name[1] == '.'));
3912 if (nfsrv_vptofh(nx, 0, (isdotdot ? &dnfh : NULL), nvp, &context, nfhp)) {
3913 // XXX file handle is optional, so we should be able to
3914 // XXX return this entry without the file handle
3915 vnode_put(nvp);
3916 goto invalid;
3917 }
3918 nfsm_srv_vattr_init(vap, 1);
3919 if (vnode_getattr(nvp, vap, &context)) {
3920 // XXX attributes are optional, so we should be able to
3921 // XXX return this entry without the attributes
3922 vnode_put(nvp);
3923 goto invalid;
3924 }
3925 vnode_put(nvp);
3926
3927 /*
3928 * If either the dircount or maxcount will be
3929 * exceeded, get out now. Both of these lengths
3930 * are calculated conservatively, including all
3931 * XDR overheads.
3932 */
3933 len += (8 * NFSX_UNSIGNED + nlen + rem + nfhp->nfh_len +
3934 NFSX_V3POSTOPATTR);
3935 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3936 if (len > count || dirlen > fullsiz) {
3937 eofflag = 0;
3938 break;
3939 }
3940
3941 /*
3942 * Build the directory record xdr from
3943 * the direntry entry.
3944 */
3945 fp = (struct nfs_fattr *)&fl.fl_fattr;
3946 nfsm_srvfillattr(vap, fp);
3947 fhsize = nfhp->nfh_len;
3948 fl.fl_fhsize = txdr_unsigned(fhsize);
3949 fl.fl_fhok = nfs_true;
3950 fl.fl_postopok = nfs_true;
3951 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3952 dp->d_seekoff &= 0x00000000ffffffffULL;
3953 txdr_hyper(&dp->d_seekoff, &fl.fl_off);
3954
3955 nfsm_clget;
3956 *tl = nfs_true;
3957 bp += NFSX_UNSIGNED;
3958
3959 nfsm_clget;
3960 txdr_hyper(&dp->d_fileno, &tquad);
3961 *tl = tquad.nfsuquad[0];
3962 bp += NFSX_UNSIGNED;
3963 nfsm_clget;
3964 *tl = tquad.nfsuquad[1];
3965 bp += NFSX_UNSIGNED;
3966
3967 nfsm_clget;
3968 *tl = txdr_unsigned(nlen);
3969 bp += NFSX_UNSIGNED;
3970
3971 /* And loop around copying the name */
3972 xfer = nlen;
3973 cp = dp->d_name;
3974 while (xfer > 0) {
3975 nfsm_clget;
3976 if ((bp + xfer) > be)
3977 tsiz = be - bp;
3978 else
3979 tsiz = xfer;
3980 bcopy(cp, bp, tsiz);
3981 bp += tsiz;
3982 xfer -= tsiz;
3983 if (xfer > 0)
3984 cp += tsiz;
3985 }
3986 /* And null pad to a long boundary */
3987 for (i = 0; i < rem; i++)
3988 *bp++ = '\0';
3989
3990 /*
3991 * Now copy the flrep structure out.
3992 */
3993 xfer = sizeof(struct flrep) - sizeof(fl.fl_nfh) + fhsize;
3994 cp = (caddr_t)&fl;
3995 while (xfer > 0) {
3996 nfsm_clget;
3997 if ((bp + xfer) > be)
3998 tsiz = be - bp;
3999 else
4000 tsiz = xfer;
4001 bcopy(cp, bp, tsiz);
4002 bp += tsiz;
4003 xfer -= tsiz;
4004 if (xfer > 0)
4005 cp += tsiz;
4006 }
4007 }
4008 invalid:
4009 cpos += dp->d_reclen;
4010 dp = (struct direntry *)cpos;
4011 nentries--;
4012 }
4013 vnode_put(vp);
4014 vp = NULL;
4015 nfsm_clget;
4016 *tl = nfs_false;
4017 bp += NFSX_UNSIGNED;
4018 nfsm_clget;
4019 if (eofflag)
4020 *tl = nfs_true;
4021 else
4022 *tl = nfs_false;
4023 bp += NFSX_UNSIGNED;
4024 if (mp != mb) {
4025 if (bp < be)
4026 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
4027 } else
4028 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
4029 FREE(rbuf, M_TEMP);
4030 nfsmout:
4031 if (vp)
4032 vnode_put(vp);
4033 return (error);
4034 }
4035
4036 /*
4037 * nfs commit service
4038 */
4039 int
4040 nfsrv_commit(nfsd, slp, procp, mrq)
4041 struct nfsrv_descript *nfsd;
4042 struct nfssvc_sock *slp;
4043 proc_t procp;
4044 mbuf_t *mrq;
4045 {
4046 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4047 mbuf_t nam = nfsd->nd_nam;
4048 caddr_t dpos = nfsd->nd_dpos;
4049 struct vnode_attr bfor, aft;
4050 vnode_t vp;
4051 struct nfs_filehandle nfh;
4052 struct nfs_export *nx;
4053 struct nfs_export_options *nxo;
4054 u_long *tl;
4055 long t1;
4056 caddr_t bpos;
4057 int error = 0, for_ret = 1, aft_ret = 1, count;
4058 char *cp2;
4059 mbuf_t mb, mb2, mreq;
4060 u_quad_t off;
4061 struct vfs_context context;
4062
4063 nfsm_srvmtofh(&nfh);
4064 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
4065
4066 /*
4067 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4068 * count parameters, so these arguments are useless (someday maybe).
4069 */
4070 fxdr_hyper(tl, &off);
4071 tl += 2;
4072 count = fxdr_unsigned(int, *tl);
4073 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4074 nfsm_reply(2 * NFSX_UNSIGNED);
4075 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4076 return (0);
4077 }
4078 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4079 vnode_put(vp);
4080 nfsm_reply(2 * NFSX_UNSIGNED);
4081 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4082 return (0);
4083 }
4084 context.vc_proc = procp;
4085 context.vc_ucred = nfsd->nd_cr;
4086
4087 nfsm_srv_pre_vattr_init(&bfor, 1);
4088 for_ret = vnode_getattr(vp, &bfor, &context);
4089 error = VNOP_FSYNC(vp, MNT_WAIT, &context);
4090 nfsm_srv_vattr_init(&aft, 1);
4091 aft_ret = vnode_getattr(vp, &aft, &context);
4092 vnode_put(vp);
4093 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
4094 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4095 if (!error) {
4096 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
4097 *tl++ = txdr_unsigned(boottime_sec());
4098 *tl = txdr_unsigned(0);
4099 } else
4100 return (0);
4101 nfsmout:
4102 return (error);
4103 }
4104
4105 /*
4106 * nfs statfs service
4107 */
4108 int
4109 nfsrv_statfs(nfsd, slp, procp, mrq)
4110 struct nfsrv_descript *nfsd;
4111 struct nfssvc_sock *slp;
4112 proc_t procp;
4113 mbuf_t *mrq;
4114 {
4115 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4116 mbuf_t nam = nfsd->nd_nam;
4117 caddr_t dpos = nfsd->nd_dpos;
4118 struct vfs_attr va;
4119 struct nfs_statfs *sfp;
4120 u_long *tl;
4121 long t1;
4122 caddr_t bpos;
4123 int error = 0, getret = 1;
4124 int v3 = (nfsd->nd_flag & ND_NFSV3);
4125 char *cp2;
4126 mbuf_t mb, mb2, mreq;
4127 vnode_t vp;
4128 struct vnode_attr at;
4129 struct nfs_filehandle nfh;
4130 struct nfs_export *nx;
4131 struct nfs_export_options *nxo;
4132 u_quad_t tval;
4133 off_t blksize;
4134 struct vfs_context context;
4135
4136 nfsm_srvmtofh(&nfh);
4137 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4138 nfsm_reply(NFSX_UNSIGNED);
4139 nfsm_srvpostop_attr(getret, &at);
4140 return (0);
4141 }
4142 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4143 vnode_put(vp);
4144 nfsm_reply(NFSX_UNSIGNED);
4145 nfsm_srvpostop_attr(getret, &at);
4146 return (0);
4147 }
4148 context.vc_proc = procp;
4149 context.vc_ucred = nfsd->nd_cr;
4150
4151 VFSATTR_INIT(&va);
4152 VFSATTR_WANTED(&va, f_blocks);
4153 VFSATTR_WANTED(&va, f_bavail);
4154 VFSATTR_WANTED(&va, f_files);
4155 VFSATTR_WANTED(&va, f_ffree);
4156 error = vfs_getattr(vnode_mount(vp), &va, &context);
4157 blksize = vnode_mount(vp)->mnt_vfsstat.f_bsize;
4158 nfsm_srv_vattr_init(&at, v3);
4159 getret = vnode_getattr(vp, &at, &context);
4160 vnode_put(vp);
4161 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
4162 if (v3)
4163 nfsm_srvpostop_attr(getret, &at);
4164 if (error)
4165 return (0);
4166 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
4167 if (v3) {
4168 tval = (u_quad_t)(va.f_blocks * blksize);
4169 txdr_hyper(&tval, &sfp->sf_tbytes);
4170 tval = (u_quad_t)(va.f_bfree * blksize);
4171 txdr_hyper(&tval, &sfp->sf_fbytes);
4172 tval = (u_quad_t)(va.f_bavail * blksize);
4173 txdr_hyper(&tval, &sfp->sf_abytes);
4174 txdr_hyper(&va.f_files, &sfp->sf_tfiles);
4175 txdr_hyper(&va.f_ffree, &sfp->sf_ffiles);
4176 txdr_hyper(&va.f_ffree, &sfp->sf_afiles);
4177 sfp->sf_invarsec = 0;
4178 } else {
4179 sfp->sf_tsize = txdr_unsigned(NFS_V2MAXDATA);
4180 sfp->sf_bsize = txdr_unsigned((unsigned)blksize);
4181 sfp->sf_blocks = txdr_unsigned((unsigned)va.f_blocks);
4182 sfp->sf_bfree = txdr_unsigned((unsigned)va.f_bfree);
4183 sfp->sf_bavail = txdr_unsigned((unsigned)va.f_bavail);
4184 }
4185 nfsmout:
4186 return (error);
4187 }
4188
4189 /*
4190 * nfs fsinfo service
4191 */
4192 int
4193 nfsrv_fsinfo(nfsd, slp, procp, mrq)
4194 struct nfsrv_descript *nfsd;
4195 struct nfssvc_sock *slp;
4196 proc_t procp;
4197 mbuf_t *mrq;
4198 {
4199 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4200 mbuf_t nam = nfsd->nd_nam;
4201 caddr_t dpos = nfsd->nd_dpos;
4202 u_long *tl;
4203 struct nfsv3_fsinfo *sip;
4204 long t1;
4205 caddr_t bpos;
4206 int error = 0, getret = 1, prefsize, maxsize;
4207 char *cp2;
4208 mbuf_t mb, mb2, mreq;
4209 vnode_t vp;
4210 struct vnode_attr at;
4211 struct nfs_filehandle nfh;
4212 struct nfs_export *nx;
4213 struct nfs_export_options *nxo;
4214 struct vfs_context context;
4215
4216 nfsm_srvmtofh(&nfh);
4217 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4218 nfsm_reply(NFSX_UNSIGNED);
4219 nfsm_srvpostop_attr(getret, &at);
4220 return (0);
4221 }
4222 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4223 vnode_put(vp);
4224 nfsm_reply(NFSX_UNSIGNED);
4225 nfsm_srvpostop_attr(getret, &at);
4226 return (0);
4227 }
4228 context.vc_proc = procp;
4229 context.vc_ucred = nfsd->nd_cr;
4230
4231 nfsm_srv_vattr_init(&at, 1);
4232 getret = vnode_getattr(vp, &at, &context);
4233 vnode_put(vp);
4234 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
4235 nfsm_srvpostop_attr(getret, &at);
4236 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
4237
4238 /*
4239 * XXX
4240 * There should be file system VFS OP(s) to get this information.
4241 * For now, assume our usual NFS defaults.
4242 */
4243 if (slp->ns_sotype == SOCK_DGRAM) {
4244 maxsize = NFS_MAXDGRAMDATA;
4245 prefsize = NFS_PREFDGRAMDATA;
4246 } else
4247 maxsize = prefsize = NFS_MAXDATA;
4248 sip->fs_rtmax = txdr_unsigned(maxsize);
4249 sip->fs_rtpref = txdr_unsigned(prefsize);
4250 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
4251 sip->fs_wtmax = txdr_unsigned(maxsize);
4252 sip->fs_wtpref = txdr_unsigned(prefsize);
4253 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
4254 sip->fs_dtpref = txdr_unsigned(prefsize);
4255 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
4256 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
4257 sip->fs_timedelta.nfsv3_sec = 0;
4258 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
4259 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
4260 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
4261 NFSV3FSINFO_CANSETTIME);
4262 nfsmout:
4263 return (error);
4264 }
4265
4266 /*
4267 * nfs pathconf service
4268 */
4269 int
4270 nfsrv_pathconf(nfsd, slp, procp, mrq)
4271 struct nfsrv_descript *nfsd;
4272 struct nfssvc_sock *slp;
4273 proc_t procp;
4274 mbuf_t *mrq;
4275 {
4276 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4277 mbuf_t nam = nfsd->nd_nam;
4278 caddr_t dpos = nfsd->nd_dpos;
4279 u_long *tl;
4280 struct nfsv3_pathconf *pc;
4281 long t1;
4282 caddr_t bpos;
4283 int error = 0, getret = 1, linkmax, namemax;
4284 int chownres, notrunc, case_sensitive, case_preserving;
4285 char *cp2;
4286 mbuf_t mb, mb2, mreq;
4287 vnode_t vp;
4288 struct vnode_attr at;
4289 struct nfs_filehandle nfh;
4290 struct nfs_export *nx;
4291 struct nfs_export_options *nxo;
4292 struct vfs_context context;
4293
4294 nfsm_srvmtofh(&nfh);
4295 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4296 nfsm_reply(NFSX_UNSIGNED);
4297 nfsm_srvpostop_attr(getret, &at);
4298 return (0);
4299 }
4300 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4301 vnode_put(vp);
4302 nfsm_reply(NFSX_UNSIGNED);
4303 nfsm_srvpostop_attr(getret, &at);
4304 return (0);
4305 }
4306 context.vc_proc = procp;
4307 context.vc_ucred = nfsd->nd_cr;
4308
4309 error = VNOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax, &context);
4310 if (!error)
4311 error = VNOP_PATHCONF(vp, _PC_NAME_MAX, &namemax, &context);
4312 if (!error)
4313 error = VNOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres, &context);
4314 if (!error)
4315 error = VNOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc, &context);
4316 if (!error)
4317 error = VNOP_PATHCONF(vp, _PC_CASE_SENSITIVE, &case_sensitive, &context);
4318 if (!error)
4319 error = VNOP_PATHCONF(vp, _PC_CASE_PRESERVING, &case_preserving, &context);
4320 nfsm_srv_vattr_init(&at, 1);
4321 getret = vnode_getattr(vp, &at, &context);
4322 vnode_put(vp);
4323 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
4324 nfsm_srvpostop_attr(getret, &at);
4325 if (error)
4326 return (0);
4327 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
4328
4329 pc->pc_linkmax = txdr_unsigned(linkmax);
4330 pc->pc_namemax = txdr_unsigned(namemax);
4331 pc->pc_notrunc = txdr_unsigned(notrunc);
4332 pc->pc_chownrestricted = txdr_unsigned(chownres);
4333 pc->pc_caseinsensitive = txdr_unsigned(!case_sensitive);
4334 pc->pc_casepreserving = txdr_unsigned(case_preserving);
4335
4336 nfsmout:
4337 return (error);
4338 }
4339
4340 /*
4341 * Null operation, used by clients to ping server
4342 */
4343 /* ARGSUSED */
4344 int
4345 nfsrv_null(
4346 struct nfsrv_descript *nfsd,
4347 struct nfssvc_sock *slp,
4348 __unused proc_t procp,
4349 mbuf_t *mrq)
4350 {
4351 mbuf_t mrep = nfsd->nd_mrep;
4352 caddr_t bpos;
4353 int error = NFSERR_RETVOID;
4354 mbuf_t mb, mreq;
4355
4356 nfsm_reply(0);
4357 nfsmout:
4358 return (0);
4359 }
4360
4361 /*
4362 * No operation, used for obsolete procedures
4363 */
4364 /* ARGSUSED */
4365 int
4366 nfsrv_noop(
4367 struct nfsrv_descript *nfsd,
4368 struct nfssvc_sock *slp,
4369 __unused proc_t procp,
4370 mbuf_t *mrq)
4371 {
4372 mbuf_t mrep = nfsd->nd_mrep;
4373 caddr_t bpos;
4374 int error;
4375 mbuf_t mb, mreq;
4376
4377 if (nfsd->nd_repstat)
4378 error = nfsd->nd_repstat;
4379 else
4380 error = EPROCUNAVAIL;
4381 nfsm_reply(0);
4382 nfsmout:
4383 return (0);
4384 }
4385
4386 /*
4387 * Perform access checking for vnodes obtained from file handles that would
4388 * refer to files already opened by a Unix client. You cannot just use
4389 * vnode_authorize() for two reasons.
4390 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4391 * 2 - The owner is to be given access irrespective of mode bits so that
4392 * processes that chmod after opening a file don't break. I don't like
4393 * this because it opens a security hole, but since the nfs server opens
4394 * a security hole the size of a barn door anyhow, what the heck.
4395 *
4396 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4397 * will return EPERM instead of EACCESS. EPERM is always an error.
4398 */
4399
4400 static int
4401 nfsrv_authorize(
4402 vnode_t vp,
4403 vnode_t dvp,
4404 kauth_action_t action,
4405 vfs_context_t context,
4406 struct nfs_export_options *nxo,
4407 int override)
4408 {
4409 struct vnode_attr vattr;
4410 int error;
4411
4412 if (action & KAUTH_VNODE_WRITE_RIGHTS) {
4413 /*
4414 * Disallow write attempts on read-only exports;
4415 * unless the file is a socket or a block or character
4416 * device resident on the file system.
4417 */
4418 if (nxo->nxo_flags & NX_READONLY) {
4419 switch (vnode_vtype(vp)) {
4420 case VREG: case VDIR: case VLNK: case VCPLX:
4421 return (EROFS);
4422 default:
4423 break;
4424 }
4425 }
4426 }
4427 error = vnode_authorize(vp, dvp, action, context);
4428 /*
4429 * Allow certain operations for the owner (reads and writes
4430 * on files that are already open). Picking up from FreeBSD.
4431 */
4432 if (override && (error == EACCES)) {
4433 VATTR_INIT(&vattr);
4434 VATTR_WANTED(&vattr, va_uid);
4435 if ((vnode_getattr(vp, &vattr, context) == 0) &&
4436 (kauth_cred_getuid(vfs_context_ucred(context)) == vattr.va_uid))
4437 error = 0;
4438 }
4439 return error;
4440 }
4441 #endif /* NFS_NOSERVER */
4442