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