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