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