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