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