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