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