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