]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
xnu-792.21.3.tar.gz
[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 /*
1175 * Actually, there is no need to txdr these fields,
1176 * but it may make the values more human readable,
1177 * for debugging purposes.
1178 */
1179 *tl++ = txdr_unsigned(boottime_sec());
1180 *tl = txdr_unsigned(0);
1181 } else {
1182 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1183 nfsm_srvfillattr(vap, fp);
1184 }
1185 nfsmout:
1186 if (uio_bufp != NULL) {
1187 FREE(uio_bufp, M_TEMP);
1188 }
1189 return (error);
1190 }
1191
1192 /*
1193 * NFS write service with write gathering support. Called when
1194 * nfsrvw_procrastinate > 0.
1195 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1196 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1197 * Jan. 1994.
1198 */
1199 int
1200 nfsrv_writegather(ndp, slp, procp, mrq)
1201 struct nfsrv_descript **ndp;
1202 struct nfssvc_sock *slp;
1203 proc_t procp;
1204 mbuf_t *mrq;
1205 {
1206 mbuf_t mp;
1207 struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1208 struct nfs_export *nx;
1209 struct nfs_export_options *nxo;
1210 struct nfs_fattr *fp;
1211 int i;
1212 struct nfsrvw_delayhash *wpp;
1213 kauth_cred_t cred;
1214 struct vnode_attr va, forat;
1215 u_long *tl;
1216 long t1;
1217 caddr_t bpos, dpos, tpos;
1218 int error = 0, len, forat_ret = 1;
1219 int ioflags, aftat_ret = 1, adjust, v3, zeroing, tlen;
1220 char *cp2;
1221 mbuf_t mb, mb2, mreq, mrep, md;
1222 vnode_t vp;
1223 uio_t uiop = NULL;
1224 char *uio_bufp = NULL;
1225 u_quad_t cur_usec;
1226 struct timeval now;
1227 struct vfs_context context;
1228
1229 context.vc_proc = procp;
1230
1231 #ifndef nolint
1232 i = 0;
1233 len = 0;
1234 #endif
1235
1236 *mrq = NULL;
1237 if (*ndp) {
1238 nfsd = *ndp;
1239 *ndp = NULL;
1240 mrep = nfsd->nd_mrep;
1241 md = nfsd->nd_md;
1242 dpos = nfsd->nd_dpos;
1243 cred = nfsd->nd_cr;
1244 context.vc_ucred = cred;
1245 v3 = (nfsd->nd_flag & ND_NFSV3);
1246 LIST_INIT(&nfsd->nd_coalesce);
1247 nfsd->nd_mreq = NULL;
1248 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1249 microuptime(&now);
1250 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1251 nfsd->nd_time = cur_usec +
1252 (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
1253
1254 /*
1255 * Now, get the write header..
1256 */
1257 nfsm_srvmtofh(&nfsd->nd_fh);
1258 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1259 if (v3) {
1260 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
1261 fxdr_hyper(tl, &nfsd->nd_off);
1262 tl += 3;
1263 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1264 } else {
1265 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1266 nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
1267 tl += 2;
1268 if (nfs_async)
1269 nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1270 }
1271 len = fxdr_unsigned(long, *tl);
1272 nfsd->nd_len = len;
1273 nfsd->nd_eoff = nfsd->nd_off + len;
1274
1275 /*
1276 * Trim the header out of the mbuf list and trim off any trailing
1277 * junk so that the mbuf list has only the write data.
1278 */
1279 zeroing = 1;
1280 i = 0;
1281 mp = mrep;
1282 while (mp) {
1283 if (mp == md) {
1284 zeroing = 0;
1285 tpos = mbuf_data(mp);
1286 tlen = mbuf_len(mp);
1287 adjust = dpos - tpos;
1288 tlen -= adjust;
1289 mbuf_setlen(mp, tlen);
1290 if (tlen > 0 && adjust > 0) {
1291 tpos += adjust;
1292 if ((error = mbuf_setdata(mp, tpos, tlen)))
1293 goto nfsmout;
1294 }
1295 }
1296 if (zeroing)
1297 mbuf_setlen(mp, 0);
1298 else {
1299 tlen = mbuf_len(mp);
1300 i += tlen;
1301 if (i > len) {
1302 mbuf_setlen(mp, tlen - (i - len));
1303 zeroing = 1;
1304 }
1305 }
1306 mp = mbuf_next(mp);
1307 }
1308 if (len > NFS_MAXDATA || len < 0 || i < len) {
1309 nfsmout:
1310 mbuf_freem(mrep);
1311 mrep = NULL;
1312 error = EIO;
1313 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1314 if (v3)
1315 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1316 nfsd->nd_mreq = mreq;
1317 nfsd->nd_mrep = NULL;
1318 nfsd->nd_time = 1;
1319 }
1320
1321 /*
1322 * Add this entry to the hash and time queues.
1323 */
1324 lck_mtx_lock(&slp->ns_wgmutex);
1325 owp = NULL;
1326 wp = slp->ns_tq.lh_first;
1327 while (wp && wp->nd_time < nfsd->nd_time) {
1328 owp = wp;
1329 wp = wp->nd_tq.le_next;
1330 }
1331 if (owp) {
1332 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1333 } else {
1334 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1335 }
1336 if (nfsd->nd_mrep) {
1337 wpp = NWDELAYHASH(slp, nfsd->nd_fh.nfh_fid);
1338 owp = NULL;
1339 wp = wpp->lh_first;
1340 while (wp && !nfsrv_fhmatch(&nfsd->nd_fh, &wp->nd_fh)) {
1341 owp = wp;
1342 wp = wp->nd_hash.le_next;
1343 }
1344 while (wp && (wp->nd_off < nfsd->nd_off) &&
1345 nfsrv_fhmatch(&nfsd->nd_fh, &wp->nd_fh)) {
1346 owp = wp;
1347 wp = wp->nd_hash.le_next;
1348 }
1349 if (owp) {
1350 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1351
1352 /*
1353 * Search the hash list for overlapping entries and
1354 * coalesce.
1355 */
1356 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1357 wp = nfsd->nd_hash.le_next;
1358 if (NFSW_SAMECRED(owp, nfsd))
1359 nfsrvw_coalesce(owp, nfsd);
1360 }
1361 } else {
1362 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1363 }
1364 }
1365 } else {
1366 lck_mtx_lock(&slp->ns_wgmutex);
1367 }
1368
1369 /*
1370 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1371 * and generate the associated reply mbuf list(s).
1372 */
1373 loop1:
1374 microuptime(&now);
1375 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1376 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1377 owp = nfsd->nd_tq.le_next;
1378 if (nfsd->nd_time > cur_usec)
1379 break;
1380 if (nfsd->nd_mreq)
1381 continue;
1382 LIST_REMOVE(nfsd, nd_tq);
1383 LIST_REMOVE(nfsd, nd_hash);
1384 mrep = nfsd->nd_mrep;
1385 nfsd->nd_mrep = NULL;
1386 v3 = (nfsd->nd_flag & ND_NFSV3);
1387 forat_ret = aftat_ret = 1;
1388 error = nfsrv_fhtovp(&nfsd->nd_fh, nfsd->nd_nam, TRUE, &vp, &nx, &nxo);
1389 if (!error) {
1390 error = nfsrv_credcheck(nfsd, nx, nxo);
1391 if (error)
1392 vnode_put(vp);
1393 }
1394 cred = nfsd->nd_cr;
1395 context.vc_ucred = cred;
1396 if (!error) {
1397 if (v3) {
1398 nfsm_srv_pre_vattr_init(&forat, v3);
1399 forat_ret = vnode_getattr(vp, &forat, &context);
1400 }
1401 if (vnode_vtype(vp) != VREG) {
1402 if (v3)
1403 error = EINVAL;
1404 else
1405 error = (vnode_vtype(vp) == VDIR) ? EISDIR : EACCES;
1406 }
1407 } else
1408 vp = NULL;
1409 if (!error) {
1410 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA, &context, nxo, 1);
1411 }
1412
1413 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1414 ioflags = IO_NODELOCKED;
1415 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1416 ioflags = (IO_SYNC | IO_NODELOCKED);
1417 else
1418 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1419
1420 if (!error && ((nfsd->nd_eoff - nfsd->nd_off) > 0)) {
1421 mp = mrep;
1422 i = 0;
1423 while (mp) {
1424 if (mbuf_len(mp) > 0)
1425 i++;
1426 mp = mbuf_next(mp);
1427 }
1428
1429 MALLOC(uio_bufp, char *, UIO_SIZEOF(i), M_TEMP, M_WAITOK);
1430 if (uio_bufp)
1431 uiop = uio_createwithbuffer(i, nfsd->nd_off, UIO_SYSSPACE,
1432 UIO_WRITE, uio_bufp, UIO_SIZEOF(i));
1433 if (!uio_bufp || !uiop)
1434 error = ENOMEM;
1435 if (!error) {
1436 mp = mrep;
1437 while (mp) {
1438 if ((tlen = mbuf_len(mp)) > 0)
1439 uio_addiov(uiop, CAST_USER_ADDR_T((caddr_t)mbuf_data(mp)), tlen);
1440 mp = mbuf_next(mp);
1441 }
1442 error = VNOP_WRITE(vp, uiop, ioflags, &context);
1443 OSAddAtomic(1, (SInt32*)&nfsstats.srvvop_writes);
1444 }
1445 if (uio_bufp) {
1446 FREE(uio_bufp, M_TEMP);
1447 uio_bufp = NULL;
1448 }
1449 }
1450 mbuf_freem(mrep);
1451 mrep = NULL;
1452 if (vp) {
1453 nfsm_srv_pre_vattr_init(&va, v3);
1454 aftat_ret = vnode_getattr(vp, &va, &context);
1455 vnode_put(vp);
1456 }
1457
1458 /*
1459 * Loop around generating replies for all write rpcs that have
1460 * now been completed.
1461 */
1462 swp = nfsd;
1463 do {
1464 if (error) {
1465 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1466 if (v3) {
1467 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1468 }
1469 } else {
1470 nfsm_writereply(NFSX_PREOPATTR(v3) +
1471 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1472 NFSX_WRITEVERF(v3), v3);
1473 if (v3) {
1474 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1475 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1476 *tl++ = txdr_unsigned(nfsd->nd_len);
1477 *tl++ = txdr_unsigned(swp->nd_stable);
1478 /*
1479 * Actually, there is no need to txdr these fields,
1480 * but it may make the values more human readable,
1481 * for debugging purposes.
1482 */
1483 *tl++ = txdr_unsigned(boottime_sec());
1484 *tl = txdr_unsigned(0);
1485 } else {
1486 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1487 nfsm_srvfillattr(&va, fp);
1488 }
1489 }
1490 nfsd->nd_mreq = mreq;
1491 if (nfsd->nd_mrep)
1492 panic("nfsrv_write: nd_mrep not free");
1493
1494 /*
1495 * Done. Put it at the head of the timer queue so that
1496 * the final phase can return the reply.
1497 */
1498 if (nfsd != swp) {
1499 nfsd->nd_time = 1;
1500 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1501 }
1502 nfsd = swp->nd_coalesce.lh_first;
1503 if (nfsd) {
1504 LIST_REMOVE(nfsd, nd_tq);
1505 }
1506 } while (nfsd);
1507 swp->nd_time = 1;
1508 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1509 goto loop1;
1510 }
1511
1512 /*
1513 * Search for a reply to return.
1514 */
1515 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1516 if (nfsd->nd_mreq) {
1517 LIST_REMOVE(nfsd, nd_tq);
1518 *mrq = nfsd->nd_mreq;
1519 *ndp = nfsd;
1520 break;
1521 }
1522 slp->ns_wgtime = slp->ns_tq.lh_first ? slp->ns_tq.lh_first->nd_time : 0;
1523 lck_mtx_unlock(&slp->ns_wgmutex);
1524 return (0);
1525 }
1526
1527 /*
1528 * Coalesce the write request nfsd into owp. To do this we must:
1529 * - remove nfsd from the queues
1530 * - merge nfsd->nd_mrep into owp->nd_mrep
1531 * - update the nd_eoff and nd_stable for owp
1532 * - put nfsd on owp's nd_coalesce list
1533 */
1534 static void
1535 nfsrvw_coalesce(
1536 struct nfsrv_descript *owp,
1537 struct nfsrv_descript *nfsd)
1538 {
1539 int overlap, error;
1540 mbuf_t mp, mpnext;
1541 struct nfsrv_descript *p;
1542
1543 LIST_REMOVE(nfsd, nd_hash);
1544 LIST_REMOVE(nfsd, nd_tq);
1545 if (owp->nd_eoff < nfsd->nd_eoff) {
1546 overlap = owp->nd_eoff - nfsd->nd_off;
1547 if (overlap < 0)
1548 panic("nfsrv_coalesce: bad off");
1549 if (overlap > 0)
1550 mbuf_adj(nfsd->nd_mrep, overlap);
1551 mp = owp->nd_mrep;
1552 while ((mpnext = mbuf_next(mp)))
1553 mp = mpnext;
1554 error = mbuf_setnext(mp, nfsd->nd_mrep);
1555 if (error)
1556 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error);
1557 owp->nd_eoff = nfsd->nd_eoff;
1558 } else {
1559 mbuf_freem(nfsd->nd_mrep);
1560 }
1561 nfsd->nd_mrep = NULL;
1562 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1563 owp->nd_stable = NFSV3WRITE_FILESYNC;
1564 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1565 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1566 owp->nd_stable = NFSV3WRITE_DATASYNC;
1567 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1568
1569 /*
1570 * If nfsd had anything else coalesced into it, transfer them
1571 * to owp, otherwise their replies will never get sent.
1572 */
1573 for (p = nfsd->nd_coalesce.lh_first; p;
1574 p = nfsd->nd_coalesce.lh_first) {
1575 LIST_REMOVE(p, nd_tq);
1576 LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1577 }
1578 }
1579
1580 /*
1581 * Sort the group list in increasing numerical order.
1582 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1583 * that used to be here.)
1584 *
1585 * XXX ILLEGAL
1586 */
1587 void
1588 nfsrvw_sort(list, num)
1589 gid_t *list;
1590 int num;
1591 {
1592 int i, j;
1593 gid_t v;
1594
1595 /* Insertion sort. */
1596 for (i = 1; i < num; i++) {
1597 v = list[i];
1598 /* find correct slot for value v, moving others up */
1599 for (j = i; --j >= 0 && v < list[j];)
1600 list[j + 1] = list[j];
1601 list[j + 1] = v;
1602 }
1603 }
1604
1605 /*
1606 * copy credentials making sure that the result can be compared with bcmp().
1607 *
1608 * XXX ILLEGAL
1609 */
1610 void
1611 nfsrv_setcred(kauth_cred_t incred, kauth_cred_t outcred)
1612 {
1613 int i;
1614
1615 bzero((caddr_t)outcred, sizeof (*outcred));
1616 outcred->cr_ref = 1;
1617 outcred->cr_uid = kauth_cred_getuid(incred);
1618 outcred->cr_ngroups = incred->cr_ngroups;
1619 for (i = 0; i < incred->cr_ngroups; i++)
1620 outcred->cr_groups[i] = incred->cr_groups[i];
1621 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1622 }
1623
1624 /*
1625 * nfs create service
1626 * now does a truncate to 0 length via. setattr if it already exists
1627 */
1628 int
1629 nfsrv_create(nfsd, slp, procp, mrq)
1630 struct nfsrv_descript *nfsd;
1631 struct nfssvc_sock *slp;
1632 proc_t procp;
1633 mbuf_t *mrq;
1634 {
1635 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
1636 mbuf_t nam = nfsd->nd_nam;
1637 caddr_t dpos = nfsd->nd_dpos;
1638 struct nfs_fattr *fp;
1639 struct vnode_attr dirfor, diraft, postat;
1640 struct vnode_attr va;
1641 struct vnode_attr *vap = &va;
1642 struct nfsv2_sattr *sp;
1643 u_long *tl;
1644 struct nameidata nd;
1645 caddr_t cp;
1646 long t1;
1647 caddr_t bpos;
1648 int error = 0, rdev, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1649 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1650 char *cp2;
1651 mbuf_t mb, mb2, mreq;
1652 vnode_t vp, dvp, dirp = NULL;
1653 struct nfs_filehandle nfh;
1654 struct nfs_export *nx;
1655 struct nfs_export_options *nxo;
1656 u_quad_t tempsize;
1657 u_char cverf[NFSX_V3CREATEVERF];
1658 struct vfs_context context;
1659 uid_t saved_uid;
1660
1661 context.vc_proc = procp;
1662 context.vc_ucred = nfsd->nd_cr;
1663
1664 /*
1665 * Save the original credential UID in case they are
1666 * mapped and we need to map the IDs in the attributes.
1667 */
1668 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
1669
1670 #ifndef nolint
1671 rdev = 0;
1672 #endif
1673 nd.ni_cnd.cn_nameiop = 0;
1674 vp = dvp = NULL;
1675 nfsm_srvmtofh(&nfh);
1676 nfsm_srvnamesiz(len, v3);
1677
1678 nd.ni_cnd.cn_nameiop = CREATE;
1679 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1680 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
1681 if (!error)
1682 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
1683 if (dirp) {
1684 if (v3) {
1685 nfsm_srv_pre_vattr_init(&dirfor, v3);
1686 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
1687 } else {
1688 vnode_put(dirp);
1689 dirp = NULL;
1690 }
1691 }
1692 if (error) {
1693 nd.ni_cnd.cn_nameiop = 0;
1694 nfsm_reply(NFSX_WCCDATA(v3));
1695 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1696 if (dirp)
1697 vnode_put(dirp);
1698 return (0);
1699 }
1700 dvp = nd.ni_dvp;
1701 vp = nd.ni_vp;
1702
1703 VATTR_INIT(vap);
1704
1705 if (v3) {
1706 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1707 how = fxdr_unsigned(int, *tl);
1708 switch (how) {
1709 case NFSV3CREATE_GUARDED:
1710 if (vp) {
1711 error = EEXIST;
1712 break;
1713 }
1714 case NFSV3CREATE_UNCHECKED:
1715 nfsm_srvsattr(vap);
1716 break;
1717 case NFSV3CREATE_EXCLUSIVE:
1718 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1719 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1720 exclusive_flag = 1;
1721 if (vp == NULL)
1722 VATTR_SET(vap, va_mode, 0);
1723 break;
1724 };
1725 VATTR_SET(vap, va_type, VREG);
1726 } else {
1727 enum vtype v_type;
1728
1729 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1730 v_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1731 if (v_type == VNON)
1732 v_type = VREG;
1733 VATTR_SET(vap, va_type, v_type);
1734 VATTR_SET(vap, va_mode, nfstov_mode(sp->sa_mode));
1735
1736 switch (v_type) {
1737 case VREG:
1738 tsize = fxdr_unsigned(long, sp->sa_size);
1739 if (tsize != -1)
1740 VATTR_SET(vap, va_data_size, (u_quad_t)tsize);
1741 break;
1742 case VCHR:
1743 case VBLK:
1744 case VFIFO:
1745 rdev = fxdr_unsigned(long, sp->sa_size);
1746 break;
1747 default:
1748 break;
1749 };
1750 }
1751
1752 /*
1753 * If it doesn't exist, create it
1754 * otherwise just truncate to 0 length
1755 * should I set the mode too ??
1756 */
1757 if (vp == NULL) {
1758 kauth_acl_t xacl = NULL;
1759
1760 /*
1761 * If the credentials were mapped, we should
1762 * map the same values in the attributes.
1763 */
1764 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
1765 int ismember;
1766 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
1767 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
1768 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
1769 }
1770
1771 /* authorize before creating */
1772 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
1773
1774 /* construct ACL and handle inheritance */
1775 if (!error) {
1776 error = kauth_acl_inherit(dvp,
1777 NULL,
1778 &xacl,
1779 0 /* !isdir */,
1780 &context);
1781
1782 if (!error && xacl != NULL)
1783 VATTR_SET(vap, va_acl, xacl);
1784 }
1785 VATTR_CLEAR_ACTIVE(vap, va_data_size);
1786 VATTR_CLEAR_ACTIVE(vap, va_access_time);
1787
1788 /* validate new-file security information */
1789 if (!error) {
1790 error = vnode_authattr_new(dvp, vap, 0, &context);
1791 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
1792 /*
1793 * Most NFS servers just ignore the UID/GID attributes, so we
1794 * try ignoring them if that'll help the request succeed.
1795 */
1796 VATTR_CLEAR_ACTIVE(vap, va_uid);
1797 VATTR_CLEAR_ACTIVE(vap, va_gid);
1798 error = vnode_authattr_new(dvp, vap, 0, &context);
1799 }
1800 }
1801
1802 if (vap->va_type == VREG || vap->va_type == VSOCK) {
1803
1804 if (!error)
1805 error = VNOP_CREATE(dvp, &vp, &nd.ni_cnd, vap, &context);
1806
1807 if (!error && !VATTR_ALL_SUPPORTED(vap))
1808 /*
1809 * If some of the requested attributes weren't handled by the VNOP,
1810 * use our fallback code.
1811 */
1812 error = vnode_setattr_fallback(vp, vap, &context);
1813
1814 if (xacl != NULL)
1815 kauth_acl_free(xacl);
1816
1817 if (!error) {
1818 if (exclusive_flag) {
1819 exclusive_flag = 0;
1820 VATTR_INIT(vap);
1821 bcopy(cverf, (caddr_t)&vap->va_access_time,
1822 NFSX_V3CREATEVERF);
1823 VATTR_SET_ACTIVE(vap, va_access_time);
1824 // skip authorization, as this is an
1825 // NFS internal implementation detail.
1826 error = vnode_setattr(vp, vap, &context);
1827 }
1828 }
1829
1830 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1831 vap->va_type == VFIFO) {
1832 if (vap->va_type == VCHR && rdev == (int)0xffffffff)
1833 VATTR_SET(vap, va_type, VFIFO);
1834 if (vap->va_type != VFIFO &&
1835 (error = suser(nfsd->nd_cr, (u_short *)0))) {
1836 nfsm_reply(0);
1837 } else
1838 VATTR_SET(vap, va_rdev, (dev_t)rdev);
1839
1840 error = VNOP_MKNOD(dvp, &vp, &nd.ni_cnd, vap, &context);
1841
1842 if (xacl != NULL)
1843 kauth_acl_free(xacl);
1844
1845 if (error) {
1846 nfsm_reply(0);
1847 }
1848 if (vp) {
1849 vnode_recycle(vp);
1850 vnode_put(vp);
1851 vp = NULL;
1852 }
1853 nd.ni_cnd.cn_nameiop = LOOKUP;
1854 nd.ni_cnd.cn_flags &= ~LOCKPARENT;
1855 nd.ni_cnd.cn_context = &context;
1856 nd.ni_startdir = dvp;
1857 nd.ni_usedvp = dvp;
1858 error = lookup(&nd);
1859 if (!error) {
1860 if (nd.ni_cnd.cn_flags & ISSYMLINK)
1861 error = EINVAL;
1862 vp = nd.ni_vp;
1863 }
1864 if (error)
1865 nfsm_reply(0);
1866 } else {
1867 error = ENXIO;
1868 }
1869 /*
1870 * nameidone has to happen before we vnode_put(dvp)
1871 * since it may need to release the fs_nodelock on the dvp
1872 */
1873 nameidone(&nd);
1874 nd.ni_cnd.cn_nameiop = 0;
1875
1876 vnode_put(dvp);
1877 } else {
1878 /*
1879 * nameidone has to happen before we vnode_put(dvp)
1880 * since it may need to release the fs_nodelock on the dvp
1881 */
1882 nameidone(&nd);
1883 nd.ni_cnd.cn_nameiop = 0;
1884
1885 vnode_put(dvp);
1886
1887 if (!error && VATTR_IS_ACTIVE(vap, va_data_size)) {
1888 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA,
1889 &context, nxo, 0);
1890 if (!error) {
1891 tempsize = vap->va_data_size;
1892 VATTR_INIT(vap);
1893 VATTR_SET(vap, va_data_size, tempsize);
1894 error = vnode_setattr(vp, vap, &context);
1895 }
1896 }
1897 }
1898 if (!error) {
1899 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
1900 if (!error) {
1901 nfsm_srv_vattr_init(&postat, v3);
1902 error = vnode_getattr(vp, &postat, &context);
1903 }
1904 }
1905 if (vp)
1906 vnode_put(vp);
1907
1908 if (v3) {
1909 if (exclusive_flag && !error &&
1910 bcmp(cverf, (caddr_t)&postat.va_access_time, NFSX_V3CREATEVERF))
1911 error = EEXIST;
1912 nfsm_srv_vattr_init(&diraft, v3);
1913 diraft_ret = vnode_getattr(dirp, &diraft, &context);
1914 vnode_put(dirp);
1915 dirp = NULL;
1916 }
1917 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1918
1919 if (v3) {
1920 if (!error) {
1921 nfsm_srvpostop_fh(&nfh);
1922 nfsm_srvpostop_attr(0, &postat);
1923 }
1924 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1925 } else {
1926 nfsm_srvfhtom(&nfh, v3);
1927 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1928 nfsm_srvfillattr(&postat, fp);
1929 }
1930 return (0);
1931 nfsmout:
1932 if (nd.ni_cnd.cn_nameiop) {
1933 /*
1934 * nameidone has to happen before we vnode_put(dvp)
1935 * since it may need to release the fs_nodelock on the dvp
1936 */
1937 nameidone(&nd);
1938
1939 if (vp)
1940 vnode_put(vp);
1941 vnode_put(dvp);
1942 }
1943 if (dirp)
1944 vnode_put(dirp);
1945 return (error);
1946 }
1947
1948 /*
1949 * nfs v3 mknod service
1950 */
1951 int
1952 nfsrv_mknod(nfsd, slp, procp, mrq)
1953 struct nfsrv_descript *nfsd;
1954 struct nfssvc_sock *slp;
1955 proc_t procp;
1956 mbuf_t *mrq;
1957 {
1958 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
1959 mbuf_t nam = nfsd->nd_nam;
1960 caddr_t dpos = nfsd->nd_dpos;
1961 struct vnode_attr dirfor, diraft, postat;
1962 struct vnode_attr va;
1963 struct vnode_attr *vap = &va;
1964 u_long *tl;
1965 struct nameidata nd;
1966 long t1;
1967 caddr_t bpos;
1968 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1969 u_long major, minor;
1970 enum vtype vtyp;
1971 char *cp2;
1972 mbuf_t mb, mb2, mreq;
1973 vnode_t vp, dvp, dirp = NULL;
1974 struct nfs_filehandle nfh;
1975 struct nfs_export *nx;
1976 struct nfs_export_options *nxo;
1977 struct vfs_context hacked_context; /* XXX should we have this? */
1978 struct vfs_context context;
1979 uid_t saved_uid;
1980 kauth_acl_t xacl = NULL;
1981
1982 context.vc_proc = procp;
1983 context.vc_ucred = nfsd->nd_cr;
1984 hacked_context.vc_proc = procp;
1985 hacked_context.vc_ucred = proc_ucred(procp);
1986
1987 /*
1988 * Save the original credential UID in case they are
1989 * mapped and we need to map the IDs in the attributes.
1990 */
1991 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
1992
1993 vp = dvp = NULL;
1994 nd.ni_cnd.cn_nameiop = 0;
1995 nfsm_srvmtofh(&nfh);
1996 nfsm_srvnamesiz(len, 1);
1997
1998 nd.ni_cnd.cn_nameiop = CREATE;
1999 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2000 error = nfsm_path_mbuftond(&md, &dpos, 1, FALSE, &len, &nd);
2001 if (!error)
2002 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2003 if (dirp) {
2004 nfsm_srv_pre_vattr_init(&dirfor, 1);
2005 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2006 }
2007 if (error) {
2008 nd.ni_cnd.cn_nameiop = 0;
2009 nfsm_reply(NFSX_WCCDATA(1));
2010 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2011 if (dirp)
2012 vnode_put(dirp);
2013 return (0);
2014 }
2015 dvp = nd.ni_dvp;
2016 vp = nd.ni_vp;
2017
2018 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2019 vtyp = nfsv3tov_type(*tl);
2020 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
2021 error = NFSERR_BADTYPE;
2022 goto out;
2023 }
2024 VATTR_INIT(vap);
2025 nfsm_srvsattr(vap);
2026
2027 if (vtyp == VCHR || vtyp == VBLK) {
2028 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2029 major = fxdr_unsigned(u_long, *tl++);
2030 minor = fxdr_unsigned(u_long, *tl);
2031 VATTR_SET(vap, va_rdev, makedev(major, minor));
2032 }
2033
2034 /*
2035 * If it doesn't exist, create it.
2036 */
2037 if (vp) {
2038 error = EEXIST;
2039 goto out;
2040 }
2041 VATTR_SET(vap, va_type, vtyp);
2042
2043 /*
2044 * If the credentials were mapped, we should
2045 * map the same values in the attributes.
2046 */
2047 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
2048 int ismember;
2049 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
2050 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
2051 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
2052 }
2053
2054 /* authorize before creating */
2055 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2056
2057 /* construct ACL and handle inheritance */
2058 if (!error) {
2059 error = kauth_acl_inherit(dvp,
2060 NULL,
2061 &xacl,
2062 0 /* !isdir */,
2063 &context);
2064
2065 if (!error && xacl != NULL)
2066 VATTR_SET(vap, va_acl, xacl);
2067 }
2068 VATTR_CLEAR_ACTIVE(vap, va_data_size);
2069 VATTR_CLEAR_ACTIVE(vap, va_access_time);
2070
2071 /* validate new-file security information */
2072 if (!error) {
2073 error = vnode_authattr_new(dvp, vap, 0, &context);
2074 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
2075 /*
2076 * Most NFS servers just ignore the UID/GID attributes, so we
2077 * try ignoring them if that'll help the request succeed.
2078 */
2079 VATTR_CLEAR_ACTIVE(vap, va_uid);
2080 VATTR_CLEAR_ACTIVE(vap, va_gid);
2081 error = vnode_authattr_new(dvp, vap, 0, &context);
2082 }
2083 }
2084
2085 if (vtyp == VSOCK) {
2086 error = VNOP_CREATE(dvp, &vp, &nd.ni_cnd, vap, &context);
2087
2088 if (!error && !VATTR_ALL_SUPPORTED(vap))
2089 /*
2090 * If some of the requested attributes weren't handled by the VNOP,
2091 * use our fallback code.
2092 */
2093 error = vnode_setattr_fallback(vp, vap, &context);
2094 } else {
2095 if (vtyp != VFIFO && (error = suser(nfsd->nd_cr, (u_short *)0))) {
2096 goto out1;
2097 }
2098 if ((error = VNOP_MKNOD(dvp, &vp, &nd.ni_cnd, vap, &context))) {
2099 goto out1;
2100 }
2101 if (vp) {
2102 vnode_recycle(vp);
2103 vnode_put(vp);
2104 vp = NULL;
2105 }
2106 nd.ni_cnd.cn_nameiop = LOOKUP;
2107 nd.ni_cnd.cn_flags &= ~LOCKPARENT;
2108 nd.ni_cnd.cn_context = &hacked_context;
2109 nd.ni_startdir = dvp;
2110 nd.ni_usedvp = dvp;
2111 error = lookup(&nd);
2112 if (!error) {
2113 vp = nd.ni_vp;
2114 if (nd.ni_cnd.cn_flags & ISSYMLINK)
2115 error = EINVAL;
2116 }
2117 }
2118 out1:
2119 if (xacl != NULL)
2120 kauth_acl_free(xacl);
2121 out:
2122 /*
2123 * nameidone has to happen before we vnode_put(dvp)
2124 * since it may need to release the fs_nodelock on the dvp
2125 */
2126 nameidone(&nd);
2127 nd.ni_cnd.cn_nameiop = 0;
2128
2129 vnode_put(dvp);
2130
2131 if (!error) {
2132 error = nfsrv_vptofh(nx, 0, NULL, vp, &context, &nfh);
2133 if (!error) {
2134 nfsm_srv_vattr_init(&postat, 1);
2135 error = vnode_getattr(vp, &postat, &context);
2136 }
2137 }
2138 if (vp)
2139 vnode_put(vp);
2140
2141 nfsm_srv_vattr_init(&diraft, 1);
2142 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2143 vnode_put(dirp);
2144 dirp = NULL;
2145
2146 nfsm_reply(NFSX_SRVFH(1, &nfh) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2147 if (!error) {
2148 nfsm_srvpostop_fh(&nfh);
2149 nfsm_srvpostop_attr(0, &postat);
2150 }
2151 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2152 return (0);
2153 nfsmout:
2154 if (nd.ni_cnd.cn_nameiop) {
2155 /*
2156 * nameidone has to happen before we vnode_put(dvp)
2157 * since it may need to release the fs_nodelock on the dvp
2158 */
2159 nameidone(&nd);
2160
2161 if (vp)
2162 vnode_put(vp);
2163 vnode_put(dvp);
2164 }
2165 if (dirp)
2166 vnode_put(dirp);
2167 return (error);
2168 }
2169
2170 /*
2171 * nfs remove service
2172 */
2173 int
2174 nfsrv_remove(nfsd, slp, procp, mrq)
2175 struct nfsrv_descript *nfsd;
2176 struct nfssvc_sock *slp;
2177 proc_t procp;
2178 mbuf_t *mrq;
2179 {
2180 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2181 mbuf_t nam = nfsd->nd_nam;
2182 caddr_t dpos = nfsd->nd_dpos;
2183 struct nameidata nd;
2184 u_long *tl;
2185 long t1;
2186 caddr_t bpos;
2187 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2188 int v3 = (nfsd->nd_flag & ND_NFSV3);
2189 char *cp2;
2190 mbuf_t mb, mreq;
2191 vnode_t vp, dvp, dirp = NULL;
2192 struct vnode_attr dirfor, diraft;
2193 struct nfs_filehandle nfh;
2194 struct nfs_export *nx;
2195 struct nfs_export_options *nxo;
2196 struct vfs_context context;
2197
2198 context.vc_proc = procp;
2199 context.vc_ucred = nfsd->nd_cr;
2200
2201 dvp = vp = NULL;
2202 nfsm_srvmtofh(&nfh);
2203 nfsm_srvnamesiz(len, v3);
2204
2205 nd.ni_cnd.cn_nameiop = DELETE;
2206 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2207 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2208 if (!error)
2209 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2210 if (dirp) {
2211 if (v3) {
2212 nfsm_srv_pre_vattr_init(&dirfor, v3);
2213 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2214 } else {
2215 vnode_put(dirp);
2216 dirp = NULL;
2217 }
2218 }
2219 if (!error) {
2220 dvp = nd.ni_dvp;
2221 vp = nd.ni_vp;
2222
2223 if (vnode_vtype(vp) == VDIR)
2224 error = EPERM; /* POSIX */
2225 else if (vnode_isvroot(vp))
2226 /*
2227 * The root of a mounted filesystem cannot be deleted.
2228 */
2229 error = EBUSY;
2230 else
2231 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
2232
2233 if (!error)
2234 error = VNOP_REMOVE(dvp, vp, &nd.ni_cnd, 0, &context);
2235
2236 /*
2237 * nameidone has to happen before we vnode_put(dvp)
2238 * since it may need to release the fs_nodelock on the dvp
2239 */
2240 nameidone(&nd);
2241
2242 vnode_put(vp);
2243 vnode_put(dvp);
2244 }
2245 if (dirp) {
2246 nfsm_srv_vattr_init(&diraft, v3);
2247 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2248 vnode_put(dirp);
2249 }
2250 nfsm_reply(NFSX_WCCDATA(v3));
2251 if (v3) {
2252 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2253 return (0);
2254 }
2255 nfsmout:
2256 return (error);
2257 }
2258
2259 /*
2260 * nfs rename service
2261 */
2262 int
2263 nfsrv_rename(nfsd, slp, procp, mrq)
2264 struct nfsrv_descript *nfsd;
2265 struct nfssvc_sock *slp;
2266 proc_t procp;
2267 mbuf_t *mrq;
2268 {
2269 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2270 mbuf_t nam = nfsd->nd_nam;
2271 caddr_t dpos = nfsd->nd_dpos;
2272 kauth_cred_t saved_cred = NULL;
2273 u_long *tl;
2274 long t1;
2275 caddr_t bpos;
2276 int error = 0, fromlen, tolen;
2277 int fdirfor_ret = 1, fdiraft_ret = 1;
2278 int tdirfor_ret = 1, tdiraft_ret = 1;
2279 int v3 = (nfsd->nd_flag & ND_NFSV3);
2280 char *cp2, *frompath = NULL, *topath = NULL;
2281 mbuf_t mb, mreq;
2282 struct nameidata fromnd, tond;
2283 vnode_t fvp, tvp, tdvp, fdvp, fdirp = NULL;
2284 vnode_t tdirp = NULL;
2285 struct vnode_attr fdirfor, fdiraft, tdirfor, tdiraft;
2286 struct nfs_filehandle fnfh, tnfh;
2287 struct nfs_export *fnx, *tnx;
2288 struct nfs_export_options *fnxo, *tnxo;
2289 enum vtype fvtype, tvtype;
2290 int holding_mntlock;
2291 mount_t locked_mp;
2292 struct vfs_context context;
2293
2294 context.vc_proc = procp;
2295 context.vc_ucred = nfsd->nd_cr;
2296
2297 #ifndef nolint
2298 fvp = (vnode_t)0;
2299 #endif
2300
2301 /*
2302 * these need to be set before
2303 * calling any nfsm_xxxx macros
2304 * since they may take us out
2305 * through the error path
2306 */
2307 holding_mntlock = 0;
2308 fvp = tvp = NULL;
2309 fdvp = tdvp = NULL;
2310 locked_mp = NULL;
2311
2312 nfsm_srvmtofh(&fnfh);
2313 nfsm_srvnamesiz(fromlen, v3);
2314 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &fromlen, &fromnd);
2315 if (error) {
2316 nfsm_reply(0);
2317 return (0);
2318 }
2319 frompath = fromnd.ni_cnd.cn_pnbuf;
2320 nfsm_srvmtofh(&tnfh);
2321 nfsm_strsiz(tolen, NFS_MAXNAMLEN, v3);
2322 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &tolen, &tond);
2323 if (error) {
2324 nfsm_reply(0);
2325 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2326 return (0);
2327 }
2328 topath = tond.ni_cnd.cn_pnbuf;
2329
2330 /*
2331 * Remember our original uid so that we can reset cr_uid before
2332 * the second nfs_namei() call, in case it is remapped.
2333 */
2334 saved_cred = nfsd->nd_cr;
2335 kauth_cred_ref(saved_cred);
2336 retry:
2337 fromnd.ni_cnd.cn_nameiop = DELETE;
2338 fromnd.ni_cnd.cn_flags = WANTPARENT;
2339
2340 fromnd.ni_cnd.cn_pnbuf = frompath;
2341 frompath = NULL;
2342 fromnd.ni_cnd.cn_pnlen = MAXPATHLEN;
2343 fromnd.ni_cnd.cn_flags |= HASBUF;
2344
2345 error = nfs_namei(nfsd, &context, &fromnd, &fnfh, nam, FALSE, &fdirp, &fnx, &fnxo);
2346 if (error)
2347 goto out;
2348 fdvp = fromnd.ni_dvp;
2349 fvp = fromnd.ni_vp;
2350
2351 if (fdirp) {
2352 if (v3) {
2353 nfsm_srv_pre_vattr_init(&fdirfor, v3);
2354 fdirfor_ret = vnode_getattr(fdirp, &fdirfor, &context);
2355 } else {
2356 vnode_put(fdirp);
2357 fdirp = NULL;
2358 }
2359 }
2360 fvtype = vnode_vtype(fvp);
2361
2362 /* reset credential if it was remapped */
2363 if (nfsd->nd_cr != saved_cred) {
2364 kauth_cred_rele(nfsd->nd_cr);
2365 nfsd->nd_cr = saved_cred;
2366 kauth_cred_ref(nfsd->nd_cr);
2367 }
2368
2369 tond.ni_cnd.cn_nameiop = RENAME;
2370 tond.ni_cnd.cn_flags = WANTPARENT;
2371
2372 tond.ni_cnd.cn_pnbuf = topath;
2373 topath = NULL;
2374 tond.ni_cnd.cn_pnlen = MAXPATHLEN;
2375 tond.ni_cnd.cn_flags |= HASBUF;
2376
2377 if (fvtype == VDIR)
2378 tond.ni_cnd.cn_flags |= WILLBEDIR;
2379
2380 error = nfs_namei(nfsd, &context, &tond, &tnfh, nam, FALSE, &tdirp, &tnx, &tnxo);
2381 if (error) {
2382 /*
2383 * Translate error code for rename("dir1", "dir2/.").
2384 */
2385 if (error == EISDIR && fvtype == VDIR) {
2386 if (v3)
2387 error = EINVAL;
2388 else
2389 error = ENOTEMPTY;
2390 }
2391 goto out;
2392 }
2393 tdvp = tond.ni_dvp;
2394 tvp = tond.ni_vp;
2395
2396 if (tdirp) {
2397 if (v3) {
2398 nfsm_srv_pre_vattr_init(&tdirfor, v3);
2399 tdirfor_ret = vnode_getattr(tdirp, &tdirfor, &context);
2400 } else {
2401 vnode_put(tdirp);
2402 tdirp = NULL;
2403 }
2404 }
2405
2406 if (tvp != NULL) {
2407 tvtype = vnode_vtype(tvp);
2408
2409 if (fvtype == VDIR && tvtype != VDIR) {
2410 if (v3)
2411 error = EEXIST;
2412 else
2413 error = EISDIR;
2414 goto out;
2415 } else if (fvtype != VDIR && tvtype == VDIR) {
2416 if (v3)
2417 error = EEXIST;
2418 else
2419 error = ENOTDIR;
2420 goto out;
2421 }
2422 if (tvtype == VDIR && vnode_mountedhere(tvp)) {
2423 if (v3)
2424 error = EXDEV;
2425 else
2426 error = ENOTEMPTY;
2427 goto out;
2428 }
2429 }
2430 if (fvp == tdvp) {
2431 if (v3)
2432 error = EINVAL;
2433 else
2434 error = ENOTEMPTY;
2435 goto out;
2436 }
2437
2438 /*
2439 * Authorization.
2440 *
2441 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2442 * the node is moving between directories and we need rights to remove from the
2443 * old and add to the new.
2444 *
2445 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2446 *
2447 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2448 * implement the deferred-inherit bit.
2449 */
2450 {
2451 int moving = 0;
2452
2453 error = 0;
2454 if ((tvp != NULL) && vnode_isdir(tvp)) {
2455 if (tvp != fdvp)
2456 moving = 1;
2457 } else if (tdvp != fdvp) {
2458 moving = 1;
2459 }
2460 if (moving) {
2461 /* moving out of fdvp, must have delete rights */
2462 if ((error = nfsrv_authorize(fvp, fdvp, KAUTH_VNODE_DELETE, &context, fnxo, 0)) != 0)
2463 goto auth_exit;
2464 /* moving into tdvp or tvp, must have rights to add */
2465 if ((error = nfsrv_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
2466 NULL,
2467 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2468 &context, tnxo, 0)) != 0)
2469 goto auth_exit;
2470 } else {
2471 /* node staying in same directory, must be allowed to add new name */
2472 if ((error = nfsrv_authorize(fdvp, NULL,
2473 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2474 &context, fnxo, 0)) != 0)
2475 goto auth_exit;
2476 }
2477 /* overwriting tvp */
2478 if ((tvp != NULL) && !vnode_isdir(tvp) &&
2479 ((error = nfsrv_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, &context, tnxo, 0)) != 0))
2480 goto auth_exit;
2481
2482 /* XXX more checks? */
2483
2484 auth_exit:
2485 /* authorization denied */
2486 if (error != 0)
2487 goto out;
2488 }
2489
2490 if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
2491 (tvp && (vnode_mount(fvp) != vnode_mount(tvp)))) {
2492 if (v3)
2493 error = EXDEV;
2494 else
2495 error = ENOTEMPTY;
2496 goto out;
2497 }
2498 /*
2499 * The following edge case is caught here:
2500 * (to cannot be a descendent of from)
2501 *
2502 * o fdvp
2503 * /
2504 * /
2505 * o fvp
2506 * \
2507 * \
2508 * o tdvp
2509 * /
2510 * /
2511 * o tvp
2512 */
2513 if (tdvp->v_parent == fvp) {
2514 if (v3)
2515 error = EXDEV;
2516 else
2517 error = ENOTEMPTY;
2518 goto out;
2519 }
2520 if (fvtype == VDIR && vnode_mountedhere(fvp)) {
2521 if (v3)
2522 error = EXDEV;
2523 else
2524 error = ENOTEMPTY;
2525 goto out;
2526 }
2527 /*
2528 * If source is the same as the destination (that is the
2529 * same vnode) then there is nothing to do...
2530 * EXCEPT if the underlying file system supports case
2531 * insensitivity and is case preserving. In this case
2532 * the file system needs to handle the special case of
2533 * getting the same vnode as target (fvp) and source (tvp).
2534 *
2535 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2536 * and _PC_CASE_PRESERVING can have this exception, and they need to
2537 * handle the special case of getting the same vnode as target and
2538 * source. NOTE: Then the target is unlocked going into vnop_rename,
2539 * so not to cause locking problems. There is a single reference on tvp.
2540 *
2541 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2542 * that correct behaviour then is just to remove the source (link)
2543 */
2544 if ((fvp == tvp) && (fdvp == tdvp)) {
2545 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2546 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2547 fromnd.ni_cnd.cn_namelen)) {
2548 goto out;
2549 }
2550 }
2551
2552 if (holding_mntlock && vnode_mount(fvp) != locked_mp) {
2553 /*
2554 * we're holding a reference and lock
2555 * on locked_mp, but it no longer matches
2556 * what we want to do... so drop our hold
2557 */
2558 mount_unlock_renames(locked_mp);
2559 mount_drop(locked_mp, 0);
2560 holding_mntlock = 0;
2561 }
2562 if (tdvp != fdvp && fvtype == VDIR) {
2563 /*
2564 * serialize renames that re-shape
2565 * the tree... if holding_mntlock is
2566 * set, then we're ready to go...
2567 * otherwise we
2568 * first need to drop the iocounts
2569 * we picked up, second take the
2570 * lock to serialize the access,
2571 * then finally start the lookup
2572 * process over with the lock held
2573 */
2574 if (!holding_mntlock) {
2575 /*
2576 * need to grab a reference on
2577 * the mount point before we
2578 * drop all the iocounts... once
2579 * the iocounts are gone, the mount
2580 * could follow
2581 */
2582 locked_mp = vnode_mount(fvp);
2583 mount_ref(locked_mp, 0);
2584
2585 /* make a copy of to path to pass to nfs_namei() again */
2586 MALLOC_ZONE(topath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2587 if (topath)
2588 bcopy(tond.ni_cnd.cn_pnbuf, topath, tolen + 1);
2589
2590 /*
2591 * nameidone has to happen before we vnode_put(tdvp)
2592 * since it may need to release the fs_nodelock on the tdvp
2593 */
2594 nameidone(&tond);
2595
2596 if (tvp)
2597 vnode_put(tvp);
2598 vnode_put(tdvp);
2599
2600 /* make a copy of from path to pass to nfs_namei() again */
2601 MALLOC_ZONE(frompath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2602 if (frompath)
2603 bcopy(fromnd.ni_cnd.cn_pnbuf, frompath, fromlen + 1);
2604
2605 /*
2606 * nameidone has to happen before we vnode_put(fdvp)
2607 * since it may need to release the fs_nodelock on the fdvp
2608 */
2609 nameidone(&fromnd);
2610
2611 vnode_put(fvp);
2612 vnode_put(fdvp);
2613
2614 if (fdirp) {
2615 vnode_put(fdirp);
2616 fdirp = NULL;
2617 }
2618 if (tdirp) {
2619 vnode_put(tdirp);
2620 tdirp = NULL;
2621 }
2622 mount_lock_renames(locked_mp);
2623 holding_mntlock = 1;
2624
2625 fvp = tvp = NULL;
2626 fdvp = tdvp = NULL;
2627
2628 fdirfor_ret = tdirfor_ret = 1;
2629
2630 if (!topath || !frompath) {
2631 /* we couldn't allocate a path, so bail */
2632 error = ENOMEM;
2633 goto out;
2634 }
2635
2636 goto retry;
2637 }
2638 } else {
2639 /*
2640 * when we dropped the iocounts to take
2641 * the lock, we allowed the identity of
2642 * the various vnodes to change... if they did,
2643 * we may no longer be dealing with a rename
2644 * that reshapes the tree... once we're holding
2645 * the iocounts, the vnodes can't change type
2646 * so we're free to drop the lock at this point
2647 * and continue on
2648 */
2649 if (holding_mntlock) {
2650 mount_unlock_renames(locked_mp);
2651 mount_drop(locked_mp, 0);
2652 holding_mntlock = 0;
2653 }
2654 }
2655
2656 // save these off so we can later verify that fvp is the same
2657 char *oname;
2658 vnode_t oparent;
2659 oname = fvp->v_name;
2660 oparent = fvp->v_parent;
2661
2662 error = VNOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2663 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd, &context);
2664 /*
2665 * fix up name & parent pointers. note that we first
2666 * check that fvp has the same name/parent pointers it
2667 * had before the rename call... this is a 'weak' check
2668 * at best...
2669 */
2670 if (oname == fvp->v_name && oparent == fvp->v_parent) {
2671 int update_flags;
2672 update_flags = VNODE_UPDATE_NAME;
2673 if (fdvp != tdvp)
2674 update_flags |= VNODE_UPDATE_PARENT;
2675 vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
2676 }
2677 out:
2678 if (holding_mntlock) {
2679 mount_unlock_renames(locked_mp);
2680 mount_drop(locked_mp, 0);
2681 holding_mntlock = 0;
2682 }
2683 if (tdvp) {
2684 /*
2685 * nameidone has to happen before we vnode_put(tdvp)
2686 * since it may need to release the fs_nodelock on the tdvp
2687 */
2688 nameidone(&tond);
2689 if (tvp)
2690 vnode_put(tvp);
2691 vnode_put(tdvp);
2692
2693 tdvp = NULL;
2694 }
2695 if (fdvp) {
2696 /*
2697 * nameidone has to happen before we vnode_put(fdvp)
2698 * since it may need to release the fs_nodelock on the fdvp
2699 */
2700 nameidone(&fromnd);
2701
2702 if (fvp)
2703 vnode_put(fvp);
2704 vnode_put(fdvp);
2705
2706 fdvp = NULL;
2707 }
2708 if (fdirp) {
2709 nfsm_srv_vattr_init(&fdiraft, v3);
2710 fdiraft_ret = vnode_getattr(fdirp, &fdiraft, &context);
2711 vnode_put(fdirp);
2712 fdirp = NULL;
2713 }
2714 if (tdirp) {
2715 nfsm_srv_vattr_init(&tdiraft, v3);
2716 tdiraft_ret = vnode_getattr(tdirp, &tdiraft, &context);
2717 vnode_put(tdirp);
2718 tdirp = NULL;
2719 }
2720 nfsm_reply(2 * NFSX_WCCDATA(v3));
2721 if (v3) {
2722 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2723 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2724 }
2725 if (frompath)
2726 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2727 if (topath)
2728 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2729 if (saved_cred)
2730 kauth_cred_rele(saved_cred);
2731 return (0);
2732
2733 nfsmout:
2734 if (holding_mntlock) {
2735 mount_unlock_renames(locked_mp);
2736 mount_drop(locked_mp, 0);
2737 }
2738 if (tdvp) {
2739 /*
2740 * nameidone has to happen before we vnode_put(tdvp)
2741 * since it may need to release the fs_nodelock on the tdvp
2742 */
2743 nameidone(&tond);
2744
2745 if (tvp)
2746 vnode_put(tvp);
2747 vnode_put(tdvp);
2748 }
2749 if (fdvp) {
2750 /*
2751 * nameidone has to happen before we vnode_put(fdvp)
2752 * since it may need to release the fs_nodelock on the fdvp
2753 */
2754 nameidone(&fromnd);
2755
2756 if (fvp)
2757 vnode_put(fvp);
2758 vnode_put(fdvp);
2759 }
2760 if (fdirp)
2761 vnode_put(fdirp);
2762 if (tdirp)
2763 vnode_put(tdirp);
2764 if (frompath)
2765 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2766 if (topath)
2767 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2768 if (saved_cred)
2769 kauth_cred_rele(saved_cred);
2770 return (error);
2771 }
2772
2773 /*
2774 * nfs link service
2775 */
2776 int
2777 nfsrv_link(nfsd, slp, procp, mrq)
2778 struct nfsrv_descript *nfsd;
2779 struct nfssvc_sock *slp;
2780 proc_t procp;
2781 mbuf_t *mrq;
2782 {
2783 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2784 mbuf_t nam = nfsd->nd_nam;
2785 caddr_t dpos = nfsd->nd_dpos;
2786 struct nameidata nd;
2787 u_long *tl;
2788 long t1;
2789 caddr_t bpos;
2790 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2791 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2792 char *cp2;
2793 mbuf_t mb, mreq;
2794 vnode_t vp, xp, dvp, dirp = NULL;
2795 struct vnode_attr dirfor, diraft, at;
2796 struct nfs_filehandle nfh, dnfh;
2797 struct nfs_export *nx;
2798 struct nfs_export_options *nxo;
2799 struct vfs_context context;
2800
2801 vp = xp = dvp = NULL;
2802 nfsm_srvmtofh(&nfh);
2803 nfsm_srvmtofh(&dnfh);
2804 nfsm_srvnamesiz(len, v3);
2805 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
2806 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2807 nfsm_srvpostop_attr(getret, &at);
2808 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2809 return (0);
2810 }
2811 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
2812 vnode_put(vp);
2813 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2814 nfsm_srvpostop_attr(getret, &at);
2815 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2816 return (0);
2817 }
2818
2819 /* we're not allowed to link to directories... */
2820 if (vnode_vtype(vp) == VDIR) {
2821 error = EPERM; /* POSIX */
2822 goto out1;
2823 }
2824
2825 context.vc_proc = procp;
2826 context.vc_ucred = nfsd->nd_cr;
2827
2828 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2829 if ((error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LINKTARGET, &context, nxo, 0)) != 0)
2830 goto out1;
2831
2832 nd.ni_cnd.cn_nameiop = CREATE;
2833 nd.ni_cnd.cn_flags = LOCKPARENT;
2834 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2835 if (!error)
2836 error = nfs_namei(nfsd, &context, &nd, &dnfh, nam, FALSE, &dirp, &nx, &nxo);
2837 if (dirp) {
2838 if (v3) {
2839 nfsm_srv_pre_vattr_init(&dirfor, v3);
2840 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2841 } else {
2842 vnode_put(dirp);
2843 dirp = NULL;
2844 }
2845 }
2846 if (error)
2847 goto out1;
2848 dvp = nd.ni_dvp;
2849 xp = nd.ni_vp;
2850
2851 if (xp != NULL)
2852 error = EEXIST;
2853 else if (vnode_mount(vp) != vnode_mount(dvp))
2854 error = EXDEV;
2855 else
2856 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2857
2858 if (!error)
2859 error = VNOP_LINK(vp, dvp, &nd.ni_cnd, &context);
2860
2861 /*
2862 * nameidone has to happen before we vnode_put(dvp)
2863 * since it may need to release the fs_nodelock on the dvp
2864 */
2865 nameidone(&nd);
2866
2867 if (xp)
2868 vnode_put(xp);
2869 vnode_put(dvp);
2870 out1:
2871 if (v3) {
2872 nfsm_srv_vattr_init(&at, v3);
2873 getret = vnode_getattr(vp, &at, &context);
2874 }
2875 if (dirp) {
2876 nfsm_srv_vattr_init(&diraft, v3);
2877 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2878 vnode_put(dirp);
2879 }
2880 vnode_put(vp);
2881
2882 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2883 if (v3) {
2884 nfsm_srvpostop_attr(getret, &at);
2885 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2886 return (0);
2887 }
2888 nfsmout:
2889 return (error);
2890 }
2891
2892 /*
2893 * nfs symbolic link service
2894 */
2895 int
2896 nfsrv_symlink(nfsd, slp, procp, mrq)
2897 struct nfsrv_descript *nfsd;
2898 struct nfssvc_sock *slp;
2899 proc_t procp;
2900 mbuf_t *mrq;
2901 {
2902 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2903 mbuf_t nam = nfsd->nd_nam;
2904 caddr_t dpos = nfsd->nd_dpos;
2905 struct vnode_attr dirfor, diraft, postat;
2906 struct nameidata nd;
2907 struct vnode_attr va;
2908 struct vnode_attr *vap = &va;
2909 u_long *tl;
2910 long t1;
2911 struct nfsv2_sattr *sp;
2912 char *bpos, *linkdata = NULL, *cp2;
2913 int error = 0, len, linkdatalen;
2914 int dirfor_ret = 1, diraft_ret = 1;
2915 int v3 = (nfsd->nd_flag & ND_NFSV3);
2916 mbuf_t mb, mreq, mb2;
2917 vnode_t vp, dvp, dirp = NULL;
2918 struct nfs_filehandle nfh;
2919 struct nfs_export *nx;
2920 struct nfs_export_options *nxo;
2921 uio_t auio;
2922 char uio_buf[ UIO_SIZEOF(1) ];
2923 struct vfs_context context;
2924 uid_t saved_uid;
2925
2926 context.vc_proc = procp;
2927 context.vc_ucred = nfsd->nd_cr;
2928
2929 /*
2930 * Save the original credential UID in case they are
2931 * mapped and we need to map the IDs in the attributes.
2932 */
2933 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
2934
2935 nd.ni_cnd.cn_nameiop = 0;
2936 vp = dvp = NULL;
2937 nfsm_srvmtofh(&nfh);
2938 nfsm_srvnamesiz(len, v3);
2939
2940 nd.ni_cnd.cn_nameiop = CREATE;
2941 nd.ni_cnd.cn_flags = LOCKPARENT;
2942 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2943 if (!error)
2944 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2945 if (dirp) {
2946 if (v3) {
2947 nfsm_srv_pre_vattr_init(&dirfor, v3);
2948 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2949 } else {
2950 vnode_put(dirp);
2951 dirp = NULL;
2952 }
2953 }
2954 if (error) {
2955 nd.ni_cnd.cn_nameiop = 0;
2956 goto out1;
2957 }
2958 dvp = nd.ni_dvp;
2959 vp = nd.ni_vp;
2960
2961 VATTR_INIT(vap);
2962 if (v3)
2963 nfsm_srvsattr(vap);
2964 nfsm_strsiz(linkdatalen, NFS_MAXPATHLEN, v3);
2965 MALLOC(linkdata, caddr_t, linkdatalen + 1, M_TEMP, M_WAITOK);
2966 if (!linkdata) {
2967 nameidone(&nd);
2968 nd.ni_cnd.cn_nameiop = 0;
2969 vnode_put(nd.ni_dvp);
2970 vnode_put(nd.ni_vp);
2971 error = ENOMEM;
2972 goto out;
2973 }
2974 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
2975 &uio_buf[0], sizeof(uio_buf));
2976 if (!auio) {
2977 nameidone(&nd);
2978 nd.ni_cnd.cn_nameiop = 0;
2979 vnode_put(nd.ni_dvp);
2980 vnode_put(nd.ni_vp);
2981 error = ENOMEM;
2982 goto out;
2983 }
2984 uio_addiov(auio, CAST_USER_ADDR_T(linkdata), linkdatalen);
2985 nfsm_mtouio(auio, linkdatalen);
2986 if (!v3) {
2987 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2988 VATTR_SET(vap, va_mode, fxdr_unsigned(u_short, sp->sa_mode));
2989 }
2990 *(linkdata + linkdatalen) = '\0';
2991 if (vp) {
2992 error = EEXIST;
2993 goto out;
2994 }
2995
2996 /*
2997 * If the credentials were mapped, we should
2998 * map the same values in the attributes.
2999 */
3000 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
3001 int ismember;
3002 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
3003 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3004 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3005 }
3006 VATTR_SET(vap, va_type, VLNK);
3007 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3008 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3009
3010 /* authorize before creating */
3011 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
3012
3013 /* validate given attributes */
3014 if (!error) {
3015 error = vnode_authattr_new(dvp, vap, 0, &context);
3016 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3017 /*
3018 * Most NFS servers just ignore the UID/GID attributes, so we
3019 * try ignoring them if that'll help the request succeed.
3020 */
3021 VATTR_CLEAR_ACTIVE(vap, va_uid);
3022 VATTR_CLEAR_ACTIVE(vap, va_gid);
3023 error = vnode_authattr_new(dvp, vap, 0, &context);
3024 }
3025 }
3026 if (!error)
3027 error = VNOP_SYMLINK(dvp, &vp, &nd.ni_cnd, vap, linkdata, &context);
3028
3029 if (!error && v3) {
3030 if (vp == NULL) {
3031 nd.ni_cnd.cn_nameiop = LOOKUP;
3032 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
3033 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
3034 nd.ni_cnd.cn_context = &context;
3035 nd.ni_startdir = dvp;
3036 nd.ni_usedvp = dvp;
3037 error = lookup(&nd);
3038 if (!error)
3039 vp = nd.ni_vp;
3040 }
3041 if (!error) {
3042 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3043 if (!error) {
3044 nfsm_srv_vattr_init(&postat, v3);
3045 error = vnode_getattr(vp, &postat, &context);
3046 }
3047 }
3048 }
3049 out:
3050 /*
3051 * nameidone has to happen before we vnode_put(dvp)
3052 * since it may need to release the fs_nodelock on the dvp
3053 */
3054 nameidone(&nd);
3055 nd.ni_cnd.cn_nameiop = 0;
3056
3057 if (vp)
3058 vnode_put(vp);
3059 vnode_put(dvp);
3060 out1:
3061 if (linkdata)
3062 FREE(linkdata, M_TEMP);
3063 if (dirp) {
3064 nfsm_srv_vattr_init(&diraft, v3);
3065 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3066 vnode_put(dirp);
3067 }
3068 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3069 if (v3) {
3070 if (!error) {
3071 nfsm_srvpostop_fh(&nfh);
3072 nfsm_srvpostop_attr(0, &postat);
3073 }
3074 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3075 }
3076 return (0);
3077 nfsmout:
3078 if (nd.ni_cnd.cn_nameiop) {
3079 /*
3080 * nameidone has to happen before we vnode_put(dvp)
3081 * since it may need to release the fs_nodelock on the dvp
3082 */
3083 nameidone(&nd);
3084
3085 if (vp)
3086 vnode_put(vp);
3087 vnode_put(dvp);
3088 }
3089 if (dirp)
3090 vnode_put(dirp);
3091 if (linkdata)
3092 FREE(linkdata, M_TEMP);
3093 return (error);
3094 }
3095
3096 /*
3097 * nfs mkdir service
3098 */
3099 int
3100 nfsrv_mkdir(nfsd, slp, procp, mrq)
3101 struct nfsrv_descript *nfsd;
3102 struct nfssvc_sock *slp;
3103 proc_t procp;
3104 mbuf_t *mrq;
3105 {
3106 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3107 mbuf_t nam = nfsd->nd_nam;
3108 caddr_t dpos = nfsd->nd_dpos;
3109 struct vnode_attr dirfor, diraft, postat;
3110 struct vnode_attr va;
3111 struct vnode_attr *vap = &va;
3112 struct nfs_fattr *fp;
3113 struct nameidata nd;
3114 caddr_t cp;
3115 u_long *tl;
3116 long t1;
3117 caddr_t bpos;
3118 int error = 0, len;
3119 int dirfor_ret = 1, diraft_ret = 1;
3120 int v3 = (nfsd->nd_flag & ND_NFSV3);
3121 char *cp2;
3122 mbuf_t mb, mb2, mreq;
3123 vnode_t vp, dvp, dirp = NULL;
3124 struct nfs_filehandle nfh;
3125 struct nfs_export *nx;
3126 struct nfs_export_options *nxo;
3127 struct vfs_context context;
3128 uid_t saved_uid;
3129 kauth_acl_t xacl = NULL;
3130
3131 context.vc_proc = procp;
3132 context.vc_ucred = nfsd->nd_cr;
3133
3134 /*
3135 * Save the original credential UID in case they are
3136 * mapped and we need to map the IDs in the attributes.
3137 */
3138 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
3139
3140 nd.ni_cnd.cn_nameiop = 0;
3141 vp = dvp = NULL;
3142 nfsm_srvmtofh(&nfh);
3143 nfsm_srvnamesiz(len, v3);
3144
3145 nd.ni_cnd.cn_nameiop = CREATE;
3146 nd.ni_cnd.cn_flags = LOCKPARENT;
3147 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3148 if (!error)
3149 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3150 if (dirp) {
3151 if (v3) {
3152 nfsm_srv_pre_vattr_init(&dirfor, v3);
3153 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3154 } else {
3155 vnode_put(dirp);
3156 dirp = NULL;
3157 }
3158 }
3159 if (error) {
3160 nd.ni_cnd.cn_nameiop = 0;
3161 nfsm_reply(NFSX_WCCDATA(v3));
3162 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3163 if (dirp)
3164 vnode_put(dirp);
3165 return (0);
3166 }
3167 dvp = nd.ni_dvp;
3168 vp = nd.ni_vp;
3169
3170 VATTR_INIT(vap);
3171 if (v3) {
3172 nfsm_srvsattr(vap);
3173 } else {
3174 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
3175 VATTR_SET(vap, va_mode, nfstov_mode(*tl++));
3176 }
3177 VATTR_SET(vap, va_type, VDIR);
3178
3179 if (vp != NULL) {
3180 /*
3181 * nameidone has to happen before we vnode_put(dvp)
3182 * since it may need to release the fs_nodelock on the dvp
3183 */
3184 nameidone(&nd);
3185
3186 vnode_put(dvp);
3187 vnode_put(vp);
3188 error = EEXIST;
3189 goto out;
3190 }
3191
3192 /*
3193 * If the credentials were mapped, we should
3194 * map the same values in the attributes.
3195 */
3196 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
3197 int ismember;
3198 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
3199 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3200 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3201 }
3202
3203 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, &context, nxo, 0);
3204
3205 /* construct ACL and handle inheritance */
3206 if (!error) {
3207 error = kauth_acl_inherit(dvp,
3208 NULL,
3209 &xacl, /* isdir */
3210 1,
3211 &context);
3212
3213 if (!error && xacl != NULL)
3214 VATTR_SET(vap, va_acl, xacl);
3215 }
3216 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3217 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3218
3219 /* validate new-file security information */
3220 if (!error) {
3221 error = vnode_authattr_new(dvp, vap, 0, &context);
3222 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3223 /*
3224 * Most NFS servers just ignore the UID/GID attributes, so we
3225 * try ignoring them if that'll help the request succeed.
3226 */
3227 VATTR_CLEAR_ACTIVE(vap, va_uid);
3228 VATTR_CLEAR_ACTIVE(vap, va_gid);
3229 error = vnode_authattr_new(dvp, vap, 0, &context);
3230 }
3231 }
3232
3233 if (!error)
3234 error = VNOP_MKDIR(dvp, &vp, &nd.ni_cnd, vap, &context);
3235
3236 if (!error && !VATTR_ALL_SUPPORTED(vap))
3237 /*
3238 * If some of the requested attributes weren't handled by the VNOP,
3239 * use our fallback code.
3240 */
3241 error = vnode_setattr_fallback(vp, vap, &context);
3242
3243 if (xacl != NULL)
3244 kauth_acl_free(xacl);
3245
3246 if (!error) {
3247 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3248 if (!error) {
3249 nfsm_srv_vattr_init(&postat, v3);
3250 error = vnode_getattr(vp, &postat, &context);
3251 }
3252 vnode_put(vp);
3253 vp = NULL;
3254 }
3255 /*
3256 * nameidone has to happen before we vnode_put(dvp)
3257 * since it may need to release the fs_nodelock on the dvp
3258 */
3259 nameidone(&nd);
3260
3261 vnode_put(dvp);
3262 out:
3263 nd.ni_cnd.cn_nameiop = 0;
3264
3265 if (dirp) {
3266 nfsm_srv_vattr_init(&diraft, v3);
3267 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3268 vnode_put(dirp);
3269 }
3270 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3271 if (v3) {
3272 if (!error) {
3273 nfsm_srvpostop_fh(&nfh);
3274 nfsm_srvpostop_attr(0, &postat);
3275 }
3276 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3277 } else {
3278 nfsm_srvfhtom(&nfh, v3);
3279 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
3280 nfsm_srvfillattr(&postat, fp);
3281 }
3282 return (0);
3283 nfsmout:
3284 if (nd.ni_cnd.cn_nameiop) {
3285 /*
3286 * nameidone has to happen before we vnode_put(dvp)
3287 * since it may need to release the fs_nodelock on the dvp
3288 */
3289 nameidone(&nd);
3290 vnode_put(dvp);
3291 if (vp)
3292 vnode_put(vp);
3293 }
3294 if (dirp)
3295 vnode_put(dirp);
3296 return (error);
3297 }
3298
3299 /*
3300 * nfs rmdir service
3301 */
3302 int
3303 nfsrv_rmdir(nfsd, slp, procp, mrq)
3304 struct nfsrv_descript *nfsd;
3305 struct nfssvc_sock *slp;
3306 proc_t procp;
3307 mbuf_t *mrq;
3308 {
3309 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3310 mbuf_t nam = nfsd->nd_nam;
3311 caddr_t dpos = nfsd->nd_dpos;
3312 u_long *tl;
3313 long t1;
3314 caddr_t bpos;
3315 int error = 0, len;
3316 int dirfor_ret = 1, diraft_ret = 1;
3317 int v3 = (nfsd->nd_flag & ND_NFSV3);
3318 char *cp2;
3319 mbuf_t mb, mreq;
3320 vnode_t vp, dvp, dirp = NULL;
3321 struct vnode_attr dirfor, diraft;
3322 struct nfs_filehandle nfh;
3323 struct nfs_export *nx;
3324 struct nfs_export_options *nxo;
3325 struct nameidata nd;
3326 struct vfs_context context;
3327
3328 context.vc_proc = procp;
3329 context.vc_ucred = nfsd->nd_cr;
3330
3331 vp = dvp = NULL;
3332 nfsm_srvmtofh(&nfh);
3333 nfsm_srvnamesiz(len, v3);
3334
3335 nd.ni_cnd.cn_nameiop = DELETE;
3336 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
3337 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3338 if (!error)
3339 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3340 if (dirp) {
3341 if (v3) {
3342 nfsm_srv_pre_vattr_init(&dirfor, v3);
3343 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3344 } else {
3345 vnode_put(dirp);
3346 dirp = NULL;
3347 }
3348 }
3349 if (error) {
3350 nfsm_reply(NFSX_WCCDATA(v3));
3351 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3352 if (dirp)
3353 vnode_put(dirp);
3354 return (0);
3355 }
3356 dvp = nd.ni_dvp;
3357 vp = nd.ni_vp;
3358
3359 if (vnode_vtype(vp) != VDIR) {
3360 error = ENOTDIR;
3361 goto out;
3362 }
3363 /*
3364 * No rmdir "." please.
3365 */
3366 if (dvp == vp) {
3367 error = EINVAL;
3368 goto out;
3369 }
3370 /*
3371 * The root of a mounted filesystem cannot be deleted.
3372 */
3373 if (vnode_isvroot(vp))
3374 error = EBUSY;
3375 if (!error)
3376 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
3377 if (!error)
3378 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, &context);
3379 out:
3380 /*
3381 * nameidone has to happen before we vnode_put(dvp)
3382 * since it may need to release the fs_nodelock on the dvp
3383 */
3384 nameidone(&nd);
3385
3386 vnode_put(dvp);
3387 vnode_put(vp);
3388
3389 if (dirp) {
3390 nfsm_srv_vattr_init(&diraft, v3);
3391 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3392 vnode_put(dirp);
3393 }
3394 nfsm_reply(NFSX_WCCDATA(v3));
3395 if (v3) {
3396 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3397 return (0);
3398 }
3399 nfsmout:
3400 return (error);
3401 }
3402
3403 /*
3404 * nfs readdir service
3405 * - mallocs what it thinks is enough to read
3406 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3407 * - calls VNOP_READDIR()
3408 * - loops around building the reply
3409 * if the output generated exceeds count break out of loop
3410 * The nfsm_clget macro is used here so that the reply will be packed
3411 * tightly in mbuf clusters.
3412 * - it only knows that it has encountered eof when the VNOP_READDIR()
3413 * reads nothing
3414 * - as such one readdir rpc will return eof false although you are there
3415 * and then the next will return eof
3416 * - it trims out records with d_fileno == 0
3417 * this doesn't matter for Unix clients, but they might confuse clients
3418 * for other os'.
3419 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3420 * than requested, but this may not apply to all filesystems. For
3421 * example, client NFS does not { although it is never remote mounted
3422 * anyhow }
3423 * The alternate call nfsrv_readdirplus() does lookups as well.
3424 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3425 * are supposed to cover. For readdir, the count is the total number of
3426 * bytes included in everything from the directory's postopattr through
3427 * the EOF flag. For readdirplus, the maxcount is the same, and the
3428 * dircount includes all that except for the entry attributes and handles.
3429 */
3430
3431 int
3432 nfsrv_readdir(nfsd, slp, procp, mrq)
3433 struct nfsrv_descript *nfsd;
3434 struct nfssvc_sock *slp;
3435 proc_t procp;
3436 mbuf_t *mrq;
3437 {
3438 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3439 mbuf_t nam = nfsd->nd_nam;
3440 caddr_t dpos = nfsd->nd_dpos;
3441 char *bp, *be;
3442 mbuf_t mp;
3443 struct direntry *dp;
3444 caddr_t cp;
3445 u_long *tl;
3446 long t1;
3447 caddr_t bpos;
3448 mbuf_t mb, mb2, mreq, mp2;
3449 char *cpos, *cend, *cp2, *rbuf;
3450 vnode_t vp;
3451 struct vnode_attr at;
3452 struct nfs_filehandle nfh;
3453 struct nfs_export *nx;
3454 struct nfs_export_options *nxo;
3455 uio_t auio;
3456 char uio_buf[ UIO_SIZEOF(1) ];
3457 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3458 int siz, count, fullsiz, eofflag, nentries = 0;
3459 int v3 = (nfsd->nd_flag & ND_NFSV3);
3460 u_quad_t off, toff, verf;
3461 nfsuint64 tquad;
3462 int vnopflag;
3463 struct vfs_context context;
3464
3465 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3466
3467 nfsm_srvmtofh(&nfh);
3468 if (v3) {
3469 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
3470 fxdr_hyper(tl, &toff);
3471 tl += 2;
3472 fxdr_hyper(tl, &verf);
3473 tl += 2;
3474 } else {
3475 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
3476 toff = fxdr_unsigned(u_quad_t, *tl++);
3477 }
3478 off = toff;
3479 count = fxdr_unsigned(int, *tl);
3480 siz = ((count + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3481 xfer = NFS_SRVMAXDATA(nfsd);
3482 if (siz > xfer)
3483 siz = xfer;
3484 fullsiz = siz;
3485 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
3486 nfsm_reply(NFSX_UNSIGNED);
3487 nfsm_srvpostop_attr(getret, &at);
3488 return (0);
3489 }
3490 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3491 vnode_put(vp);
3492 nfsm_reply(NFSX_UNSIGNED);
3493 nfsm_srvpostop_attr(getret, &at);
3494 return (0);
3495 }
3496 context.vc_proc = procp;
3497 context.vc_ucred = nfsd->nd_cr;
3498 if (!v3 || (nxo->nxo_flags & NX_32BITCLIENTS))
3499 vnopflag |= VNODE_READDIR_SEEKOFF32;
3500 if (v3) {
3501 nfsm_srv_vattr_init(&at, v3);
3502 error = getret = vnode_getattr(vp, &at, &context);
3503 if (!error && toff && verf && verf != at.va_filerev)
3504 error = NFSERR_BAD_COOKIE;
3505 }
3506 if (!error)
3507 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3508 if (error) {
3509 vnode_put(vp);
3510 nfsm_reply(NFSX_POSTOPATTR(v3));
3511 nfsm_srvpostop_attr(getret, &at);
3512 return (0);
3513 }
3514 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3515 if (!rbuf) {
3516 error = ENOMEM;
3517 vnode_put(vp);
3518 nfsm_reply(NFSX_POSTOPATTR(v3));
3519 nfsm_srvpostop_attr(getret, &at);
3520 return (0);
3521 }
3522 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3523 &uio_buf[0], sizeof(uio_buf));
3524 if (!auio) {
3525 error = ENOMEM;
3526 FREE(rbuf, M_TEMP);
3527 vnode_put(vp);
3528 nfsm_reply(NFSX_POSTOPATTR(v3));
3529 nfsm_srvpostop_attr(getret, &at);
3530 return (0);
3531 }
3532 again:
3533 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3534 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3535
3536 eofflag = 0;
3537 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3538 off = uio_offset(auio);
3539
3540 if (v3) {
3541 nfsm_srv_vattr_init(&at, v3);
3542 getret = vnode_getattr(vp, &at, &context);
3543 if (!error)
3544 error = getret;
3545 }
3546 if (error) {
3547 vnode_put(vp);
3548 FREE(rbuf, M_TEMP);
3549 nfsm_reply(NFSX_POSTOPATTR(v3));
3550 nfsm_srvpostop_attr(getret, &at);
3551 return (0);
3552 }
3553 if (uio_resid(auio) != 0) {
3554 // LP64todo - fix this
3555 siz -= uio_resid(auio);
3556
3557 /*
3558 * If nothing read, return eof
3559 * rpc reply
3560 */
3561 if (siz == 0) {
3562 vnode_put(vp);
3563 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
3564 2 * NFSX_UNSIGNED);
3565 if (v3) {
3566 nfsm_srvpostop_attr(getret, &at);
3567 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3568 txdr_hyper(&at.va_filerev, tl);
3569 tl += 2;
3570 } else
3571 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3572 *tl++ = nfs_false;
3573 *tl = nfs_true;
3574 FREE(rbuf, M_TEMP);
3575 return (0);
3576 }
3577 }
3578
3579 /*
3580 * Check for degenerate cases of nothing useful read.
3581 * If so go try again
3582 */
3583 cpos = rbuf;
3584 cend = rbuf + siz;
3585 dp = (struct direntry *)cpos;
3586 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3587 cpos += dp->d_reclen;
3588 dp = (struct direntry *)cpos;
3589 nentries--;
3590 }
3591 if (cpos >= cend || nentries == 0) {
3592 toff = off;
3593 siz = fullsiz;
3594 goto again;
3595 }
3596
3597 vnode_put(vp);
3598 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
3599 if (v3) {
3600 len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3601 nfsm_srvpostop_attr(getret, &at);
3602 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3603 txdr_hyper(&at.va_filerev, tl);
3604 } else
3605 len = 2 * NFSX_UNSIGNED;
3606 mp = mp2 = mb;
3607 bp = bpos;
3608 be = bp + mbuf_trailingspace(mp);
3609
3610 /* Loop through the records and build reply */
3611 while (cpos < cend && nentries > 0) {
3612 if (dp->d_fileno != 0) {
3613 nlen = dp->d_namlen;
3614 if (!v3 && (nlen > NFS_MAXNAMLEN))
3615 nlen = NFS_MAXNAMLEN;
3616 rem = nfsm_rndup(nlen)-nlen;
3617 len += (4 * NFSX_UNSIGNED + nlen + rem);
3618 if (v3)
3619 len += 2 * NFSX_UNSIGNED;
3620 if (len > count) {
3621 eofflag = 0;
3622 break;
3623 }
3624 /*
3625 * Build the directory record xdr from
3626 * the direntry entry.
3627 */
3628 nfsm_clget;
3629 *tl = nfs_true;
3630 bp += NFSX_UNSIGNED;
3631 nfsm_clget;
3632 if (v3) {
3633 txdr_hyper(&dp->d_fileno, &tquad);
3634 *tl = tquad.nfsuquad[0];
3635 bp += NFSX_UNSIGNED;
3636 nfsm_clget;
3637 *tl = tquad.nfsuquad[1];
3638 bp += NFSX_UNSIGNED;
3639 } else {
3640 *tl = txdr_unsigned(dp->d_fileno);
3641 bp += NFSX_UNSIGNED;
3642 }
3643 nfsm_clget;
3644 *tl = txdr_unsigned(nlen);
3645 bp += NFSX_UNSIGNED;
3646
3647 /* And loop around copying the name */
3648 xfer = nlen;
3649 cp = dp->d_name;
3650 while (xfer > 0) {
3651 nfsm_clget;
3652 if ((bp+xfer) > be)
3653 tsiz = be-bp;
3654 else
3655 tsiz = xfer;
3656 bcopy(cp, bp, tsiz);
3657 bp += tsiz;
3658 xfer -= tsiz;
3659 if (xfer > 0)
3660 cp += tsiz;
3661 }
3662 /* And null pad to a long boundary */
3663 for (i = 0; i < rem; i++)
3664 *bp++ = '\0';
3665
3666 /* Finish off the record with the cookie */
3667 nfsm_clget;
3668 if (v3) {
3669 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3670 dp->d_seekoff &= 0x00000000ffffffffULL;
3671 txdr_hyper(&dp->d_seekoff, &tquad);
3672 *tl = tquad.nfsuquad[0];
3673 bp += NFSX_UNSIGNED;
3674 nfsm_clget;
3675 *tl = tquad.nfsuquad[1];
3676 bp += NFSX_UNSIGNED;
3677 } else {
3678 *tl = txdr_unsigned(dp->d_seekoff);
3679 bp += NFSX_UNSIGNED;
3680 }
3681 }
3682 cpos += dp->d_reclen;
3683 dp = (struct direntry *)cpos;
3684 nentries--;
3685 }
3686 nfsm_clget;
3687 *tl = nfs_false;
3688 bp += NFSX_UNSIGNED;
3689 nfsm_clget;
3690 if (eofflag)
3691 *tl = nfs_true;
3692 else
3693 *tl = nfs_false;
3694 bp += NFSX_UNSIGNED;
3695 if (mp != mb) {
3696 if (bp < be)
3697 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
3698 } else
3699 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
3700 FREE(rbuf, M_TEMP);
3701 nfsmout:
3702 return (error);
3703 }
3704
3705 struct flrep {
3706 nfsuint64 fl_off;
3707 u_long fl_postopok;
3708 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
3709 u_long fl_fhok;
3710 u_long fl_fhsize;
3711 u_long fl_nfh[NFSX_V3FHMAX / sizeof (u_long)];
3712 };
3713
3714 int
3715 nfsrv_readdirplus(nfsd, slp, procp, mrq)
3716 struct nfsrv_descript *nfsd;
3717 struct nfssvc_sock *slp;
3718 proc_t procp;
3719 mbuf_t *mrq;
3720 {
3721 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3722 mbuf_t nam = nfsd->nd_nam;
3723 caddr_t dpos = nfsd->nd_dpos;
3724 char *bp, *be;
3725 mbuf_t mp;
3726 struct direntry *dp;
3727 caddr_t cp;
3728 u_long *tl;
3729 long t1;
3730 caddr_t bpos;
3731 mbuf_t mb, mb2, mreq, mp2;
3732 char *cpos, *cend, *cp2, *rbuf;
3733 vnode_t vp, nvp;
3734 struct flrep fl;
3735 struct nfs_filehandle dnfh, *nfhp = (struct nfs_filehandle *)&fl.fl_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 fl.fl_fhsize = txdr_unsigned(nfhp->nfh_len);
3948 fl.fl_fhok = nfs_true;
3949 fl.fl_postopok = nfs_true;
3950 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3951 dp->d_seekoff &= 0x00000000ffffffffULL;
3952 txdr_hyper(&dp->d_seekoff, &fl.fl_off);
3953
3954 nfsm_clget;
3955 *tl = nfs_true;
3956 bp += NFSX_UNSIGNED;
3957
3958 nfsm_clget;
3959 txdr_hyper(&dp->d_fileno, &tquad);
3960 *tl = tquad.nfsuquad[0];
3961 bp += NFSX_UNSIGNED;
3962 nfsm_clget;
3963 *tl = tquad.nfsuquad[1];
3964 bp += NFSX_UNSIGNED;
3965
3966 nfsm_clget;
3967 *tl = txdr_unsigned(nlen);
3968 bp += NFSX_UNSIGNED;
3969
3970 /* And loop around copying the name */
3971 xfer = nlen;
3972 cp = dp->d_name;
3973 while (xfer > 0) {
3974 nfsm_clget;
3975 if ((bp + xfer) > be)
3976 tsiz = be - bp;
3977 else
3978 tsiz = xfer;
3979 bcopy(cp, bp, tsiz);
3980 bp += tsiz;
3981 xfer -= tsiz;
3982 if (xfer > 0)
3983 cp += tsiz;
3984 }
3985 /* And null pad to a long boundary */
3986 for (i = 0; i < rem; i++)
3987 *bp++ = '\0';
3988
3989 /*
3990 * Now copy the flrep structure out.
3991 */
3992 xfer = sizeof(struct flrep) - sizeof(fl.fl_nfh) + fl.fl_fhsize;
3993 cp = (caddr_t)&fl;
3994 while (xfer > 0) {
3995 nfsm_clget;
3996 if ((bp + xfer) > be)
3997 tsiz = be - bp;
3998 else
3999 tsiz = xfer;
4000 bcopy(cp, bp, tsiz);
4001 bp += tsiz;
4002 xfer -= tsiz;
4003 if (xfer > 0)
4004 cp += tsiz;
4005 }
4006 }
4007 invalid:
4008 cpos += dp->d_reclen;
4009 dp = (struct direntry *)cpos;
4010 nentries--;
4011 }
4012 vnode_put(vp);
4013 vp = NULL;
4014 nfsm_clget;
4015 *tl = nfs_false;
4016 bp += NFSX_UNSIGNED;
4017 nfsm_clget;
4018 if (eofflag)
4019 *tl = nfs_true;
4020 else
4021 *tl = nfs_false;
4022 bp += NFSX_UNSIGNED;
4023 if (mp != mb) {
4024 if (bp < be)
4025 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
4026 } else
4027 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
4028 FREE(rbuf, M_TEMP);
4029 nfsmout:
4030 if (vp)
4031 vnode_put(vp);
4032 return (error);
4033 }
4034
4035 /*
4036 * nfs commit service
4037 */
4038 int
4039 nfsrv_commit(nfsd, slp, procp, mrq)
4040 struct nfsrv_descript *nfsd;
4041 struct nfssvc_sock *slp;
4042 proc_t procp;
4043 mbuf_t *mrq;
4044 {
4045 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4046 mbuf_t nam = nfsd->nd_nam;
4047 caddr_t dpos = nfsd->nd_dpos;
4048 struct vnode_attr bfor, aft;
4049 vnode_t vp;
4050 struct nfs_filehandle nfh;
4051 struct nfs_export *nx;
4052 struct nfs_export_options *nxo;
4053 u_long *tl;
4054 long t1;
4055 caddr_t bpos;
4056 int error = 0, for_ret = 1, aft_ret = 1, count;
4057 char *cp2;
4058 mbuf_t mb, mb2, mreq;
4059 u_quad_t off;
4060 struct vfs_context context;
4061
4062 nfsm_srvmtofh(&nfh);
4063 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
4064
4065 /*
4066 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4067 * count parameters, so these arguments are useless (someday maybe).
4068 */
4069 fxdr_hyper(tl, &off);
4070 tl += 2;
4071 count = fxdr_unsigned(int, *tl);
4072 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4073 nfsm_reply(2 * NFSX_UNSIGNED);
4074 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4075 return (0);
4076 }
4077 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4078 vnode_put(vp);
4079 nfsm_reply(2 * NFSX_UNSIGNED);
4080 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4081 return (0);
4082 }
4083 context.vc_proc = procp;
4084 context.vc_ucred = nfsd->nd_cr;
4085
4086 nfsm_srv_pre_vattr_init(&bfor, 1);
4087 for_ret = vnode_getattr(vp, &bfor, &context);
4088 error = VNOP_FSYNC(vp, MNT_WAIT, &context);
4089 nfsm_srv_vattr_init(&aft, 1);
4090 aft_ret = vnode_getattr(vp, &aft, &context);
4091 vnode_put(vp);
4092 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
4093 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4094 if (!error) {
4095 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
4096 *tl++ = txdr_unsigned(boottime_sec());
4097 *tl = txdr_unsigned(0);
4098 } else
4099 return (0);
4100 nfsmout:
4101 return (error);
4102 }
4103
4104 /*
4105 * nfs statfs service
4106 */
4107 int
4108 nfsrv_statfs(nfsd, slp, procp, mrq)
4109 struct nfsrv_descript *nfsd;
4110 struct nfssvc_sock *slp;
4111 proc_t procp;
4112 mbuf_t *mrq;
4113 {
4114 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4115 mbuf_t nam = nfsd->nd_nam;
4116 caddr_t dpos = nfsd->nd_dpos;
4117 struct vfs_attr va;
4118 struct nfs_statfs *sfp;
4119 u_long *tl;
4120 long t1;
4121 caddr_t bpos;
4122 int error = 0, getret = 1;
4123 int v3 = (nfsd->nd_flag & ND_NFSV3);
4124 char *cp2;
4125 mbuf_t mb, mb2, mreq;
4126 vnode_t vp;
4127 struct vnode_attr at;
4128 struct nfs_filehandle nfh;
4129 struct nfs_export *nx;
4130 struct nfs_export_options *nxo;
4131 u_quad_t tval;
4132 off_t blksize;
4133 struct vfs_context context;
4134
4135 nfsm_srvmtofh(&nfh);
4136 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4137 nfsm_reply(NFSX_UNSIGNED);
4138 nfsm_srvpostop_attr(getret, &at);
4139 return (0);
4140 }
4141 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4142 vnode_put(vp);
4143 nfsm_reply(NFSX_UNSIGNED);
4144 nfsm_srvpostop_attr(getret, &at);
4145 return (0);
4146 }
4147 context.vc_proc = procp;
4148 context.vc_ucred = nfsd->nd_cr;
4149
4150 VFSATTR_INIT(&va);
4151 VFSATTR_WANTED(&va, f_blocks);
4152 VFSATTR_WANTED(&va, f_bavail);
4153 VFSATTR_WANTED(&va, f_files);
4154 VFSATTR_WANTED(&va, f_ffree);
4155 error = vfs_getattr(vnode_mount(vp), &va, &context);
4156 blksize = vnode_mount(vp)->mnt_vfsstat.f_bsize;
4157 nfsm_srv_vattr_init(&at, v3);
4158 getret = vnode_getattr(vp, &at, &context);
4159 vnode_put(vp);
4160 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
4161 if (v3)
4162 nfsm_srvpostop_attr(getret, &at);
4163 if (error)
4164 return (0);
4165 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
4166 if (v3) {
4167 tval = (u_quad_t)(va.f_blocks * blksize);
4168 txdr_hyper(&tval, &sfp->sf_tbytes);
4169 tval = (u_quad_t)(va.f_bfree * blksize);
4170 txdr_hyper(&tval, &sfp->sf_fbytes);
4171 tval = (u_quad_t)(va.f_bavail * blksize);
4172 txdr_hyper(&tval, &sfp->sf_abytes);
4173 txdr_hyper(&va.f_files, &sfp->sf_tfiles);
4174 txdr_hyper(&va.f_ffree, &sfp->sf_ffiles);
4175 txdr_hyper(&va.f_ffree, &sfp->sf_afiles);
4176 sfp->sf_invarsec = 0;
4177 } else {
4178 sfp->sf_tsize = txdr_unsigned(NFS_V2MAXDATA);
4179 sfp->sf_bsize = txdr_unsigned((unsigned)blksize);
4180 sfp->sf_blocks = txdr_unsigned((unsigned)va.f_blocks);
4181 sfp->sf_bfree = txdr_unsigned((unsigned)va.f_bfree);
4182 sfp->sf_bavail = txdr_unsigned((unsigned)va.f_bavail);
4183 }
4184 nfsmout:
4185 return (error);
4186 }
4187
4188 /*
4189 * nfs fsinfo service
4190 */
4191 int
4192 nfsrv_fsinfo(nfsd, slp, procp, mrq)
4193 struct nfsrv_descript *nfsd;
4194 struct nfssvc_sock *slp;
4195 proc_t procp;
4196 mbuf_t *mrq;
4197 {
4198 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4199 mbuf_t nam = nfsd->nd_nam;
4200 caddr_t dpos = nfsd->nd_dpos;
4201 u_long *tl;
4202 struct nfsv3_fsinfo *sip;
4203 long t1;
4204 caddr_t bpos;
4205 int error = 0, getret = 1, prefsize, maxsize;
4206 char *cp2;
4207 mbuf_t mb, mb2, mreq;
4208 vnode_t vp;
4209 struct vnode_attr at;
4210 struct nfs_filehandle nfh;
4211 struct nfs_export *nx;
4212 struct nfs_export_options *nxo;
4213 struct vfs_context context;
4214
4215 nfsm_srvmtofh(&nfh);
4216 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4217 nfsm_reply(NFSX_UNSIGNED);
4218 nfsm_srvpostop_attr(getret, &at);
4219 return (0);
4220 }
4221 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4222 vnode_put(vp);
4223 nfsm_reply(NFSX_UNSIGNED);
4224 nfsm_srvpostop_attr(getret, &at);
4225 return (0);
4226 }
4227 context.vc_proc = procp;
4228 context.vc_ucred = nfsd->nd_cr;
4229
4230 nfsm_srv_vattr_init(&at, 1);
4231 getret = vnode_getattr(vp, &at, &context);
4232 vnode_put(vp);
4233 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
4234 nfsm_srvpostop_attr(getret, &at);
4235 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
4236
4237 /*
4238 * XXX
4239 * There should be file system VFS OP(s) to get this information.
4240 * For now, assume our usual NFS defaults.
4241 */
4242 if (slp->ns_sotype == SOCK_DGRAM) {
4243 maxsize = NFS_MAXDGRAMDATA;
4244 prefsize = NFS_PREFDGRAMDATA;
4245 } else
4246 maxsize = prefsize = NFS_MAXDATA;
4247 sip->fs_rtmax = txdr_unsigned(maxsize);
4248 sip->fs_rtpref = txdr_unsigned(prefsize);
4249 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
4250 sip->fs_wtmax = txdr_unsigned(maxsize);
4251 sip->fs_wtpref = txdr_unsigned(prefsize);
4252 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
4253 sip->fs_dtpref = txdr_unsigned(prefsize);
4254 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
4255 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
4256 sip->fs_timedelta.nfsv3_sec = 0;
4257 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
4258 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
4259 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
4260 NFSV3FSINFO_CANSETTIME);
4261 nfsmout:
4262 return (error);
4263 }
4264
4265 /*
4266 * nfs pathconf service
4267 */
4268 int
4269 nfsrv_pathconf(nfsd, slp, procp, mrq)
4270 struct nfsrv_descript *nfsd;
4271 struct nfssvc_sock *slp;
4272 proc_t procp;
4273 mbuf_t *mrq;
4274 {
4275 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4276 mbuf_t nam = nfsd->nd_nam;
4277 caddr_t dpos = nfsd->nd_dpos;
4278 u_long *tl;
4279 struct nfsv3_pathconf *pc;
4280 long t1;
4281 caddr_t bpos;
4282 int error = 0, getret = 1, linkmax, namemax;
4283 int chownres, notrunc, case_sensitive, case_preserving;
4284 char *cp2;
4285 mbuf_t mb, mb2, mreq;
4286 vnode_t vp;
4287 struct vnode_attr at;
4288 struct nfs_filehandle nfh;
4289 struct nfs_export *nx;
4290 struct nfs_export_options *nxo;
4291 struct vfs_context context;
4292
4293 nfsm_srvmtofh(&nfh);
4294 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4295 nfsm_reply(NFSX_UNSIGNED);
4296 nfsm_srvpostop_attr(getret, &at);
4297 return (0);
4298 }
4299 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4300 vnode_put(vp);
4301 nfsm_reply(NFSX_UNSIGNED);
4302 nfsm_srvpostop_attr(getret, &at);
4303 return (0);
4304 }
4305 context.vc_proc = procp;
4306 context.vc_ucred = nfsd->nd_cr;
4307
4308 error = VNOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax, &context);
4309 if (!error)
4310 error = VNOP_PATHCONF(vp, _PC_NAME_MAX, &namemax, &context);
4311 if (!error)
4312 error = VNOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres, &context);
4313 if (!error)
4314 error = VNOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc, &context);
4315 if (!error)
4316 error = VNOP_PATHCONF(vp, _PC_CASE_SENSITIVE, &case_sensitive, &context);
4317 if (!error)
4318 error = VNOP_PATHCONF(vp, _PC_CASE_PRESERVING, &case_preserving, &context);
4319 nfsm_srv_vattr_init(&at, 1);
4320 getret = vnode_getattr(vp, &at, &context);
4321 vnode_put(vp);
4322 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
4323 nfsm_srvpostop_attr(getret, &at);
4324 if (error)
4325 return (0);
4326 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
4327
4328 pc->pc_linkmax = txdr_unsigned(linkmax);
4329 pc->pc_namemax = txdr_unsigned(namemax);
4330 pc->pc_notrunc = txdr_unsigned(notrunc);
4331 pc->pc_chownrestricted = txdr_unsigned(chownres);
4332 pc->pc_caseinsensitive = txdr_unsigned(!case_sensitive);
4333 pc->pc_casepreserving = txdr_unsigned(case_preserving);
4334
4335 nfsmout:
4336 return (error);
4337 }
4338
4339 /*
4340 * Null operation, used by clients to ping server
4341 */
4342 /* ARGSUSED */
4343 int
4344 nfsrv_null(
4345 struct nfsrv_descript *nfsd,
4346 struct nfssvc_sock *slp,
4347 __unused proc_t procp,
4348 mbuf_t *mrq)
4349 {
4350 mbuf_t mrep = nfsd->nd_mrep;
4351 caddr_t bpos;
4352 int error = NFSERR_RETVOID;
4353 mbuf_t mb, mreq;
4354
4355 nfsm_reply(0);
4356 nfsmout:
4357 return (0);
4358 }
4359
4360 /*
4361 * No operation, used for obsolete procedures
4362 */
4363 /* ARGSUSED */
4364 int
4365 nfsrv_noop(
4366 struct nfsrv_descript *nfsd,
4367 struct nfssvc_sock *slp,
4368 __unused proc_t procp,
4369 mbuf_t *mrq)
4370 {
4371 mbuf_t mrep = nfsd->nd_mrep;
4372 caddr_t bpos;
4373 int error;
4374 mbuf_t mb, mreq;
4375
4376 if (nfsd->nd_repstat)
4377 error = nfsd->nd_repstat;
4378 else
4379 error = EPROCUNAVAIL;
4380 nfsm_reply(0);
4381 nfsmout:
4382 return (0);
4383 }
4384
4385 /*
4386 * Perform access checking for vnodes obtained from file handles that would
4387 * refer to files already opened by a Unix client. You cannot just use
4388 * vnode_authorize() for two reasons.
4389 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4390 * 2 - The owner is to be given access irrespective of mode bits so that
4391 * processes that chmod after opening a file don't break. I don't like
4392 * this because it opens a security hole, but since the nfs server opens
4393 * a security hole the size of a barn door anyhow, what the heck.
4394 *
4395 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4396 * will return EPERM instead of EACCESS. EPERM is always an error.
4397 */
4398
4399 static int
4400 nfsrv_authorize(
4401 vnode_t vp,
4402 vnode_t dvp,
4403 kauth_action_t action,
4404 vfs_context_t context,
4405 struct nfs_export_options *nxo,
4406 int override)
4407 {
4408 struct vnode_attr vattr;
4409 int error;
4410
4411 if (action & KAUTH_VNODE_WRITE_RIGHTS) {
4412 /*
4413 * Disallow write attempts on read-only exports;
4414 * unless the file is a socket or a block or character
4415 * device resident on the file system.
4416 */
4417 if (nxo->nxo_flags & NX_READONLY) {
4418 switch (vnode_vtype(vp)) {
4419 case VREG: case VDIR: case VLNK: case VCPLX:
4420 return (EROFS);
4421 default:
4422 break;
4423 }
4424 }
4425 }
4426 error = vnode_authorize(vp, dvp, action, context);
4427 /*
4428 * Allow certain operations for the owner (reads and writes
4429 * on files that are already open). Picking up from FreeBSD.
4430 */
4431 if (override && (error == EACCES)) {
4432 VATTR_INIT(&vattr);
4433 VATTR_WANTED(&vattr, va_uid);
4434 if ((vnode_getattr(vp, &vattr, context) == 0) &&
4435 (kauth_cred_getuid(vfs_context_ucred(context)) == vattr.va_uid))
4436 error = 0;
4437 }
4438 return error;
4439 }
4440 #endif /* NFS_NOSERVER */
4441