]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
ffad54c5e74e1f2f41b35d00b5e05a5aa995fe4f
[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 /* write verifier */
1169 *tl++ = txdr_unsigned(boottime_sec());
1170 *tl = txdr_unsigned(0);
1171 } else {
1172 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1173 nfsm_srvfillattr(vap, fp);
1174 }
1175 nfsmout:
1176 if (uio_bufp != NULL) {
1177 FREE(uio_bufp, M_TEMP);
1178 }
1179 return (error);
1180 }
1181
1182 /*
1183 * NFS write service with write gathering support. Called when
1184 * nfsrvw_procrastinate > 0.
1185 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1186 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1187 * Jan. 1994.
1188 */
1189 int
1190 nfsrv_writegather(ndp, slp, procp, mrq)
1191 struct nfsrv_descript **ndp;
1192 struct nfssvc_sock *slp;
1193 proc_t procp;
1194 mbuf_t *mrq;
1195 {
1196 mbuf_t mp;
1197 struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1198 struct nfs_export *nx;
1199 struct nfs_export_options *nxo;
1200 struct nfs_fattr *fp;
1201 int i;
1202 struct nfsrvw_delayhash *wpp;
1203 kauth_cred_t cred;
1204 struct vnode_attr va, forat;
1205 u_long *tl;
1206 long t1;
1207 caddr_t bpos, dpos, tpos;
1208 int error = 0, len, forat_ret = 1;
1209 int ioflags, aftat_ret = 1, adjust, v3, zeroing, tlen;
1210 char *cp2;
1211 mbuf_t mb, mb2, mreq, mrep, md;
1212 vnode_t vp;
1213 uio_t uiop = NULL;
1214 char *uio_bufp = NULL;
1215 u_quad_t cur_usec;
1216 struct timeval now;
1217 struct vfs_context context;
1218
1219 context.vc_proc = procp;
1220
1221 #ifndef nolint
1222 i = 0;
1223 len = 0;
1224 #endif
1225
1226 *mrq = NULL;
1227 if (*ndp) {
1228 nfsd = *ndp;
1229 *ndp = NULL;
1230 mrep = nfsd->nd_mrep;
1231 md = nfsd->nd_md;
1232 dpos = nfsd->nd_dpos;
1233 cred = nfsd->nd_cr;
1234 context.vc_ucred = cred;
1235 v3 = (nfsd->nd_flag & ND_NFSV3);
1236 LIST_INIT(&nfsd->nd_coalesce);
1237 nfsd->nd_mreq = NULL;
1238 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1239 microuptime(&now);
1240 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1241 nfsd->nd_time = cur_usec +
1242 (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
1243
1244 /*
1245 * Now, get the write header..
1246 */
1247 nfsm_srvmtofh(&nfsd->nd_fh);
1248 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1249 if (v3) {
1250 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
1251 fxdr_hyper(tl, &nfsd->nd_off);
1252 tl += 3;
1253 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1254 } else {
1255 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1256 nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
1257 tl += 2;
1258 if (nfs_async)
1259 nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1260 }
1261 len = fxdr_unsigned(long, *tl);
1262 nfsd->nd_len = len;
1263 nfsd->nd_eoff = nfsd->nd_off + len;
1264
1265 /*
1266 * Trim the header out of the mbuf list and trim off any trailing
1267 * junk so that the mbuf list has only the write data.
1268 */
1269 zeroing = 1;
1270 i = 0;
1271 mp = mrep;
1272 while (mp) {
1273 if (mp == md) {
1274 zeroing = 0;
1275 tpos = mbuf_data(mp);
1276 tlen = mbuf_len(mp);
1277 adjust = dpos - tpos;
1278 tlen -= adjust;
1279 mbuf_setlen(mp, tlen);
1280 if (tlen > 0 && adjust > 0) {
1281 tpos += adjust;
1282 if ((error = mbuf_setdata(mp, tpos, tlen)))
1283 goto nfsmout;
1284 }
1285 }
1286 if (zeroing)
1287 mbuf_setlen(mp, 0);
1288 else {
1289 tlen = mbuf_len(mp);
1290 i += tlen;
1291 if (i > len) {
1292 mbuf_setlen(mp, tlen - (i - len));
1293 zeroing = 1;
1294 }
1295 }
1296 mp = mbuf_next(mp);
1297 }
1298 if (len > NFS_MAXDATA || len < 0 || i < len) {
1299 nfsmout:
1300 mbuf_freem(mrep);
1301 mrep = NULL;
1302 error = EIO;
1303 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1304 if (v3)
1305 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1306 nfsd->nd_mreq = mreq;
1307 nfsd->nd_mrep = NULL;
1308 nfsd->nd_time = 1;
1309 }
1310
1311 /*
1312 * Add this entry to the hash and time queues.
1313 */
1314 lck_mtx_lock(&slp->ns_wgmutex);
1315 owp = NULL;
1316 wp = slp->ns_tq.lh_first;
1317 while (wp && wp->nd_time < nfsd->nd_time) {
1318 owp = wp;
1319 wp = wp->nd_tq.le_next;
1320 }
1321 if (owp) {
1322 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1323 } else {
1324 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1325 }
1326 if (nfsd->nd_mrep) {
1327 wpp = NWDELAYHASH(slp, nfsd->nd_fh.nfh_fid);
1328 owp = NULL;
1329 wp = wpp->lh_first;
1330 while (wp && !nfsrv_fhmatch(&nfsd->nd_fh, &wp->nd_fh)) {
1331 owp = wp;
1332 wp = wp->nd_hash.le_next;
1333 }
1334 while (wp && (wp->nd_off < nfsd->nd_off) &&
1335 nfsrv_fhmatch(&nfsd->nd_fh, &wp->nd_fh)) {
1336 owp = wp;
1337 wp = wp->nd_hash.le_next;
1338 }
1339 if (owp) {
1340 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1341
1342 /*
1343 * Search the hash list for overlapping entries and
1344 * coalesce.
1345 */
1346 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1347 wp = nfsd->nd_hash.le_next;
1348 if (NFSW_SAMECRED(owp, nfsd))
1349 nfsrvw_coalesce(owp, nfsd);
1350 }
1351 } else {
1352 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1353 }
1354 }
1355 } else {
1356 lck_mtx_lock(&slp->ns_wgmutex);
1357 }
1358
1359 /*
1360 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1361 * and generate the associated reply mbuf list(s).
1362 */
1363 loop1:
1364 microuptime(&now);
1365 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1366 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1367 owp = nfsd->nd_tq.le_next;
1368 if (nfsd->nd_time > cur_usec)
1369 break;
1370 if (nfsd->nd_mreq)
1371 continue;
1372 LIST_REMOVE(nfsd, nd_tq);
1373 LIST_REMOVE(nfsd, nd_hash);
1374 mrep = nfsd->nd_mrep;
1375 nfsd->nd_mrep = NULL;
1376 v3 = (nfsd->nd_flag & ND_NFSV3);
1377 forat_ret = aftat_ret = 1;
1378 error = nfsrv_fhtovp(&nfsd->nd_fh, nfsd->nd_nam, TRUE, &vp, &nx, &nxo);
1379 if (!error) {
1380 error = nfsrv_credcheck(nfsd, nx, nxo);
1381 if (error)
1382 vnode_put(vp);
1383 }
1384 cred = nfsd->nd_cr;
1385 context.vc_ucred = cred;
1386 if (!error) {
1387 if (v3) {
1388 nfsm_srv_pre_vattr_init(&forat, v3);
1389 forat_ret = vnode_getattr(vp, &forat, &context);
1390 }
1391 if (vnode_vtype(vp) != VREG) {
1392 if (v3)
1393 error = EINVAL;
1394 else
1395 error = (vnode_vtype(vp) == VDIR) ? EISDIR : EACCES;
1396 }
1397 } else
1398 vp = NULL;
1399 if (!error) {
1400 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA, &context, nxo, 1);
1401 }
1402
1403 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1404 ioflags = IO_NODELOCKED;
1405 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1406 ioflags = (IO_SYNC | IO_NODELOCKED);
1407 else
1408 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1409
1410 if (!error && ((nfsd->nd_eoff - nfsd->nd_off) > 0)) {
1411 mp = mrep;
1412 i = 0;
1413 while (mp) {
1414 if (mbuf_len(mp) > 0)
1415 i++;
1416 mp = mbuf_next(mp);
1417 }
1418
1419 MALLOC(uio_bufp, char *, UIO_SIZEOF(i), M_TEMP, M_WAITOK);
1420 if (uio_bufp)
1421 uiop = uio_createwithbuffer(i, nfsd->nd_off, UIO_SYSSPACE,
1422 UIO_WRITE, uio_bufp, UIO_SIZEOF(i));
1423 if (!uio_bufp || !uiop)
1424 error = ENOMEM;
1425 if (!error) {
1426 mp = mrep;
1427 while (mp) {
1428 if ((tlen = mbuf_len(mp)) > 0)
1429 uio_addiov(uiop, CAST_USER_ADDR_T((caddr_t)mbuf_data(mp)), tlen);
1430 mp = mbuf_next(mp);
1431 }
1432 error = VNOP_WRITE(vp, uiop, ioflags, &context);
1433 OSAddAtomic(1, (SInt32*)&nfsstats.srvvop_writes);
1434 }
1435 if (uio_bufp) {
1436 FREE(uio_bufp, M_TEMP);
1437 uio_bufp = NULL;
1438 }
1439 }
1440 mbuf_freem(mrep);
1441 mrep = NULL;
1442 if (vp) {
1443 nfsm_srv_pre_vattr_init(&va, v3);
1444 aftat_ret = vnode_getattr(vp, &va, &context);
1445 vnode_put(vp);
1446 }
1447
1448 /*
1449 * Loop around generating replies for all write rpcs that have
1450 * now been completed.
1451 */
1452 swp = nfsd;
1453 do {
1454 if (error) {
1455 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1456 if (v3) {
1457 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1458 }
1459 } else {
1460 nfsm_writereply(NFSX_PREOPATTR(v3) +
1461 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1462 NFSX_WRITEVERF(v3), v3);
1463 if (v3) {
1464 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1465 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1466 *tl++ = txdr_unsigned(nfsd->nd_len);
1467 *tl++ = txdr_unsigned(swp->nd_stable);
1468 /* write verifier */
1469 *tl++ = txdr_unsigned(boottime_sec());
1470 *tl = txdr_unsigned(0);
1471 } else {
1472 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1473 nfsm_srvfillattr(&va, fp);
1474 }
1475 }
1476 nfsd->nd_mreq = mreq;
1477 if (nfsd->nd_mrep)
1478 panic("nfsrv_write: nd_mrep not free");
1479
1480 /*
1481 * Done. Put it at the head of the timer queue so that
1482 * the final phase can return the reply.
1483 */
1484 if (nfsd != swp) {
1485 nfsd->nd_time = 1;
1486 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1487 }
1488 nfsd = swp->nd_coalesce.lh_first;
1489 if (nfsd) {
1490 LIST_REMOVE(nfsd, nd_tq);
1491 }
1492 } while (nfsd);
1493 swp->nd_time = 1;
1494 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1495 goto loop1;
1496 }
1497
1498 /*
1499 * Search for a reply to return.
1500 */
1501 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1502 if (nfsd->nd_mreq) {
1503 LIST_REMOVE(nfsd, nd_tq);
1504 *mrq = nfsd->nd_mreq;
1505 *ndp = nfsd;
1506 break;
1507 }
1508 slp->ns_wgtime = slp->ns_tq.lh_first ? slp->ns_tq.lh_first->nd_time : 0;
1509 lck_mtx_unlock(&slp->ns_wgmutex);
1510 return (0);
1511 }
1512
1513 /*
1514 * Coalesce the write request nfsd into owp. To do this we must:
1515 * - remove nfsd from the queues
1516 * - merge nfsd->nd_mrep into owp->nd_mrep
1517 * - update the nd_eoff and nd_stable for owp
1518 * - put nfsd on owp's nd_coalesce list
1519 */
1520 static void
1521 nfsrvw_coalesce(
1522 struct nfsrv_descript *owp,
1523 struct nfsrv_descript *nfsd)
1524 {
1525 int overlap, error;
1526 mbuf_t mp, mpnext;
1527 struct nfsrv_descript *p;
1528
1529 LIST_REMOVE(nfsd, nd_hash);
1530 LIST_REMOVE(nfsd, nd_tq);
1531 if (owp->nd_eoff < nfsd->nd_eoff) {
1532 overlap = owp->nd_eoff - nfsd->nd_off;
1533 if (overlap < 0)
1534 panic("nfsrv_coalesce: bad off");
1535 if (overlap > 0)
1536 mbuf_adj(nfsd->nd_mrep, overlap);
1537 mp = owp->nd_mrep;
1538 while ((mpnext = mbuf_next(mp)))
1539 mp = mpnext;
1540 error = mbuf_setnext(mp, nfsd->nd_mrep);
1541 if (error)
1542 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error);
1543 owp->nd_eoff = nfsd->nd_eoff;
1544 } else {
1545 mbuf_freem(nfsd->nd_mrep);
1546 }
1547 nfsd->nd_mrep = NULL;
1548 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1549 owp->nd_stable = NFSV3WRITE_FILESYNC;
1550 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1551 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1552 owp->nd_stable = NFSV3WRITE_DATASYNC;
1553 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1554
1555 /*
1556 * If nfsd had anything else coalesced into it, transfer them
1557 * to owp, otherwise their replies will never get sent.
1558 */
1559 for (p = nfsd->nd_coalesce.lh_first; p;
1560 p = nfsd->nd_coalesce.lh_first) {
1561 LIST_REMOVE(p, nd_tq);
1562 LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1563 }
1564 }
1565
1566 /*
1567 * Sort the group list in increasing numerical order.
1568 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1569 * that used to be here.)
1570 *
1571 * XXX ILLEGAL
1572 */
1573 void
1574 nfsrvw_sort(list, num)
1575 gid_t *list;
1576 int num;
1577 {
1578 int i, j;
1579 gid_t v;
1580
1581 /* Insertion sort. */
1582 for (i = 1; i < num; i++) {
1583 v = list[i];
1584 /* find correct slot for value v, moving others up */
1585 for (j = i; --j >= 0 && v < list[j];)
1586 list[j + 1] = list[j];
1587 list[j + 1] = v;
1588 }
1589 }
1590
1591 /*
1592 * copy credentials making sure that the result can be compared with bcmp().
1593 *
1594 * XXX ILLEGAL
1595 */
1596 void
1597 nfsrv_setcred(kauth_cred_t incred, kauth_cred_t outcred)
1598 {
1599 int i;
1600
1601 bzero((caddr_t)outcred, sizeof (*outcred));
1602 outcred->cr_ref = 1;
1603 outcred->cr_uid = kauth_cred_getuid(incred);
1604 outcred->cr_ngroups = incred->cr_ngroups;
1605 for (i = 0; i < incred->cr_ngroups; i++)
1606 outcred->cr_groups[i] = incred->cr_groups[i];
1607 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1608 }
1609
1610 /*
1611 * nfs create service
1612 * now does a truncate to 0 length via. setattr if it already exists
1613 */
1614 int
1615 nfsrv_create(nfsd, slp, procp, mrq)
1616 struct nfsrv_descript *nfsd;
1617 struct nfssvc_sock *slp;
1618 proc_t procp;
1619 mbuf_t *mrq;
1620 {
1621 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
1622 mbuf_t nam = nfsd->nd_nam;
1623 caddr_t dpos = nfsd->nd_dpos;
1624 struct nfs_fattr *fp;
1625 struct vnode_attr dirfor, diraft, postat;
1626 struct vnode_attr va;
1627 struct vnode_attr *vap = &va;
1628 struct nfsv2_sattr *sp;
1629 u_long *tl;
1630 struct nameidata nd;
1631 caddr_t cp;
1632 long t1;
1633 caddr_t bpos;
1634 int error = 0, rdev, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1635 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1636 char *cp2;
1637 mbuf_t mb, mb2, mreq;
1638 vnode_t vp, dvp, dirp = NULL;
1639 struct nfs_filehandle nfh;
1640 struct nfs_export *nx;
1641 struct nfs_export_options *nxo;
1642 u_quad_t tempsize;
1643 u_char cverf[NFSX_V3CREATEVERF];
1644 struct vfs_context context;
1645 uid_t saved_uid;
1646
1647 context.vc_proc = procp;
1648 context.vc_ucred = nfsd->nd_cr;
1649
1650 /*
1651 * Save the original credential UID in case they are
1652 * mapped and we need to map the IDs in the attributes.
1653 */
1654 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
1655
1656 #ifndef nolint
1657 rdev = 0;
1658 #endif
1659 nd.ni_cnd.cn_nameiop = 0;
1660 vp = dvp = NULL;
1661 nfsm_srvmtofh(&nfh);
1662 nfsm_srvnamesiz(len, v3);
1663
1664 nd.ni_cnd.cn_nameiop = CREATE;
1665 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1666 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
1667 if (!error)
1668 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
1669 if (dirp) {
1670 if (v3) {
1671 nfsm_srv_pre_vattr_init(&dirfor, v3);
1672 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
1673 } else {
1674 vnode_put(dirp);
1675 dirp = NULL;
1676 }
1677 }
1678 if (error) {
1679 nd.ni_cnd.cn_nameiop = 0;
1680 nfsm_reply(NFSX_WCCDATA(v3));
1681 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1682 if (dirp)
1683 vnode_put(dirp);
1684 return (0);
1685 }
1686 dvp = nd.ni_dvp;
1687 vp = nd.ni_vp;
1688
1689 VATTR_INIT(vap);
1690
1691 if (v3) {
1692 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1693 how = fxdr_unsigned(int, *tl);
1694 switch (how) {
1695 case NFSV3CREATE_GUARDED:
1696 if (vp) {
1697 error = EEXIST;
1698 break;
1699 }
1700 case NFSV3CREATE_UNCHECKED:
1701 nfsm_srvsattr(vap);
1702 break;
1703 case NFSV3CREATE_EXCLUSIVE:
1704 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1705 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1706 exclusive_flag = 1;
1707 if (vp == NULL)
1708 VATTR_SET(vap, va_mode, 0);
1709 break;
1710 };
1711 VATTR_SET(vap, va_type, VREG);
1712 } else {
1713 enum vtype v_type;
1714
1715 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1716 v_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1717 if (v_type == VNON)
1718 v_type = VREG;
1719 VATTR_SET(vap, va_type, v_type);
1720 VATTR_SET(vap, va_mode, nfstov_mode(sp->sa_mode));
1721
1722 switch (v_type) {
1723 case VREG:
1724 tsize = fxdr_unsigned(long, sp->sa_size);
1725 if (tsize != -1)
1726 VATTR_SET(vap, va_data_size, (u_quad_t)tsize);
1727 break;
1728 case VCHR:
1729 case VBLK:
1730 case VFIFO:
1731 rdev = fxdr_unsigned(long, sp->sa_size);
1732 break;
1733 default:
1734 break;
1735 };
1736 }
1737
1738 /*
1739 * If it doesn't exist, create it
1740 * otherwise just truncate to 0 length
1741 * should I set the mode too ??
1742 */
1743 if (vp == NULL) {
1744 kauth_acl_t xacl = NULL;
1745
1746 /*
1747 * If the credentials were mapped, we should
1748 * map the same values in the attributes.
1749 */
1750 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
1751 int ismember;
1752 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
1753 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
1754 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
1755 }
1756
1757 /* authorize before creating */
1758 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
1759
1760 /* construct ACL and handle inheritance */
1761 if (!error) {
1762 error = kauth_acl_inherit(dvp,
1763 NULL,
1764 &xacl,
1765 0 /* !isdir */,
1766 &context);
1767
1768 if (!error && xacl != NULL)
1769 VATTR_SET(vap, va_acl, xacl);
1770 }
1771 VATTR_CLEAR_ACTIVE(vap, va_data_size);
1772 VATTR_CLEAR_ACTIVE(vap, va_access_time);
1773
1774 /* validate new-file security information */
1775 if (!error) {
1776 error = vnode_authattr_new(dvp, vap, 0, &context);
1777 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
1778 /*
1779 * Most NFS servers just ignore the UID/GID attributes, so we
1780 * try ignoring them if that'll help the request succeed.
1781 */
1782 VATTR_CLEAR_ACTIVE(vap, va_uid);
1783 VATTR_CLEAR_ACTIVE(vap, va_gid);
1784 error = vnode_authattr_new(dvp, vap, 0, &context);
1785 }
1786 }
1787
1788 if (vap->va_type == VREG || vap->va_type == VSOCK) {
1789
1790 if (!error)
1791 error = VNOP_CREATE(dvp, &vp, &nd.ni_cnd, vap, &context);
1792
1793 if (!error && !VATTR_ALL_SUPPORTED(vap))
1794 /*
1795 * If some of the requested attributes weren't handled by the VNOP,
1796 * use our fallback code.
1797 */
1798 error = vnode_setattr_fallback(vp, vap, &context);
1799
1800 if (xacl != NULL)
1801 kauth_acl_free(xacl);
1802
1803 if (!error) {
1804 if (exclusive_flag) {
1805 exclusive_flag = 0;
1806 VATTR_INIT(vap);
1807 bcopy(cverf, (caddr_t)&vap->va_access_time,
1808 NFSX_V3CREATEVERF);
1809 VATTR_SET_ACTIVE(vap, va_access_time);
1810 // skip authorization, as this is an
1811 // NFS internal implementation detail.
1812 error = vnode_setattr(vp, vap, &context);
1813 }
1814 }
1815
1816 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1817 vap->va_type == VFIFO) {
1818 if (vap->va_type == VCHR && rdev == (int)0xffffffff)
1819 VATTR_SET(vap, va_type, VFIFO);
1820 if (vap->va_type != VFIFO &&
1821 (error = suser(nfsd->nd_cr, (u_short *)0))) {
1822 nfsm_reply(0);
1823 } else
1824 VATTR_SET(vap, va_rdev, (dev_t)rdev);
1825
1826 error = VNOP_MKNOD(dvp, &vp, &nd.ni_cnd, vap, &context);
1827
1828 if (xacl != NULL)
1829 kauth_acl_free(xacl);
1830
1831 if (error) {
1832 nfsm_reply(0);
1833 }
1834 if (vp) {
1835 vnode_recycle(vp);
1836 vnode_put(vp);
1837 vp = NULL;
1838 }
1839 nd.ni_cnd.cn_nameiop = LOOKUP;
1840 nd.ni_cnd.cn_flags &= ~LOCKPARENT;
1841 nd.ni_cnd.cn_context = &context;
1842 nd.ni_startdir = dvp;
1843 nd.ni_usedvp = dvp;
1844 error = lookup(&nd);
1845 if (!error) {
1846 if (nd.ni_cnd.cn_flags & ISSYMLINK)
1847 error = EINVAL;
1848 vp = nd.ni_vp;
1849 }
1850 if (error)
1851 nfsm_reply(0);
1852 } else {
1853 error = ENXIO;
1854 }
1855 /*
1856 * nameidone has to happen before we vnode_put(dvp)
1857 * since it may need to release the fs_nodelock on the dvp
1858 */
1859 nameidone(&nd);
1860 nd.ni_cnd.cn_nameiop = 0;
1861
1862 vnode_put(dvp);
1863 } else {
1864 /*
1865 * nameidone has to happen before we vnode_put(dvp)
1866 * since it may need to release the fs_nodelock on the dvp
1867 */
1868 nameidone(&nd);
1869 nd.ni_cnd.cn_nameiop = 0;
1870
1871 vnode_put(dvp);
1872
1873 if (!error && VATTR_IS_ACTIVE(vap, va_data_size)) {
1874 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA,
1875 &context, nxo, 0);
1876 if (!error) {
1877 tempsize = vap->va_data_size;
1878 VATTR_INIT(vap);
1879 VATTR_SET(vap, va_data_size, tempsize);
1880 error = vnode_setattr(vp, vap, &context);
1881 }
1882 }
1883 }
1884 if (!error) {
1885 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
1886 if (!error) {
1887 nfsm_srv_vattr_init(&postat, v3);
1888 error = vnode_getattr(vp, &postat, &context);
1889 }
1890 }
1891 if (vp)
1892 vnode_put(vp);
1893
1894 if (v3) {
1895 if (exclusive_flag && !error &&
1896 bcmp(cverf, (caddr_t)&postat.va_access_time, NFSX_V3CREATEVERF))
1897 error = EEXIST;
1898 nfsm_srv_vattr_init(&diraft, v3);
1899 diraft_ret = vnode_getattr(dirp, &diraft, &context);
1900 vnode_put(dirp);
1901 dirp = NULL;
1902 }
1903 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1904
1905 if (v3) {
1906 if (!error) {
1907 nfsm_srvpostop_fh(&nfh);
1908 nfsm_srvpostop_attr(0, &postat);
1909 }
1910 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1911 } else {
1912 nfsm_srvfhtom(&nfh, v3);
1913 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1914 nfsm_srvfillattr(&postat, fp);
1915 }
1916 return (0);
1917 nfsmout:
1918 if (nd.ni_cnd.cn_nameiop) {
1919 /*
1920 * nameidone has to happen before we vnode_put(dvp)
1921 * since it may need to release the fs_nodelock on the dvp
1922 */
1923 nameidone(&nd);
1924
1925 if (vp)
1926 vnode_put(vp);
1927 vnode_put(dvp);
1928 }
1929 if (dirp)
1930 vnode_put(dirp);
1931 return (error);
1932 }
1933
1934 /*
1935 * nfs v3 mknod service
1936 */
1937 int
1938 nfsrv_mknod(nfsd, slp, procp, mrq)
1939 struct nfsrv_descript *nfsd;
1940 struct nfssvc_sock *slp;
1941 proc_t procp;
1942 mbuf_t *mrq;
1943 {
1944 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
1945 mbuf_t nam = nfsd->nd_nam;
1946 caddr_t dpos = nfsd->nd_dpos;
1947 struct vnode_attr dirfor, diraft, postat;
1948 struct vnode_attr va;
1949 struct vnode_attr *vap = &va;
1950 u_long *tl;
1951 struct nameidata nd;
1952 long t1;
1953 caddr_t bpos;
1954 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1955 u_long major, minor;
1956 enum vtype vtyp;
1957 char *cp2;
1958 mbuf_t mb, mb2, mreq;
1959 vnode_t vp, dvp, dirp = NULL;
1960 struct nfs_filehandle nfh;
1961 struct nfs_export *nx;
1962 struct nfs_export_options *nxo;
1963 struct vfs_context hacked_context; /* XXX should we have this? */
1964 struct vfs_context context;
1965 uid_t saved_uid;
1966 kauth_acl_t xacl = NULL;
1967
1968 context.vc_proc = procp;
1969 context.vc_ucred = nfsd->nd_cr;
1970 hacked_context.vc_proc = procp;
1971 hacked_context.vc_ucred = proc_ucred(procp);
1972
1973 /*
1974 * Save the original credential UID in case they are
1975 * mapped and we need to map the IDs in the attributes.
1976 */
1977 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
1978
1979 vp = dvp = NULL;
1980 nd.ni_cnd.cn_nameiop = 0;
1981 nfsm_srvmtofh(&nfh);
1982 nfsm_srvnamesiz(len, 1);
1983
1984 nd.ni_cnd.cn_nameiop = CREATE;
1985 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1986 error = nfsm_path_mbuftond(&md, &dpos, 1, FALSE, &len, &nd);
1987 if (!error)
1988 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
1989 if (dirp) {
1990 nfsm_srv_pre_vattr_init(&dirfor, 1);
1991 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
1992 }
1993 if (error) {
1994 nd.ni_cnd.cn_nameiop = 0;
1995 nfsm_reply(NFSX_WCCDATA(1));
1996 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1997 if (dirp)
1998 vnode_put(dirp);
1999 return (0);
2000 }
2001 dvp = nd.ni_dvp;
2002 vp = nd.ni_vp;
2003
2004 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2005 vtyp = nfsv3tov_type(*tl);
2006 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
2007 error = NFSERR_BADTYPE;
2008 goto out;
2009 }
2010 VATTR_INIT(vap);
2011 nfsm_srvsattr(vap);
2012
2013 if (vtyp == VCHR || vtyp == VBLK) {
2014 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2015 major = fxdr_unsigned(u_long, *tl++);
2016 minor = fxdr_unsigned(u_long, *tl);
2017 VATTR_SET(vap, va_rdev, makedev(major, minor));
2018 }
2019
2020 /*
2021 * If it doesn't exist, create it.
2022 */
2023 if (vp) {
2024 error = EEXIST;
2025 goto out;
2026 }
2027 VATTR_SET(vap, va_type, vtyp);
2028
2029 /*
2030 * If the credentials were mapped, we should
2031 * map the same values in the attributes.
2032 */
2033 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
2034 int ismember;
2035 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
2036 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
2037 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
2038 }
2039
2040 /* authorize before creating */
2041 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2042
2043 /* construct ACL and handle inheritance */
2044 if (!error) {
2045 error = kauth_acl_inherit(dvp,
2046 NULL,
2047 &xacl,
2048 0 /* !isdir */,
2049 &context);
2050
2051 if (!error && xacl != NULL)
2052 VATTR_SET(vap, va_acl, xacl);
2053 }
2054 VATTR_CLEAR_ACTIVE(vap, va_data_size);
2055 VATTR_CLEAR_ACTIVE(vap, va_access_time);
2056
2057 /* validate new-file security information */
2058 if (!error) {
2059 error = vnode_authattr_new(dvp, vap, 0, &context);
2060 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
2061 /*
2062 * Most NFS servers just ignore the UID/GID attributes, so we
2063 * try ignoring them if that'll help the request succeed.
2064 */
2065 VATTR_CLEAR_ACTIVE(vap, va_uid);
2066 VATTR_CLEAR_ACTIVE(vap, va_gid);
2067 error = vnode_authattr_new(dvp, vap, 0, &context);
2068 }
2069 }
2070
2071 if (vtyp == VSOCK) {
2072 error = VNOP_CREATE(dvp, &vp, &nd.ni_cnd, vap, &context);
2073
2074 if (!error && !VATTR_ALL_SUPPORTED(vap))
2075 /*
2076 * If some of the requested attributes weren't handled by the VNOP,
2077 * use our fallback code.
2078 */
2079 error = vnode_setattr_fallback(vp, vap, &context);
2080 } else {
2081 if (vtyp != VFIFO && (error = suser(nfsd->nd_cr, (u_short *)0))) {
2082 goto out1;
2083 }
2084 if ((error = VNOP_MKNOD(dvp, &vp, &nd.ni_cnd, vap, &context))) {
2085 goto out1;
2086 }
2087 if (vp) {
2088 vnode_recycle(vp);
2089 vnode_put(vp);
2090 vp = NULL;
2091 }
2092 nd.ni_cnd.cn_nameiop = LOOKUP;
2093 nd.ni_cnd.cn_flags &= ~LOCKPARENT;
2094 nd.ni_cnd.cn_context = &hacked_context;
2095 nd.ni_startdir = dvp;
2096 nd.ni_usedvp = dvp;
2097 error = lookup(&nd);
2098 if (!error) {
2099 vp = nd.ni_vp;
2100 if (nd.ni_cnd.cn_flags & ISSYMLINK)
2101 error = EINVAL;
2102 }
2103 }
2104 out1:
2105 if (xacl != NULL)
2106 kauth_acl_free(xacl);
2107 out:
2108 /*
2109 * nameidone has to happen before we vnode_put(dvp)
2110 * since it may need to release the fs_nodelock on the dvp
2111 */
2112 nameidone(&nd);
2113 nd.ni_cnd.cn_nameiop = 0;
2114
2115 vnode_put(dvp);
2116
2117 if (!error) {
2118 error = nfsrv_vptofh(nx, 0, NULL, vp, &context, &nfh);
2119 if (!error) {
2120 nfsm_srv_vattr_init(&postat, 1);
2121 error = vnode_getattr(vp, &postat, &context);
2122 }
2123 }
2124 if (vp)
2125 vnode_put(vp);
2126
2127 nfsm_srv_vattr_init(&diraft, 1);
2128 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2129 vnode_put(dirp);
2130 dirp = NULL;
2131
2132 nfsm_reply(NFSX_SRVFH(1, &nfh) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2133 if (!error) {
2134 nfsm_srvpostop_fh(&nfh);
2135 nfsm_srvpostop_attr(0, &postat);
2136 }
2137 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2138 return (0);
2139 nfsmout:
2140 if (nd.ni_cnd.cn_nameiop) {
2141 /*
2142 * nameidone has to happen before we vnode_put(dvp)
2143 * since it may need to release the fs_nodelock on the dvp
2144 */
2145 nameidone(&nd);
2146
2147 if (vp)
2148 vnode_put(vp);
2149 vnode_put(dvp);
2150 }
2151 if (dirp)
2152 vnode_put(dirp);
2153 return (error);
2154 }
2155
2156 /*
2157 * nfs remove service
2158 */
2159 int
2160 nfsrv_remove(nfsd, slp, procp, mrq)
2161 struct nfsrv_descript *nfsd;
2162 struct nfssvc_sock *slp;
2163 proc_t procp;
2164 mbuf_t *mrq;
2165 {
2166 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2167 mbuf_t nam = nfsd->nd_nam;
2168 caddr_t dpos = nfsd->nd_dpos;
2169 struct nameidata nd;
2170 u_long *tl;
2171 long t1;
2172 caddr_t bpos;
2173 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2174 int v3 = (nfsd->nd_flag & ND_NFSV3);
2175 char *cp2;
2176 mbuf_t mb, mreq;
2177 vnode_t vp, dvp, dirp = NULL;
2178 struct vnode_attr dirfor, diraft;
2179 struct nfs_filehandle nfh;
2180 struct nfs_export *nx;
2181 struct nfs_export_options *nxo;
2182 struct vfs_context context;
2183
2184 context.vc_proc = procp;
2185 context.vc_ucred = nfsd->nd_cr;
2186
2187 dvp = vp = NULL;
2188 nfsm_srvmtofh(&nfh);
2189 nfsm_srvnamesiz(len, v3);
2190
2191 nd.ni_cnd.cn_nameiop = DELETE;
2192 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2193 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2194 if (!error)
2195 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2196 if (dirp) {
2197 if (v3) {
2198 nfsm_srv_pre_vattr_init(&dirfor, v3);
2199 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2200 } else {
2201 vnode_put(dirp);
2202 dirp = NULL;
2203 }
2204 }
2205 if (!error) {
2206 dvp = nd.ni_dvp;
2207 vp = nd.ni_vp;
2208
2209 if (vnode_vtype(vp) == VDIR)
2210 error = EPERM; /* POSIX */
2211 else if (vnode_isvroot(vp))
2212 /*
2213 * The root of a mounted filesystem cannot be deleted.
2214 */
2215 error = EBUSY;
2216 else
2217 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
2218
2219 if (!error)
2220 error = VNOP_REMOVE(dvp, vp, &nd.ni_cnd, 0, &context);
2221
2222 /*
2223 * nameidone has to happen before we vnode_put(dvp)
2224 * since it may need to release the fs_nodelock on the dvp
2225 */
2226 nameidone(&nd);
2227
2228 vnode_put(vp);
2229 vnode_put(dvp);
2230 }
2231 if (dirp) {
2232 nfsm_srv_vattr_init(&diraft, v3);
2233 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2234 vnode_put(dirp);
2235 }
2236 nfsm_reply(NFSX_WCCDATA(v3));
2237 if (v3) {
2238 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2239 return (0);
2240 }
2241 nfsmout:
2242 return (error);
2243 }
2244
2245 /*
2246 * nfs rename service
2247 */
2248 int
2249 nfsrv_rename(nfsd, slp, procp, mrq)
2250 struct nfsrv_descript *nfsd;
2251 struct nfssvc_sock *slp;
2252 proc_t procp;
2253 mbuf_t *mrq;
2254 {
2255 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2256 mbuf_t nam = nfsd->nd_nam;
2257 caddr_t dpos = nfsd->nd_dpos;
2258 kauth_cred_t saved_cred = NULL;
2259 u_long *tl;
2260 long t1;
2261 caddr_t bpos;
2262 int error = 0, fromlen, tolen;
2263 int fdirfor_ret = 1, fdiraft_ret = 1;
2264 int tdirfor_ret = 1, tdiraft_ret = 1;
2265 int v3 = (nfsd->nd_flag & ND_NFSV3);
2266 char *cp2, *frompath = NULL, *topath = NULL;
2267 mbuf_t mb, mreq;
2268 struct nameidata fromnd, tond;
2269 vnode_t fvp, tvp, tdvp, fdvp, fdirp = NULL;
2270 vnode_t tdirp = NULL;
2271 struct vnode_attr fdirfor, fdiraft, tdirfor, tdiraft;
2272 struct nfs_filehandle fnfh, tnfh;
2273 struct nfs_export *fnx, *tnx;
2274 struct nfs_export_options *fnxo, *tnxo;
2275 enum vtype fvtype, tvtype;
2276 int holding_mntlock;
2277 mount_t locked_mp;
2278 struct vfs_context context;
2279
2280 context.vc_proc = procp;
2281 context.vc_ucred = nfsd->nd_cr;
2282
2283 #ifndef nolint
2284 fvp = (vnode_t)0;
2285 #endif
2286
2287 /*
2288 * these need to be set before
2289 * calling any nfsm_xxxx macros
2290 * since they may take us out
2291 * through the error path
2292 */
2293 holding_mntlock = 0;
2294 fvp = tvp = NULL;
2295 fdvp = tdvp = NULL;
2296 locked_mp = NULL;
2297
2298 nfsm_srvmtofh(&fnfh);
2299 nfsm_srvnamesiz(fromlen, v3);
2300 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &fromlen, &fromnd);
2301 if (error) {
2302 nfsm_reply(0);
2303 return (0);
2304 }
2305 frompath = fromnd.ni_cnd.cn_pnbuf;
2306 nfsm_srvmtofh(&tnfh);
2307 nfsm_strsiz(tolen, NFS_MAXNAMLEN, v3);
2308 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &tolen, &tond);
2309 if (error) {
2310 nfsm_reply(0);
2311 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2312 return (0);
2313 }
2314 topath = tond.ni_cnd.cn_pnbuf;
2315
2316 /*
2317 * Remember our original uid so that we can reset cr_uid before
2318 * the second nfs_namei() call, in case it is remapped.
2319 */
2320 saved_cred = nfsd->nd_cr;
2321 kauth_cred_ref(saved_cred);
2322 retry:
2323 fromnd.ni_cnd.cn_nameiop = DELETE;
2324 fromnd.ni_cnd.cn_flags = WANTPARENT;
2325
2326 fromnd.ni_cnd.cn_pnbuf = frompath;
2327 frompath = NULL;
2328 fromnd.ni_cnd.cn_pnlen = MAXPATHLEN;
2329 fromnd.ni_cnd.cn_flags |= HASBUF;
2330
2331 error = nfs_namei(nfsd, &context, &fromnd, &fnfh, nam, FALSE, &fdirp, &fnx, &fnxo);
2332 if (error)
2333 goto out;
2334 fdvp = fromnd.ni_dvp;
2335 fvp = fromnd.ni_vp;
2336
2337 if (fdirp) {
2338 if (v3) {
2339 nfsm_srv_pre_vattr_init(&fdirfor, v3);
2340 fdirfor_ret = vnode_getattr(fdirp, &fdirfor, &context);
2341 } else {
2342 vnode_put(fdirp);
2343 fdirp = NULL;
2344 }
2345 }
2346 fvtype = vnode_vtype(fvp);
2347
2348 /* reset credential if it was remapped */
2349 if (nfsd->nd_cr != saved_cred) {
2350 kauth_cred_rele(nfsd->nd_cr);
2351 nfsd->nd_cr = saved_cred;
2352 kauth_cred_ref(nfsd->nd_cr);
2353 }
2354
2355 tond.ni_cnd.cn_nameiop = RENAME;
2356 tond.ni_cnd.cn_flags = WANTPARENT;
2357
2358 tond.ni_cnd.cn_pnbuf = topath;
2359 topath = NULL;
2360 tond.ni_cnd.cn_pnlen = MAXPATHLEN;
2361 tond.ni_cnd.cn_flags |= HASBUF;
2362
2363 if (fvtype == VDIR)
2364 tond.ni_cnd.cn_flags |= WILLBEDIR;
2365
2366 error = nfs_namei(nfsd, &context, &tond, &tnfh, nam, FALSE, &tdirp, &tnx, &tnxo);
2367 if (error) {
2368 /*
2369 * Translate error code for rename("dir1", "dir2/.").
2370 */
2371 if (error == EISDIR && fvtype == VDIR) {
2372 if (v3)
2373 error = EINVAL;
2374 else
2375 error = ENOTEMPTY;
2376 }
2377 goto out;
2378 }
2379 tdvp = tond.ni_dvp;
2380 tvp = tond.ni_vp;
2381
2382 if (tdirp) {
2383 if (v3) {
2384 nfsm_srv_pre_vattr_init(&tdirfor, v3);
2385 tdirfor_ret = vnode_getattr(tdirp, &tdirfor, &context);
2386 } else {
2387 vnode_put(tdirp);
2388 tdirp = NULL;
2389 }
2390 }
2391
2392 if (tvp != NULL) {
2393 tvtype = vnode_vtype(tvp);
2394
2395 if (fvtype == VDIR && tvtype != VDIR) {
2396 if (v3)
2397 error = EEXIST;
2398 else
2399 error = EISDIR;
2400 goto out;
2401 } else if (fvtype != VDIR && tvtype == VDIR) {
2402 if (v3)
2403 error = EEXIST;
2404 else
2405 error = ENOTDIR;
2406 goto out;
2407 }
2408 if (tvtype == VDIR && vnode_mountedhere(tvp)) {
2409 if (v3)
2410 error = EXDEV;
2411 else
2412 error = ENOTEMPTY;
2413 goto out;
2414 }
2415 }
2416 if (fvp == tdvp) {
2417 if (v3)
2418 error = EINVAL;
2419 else
2420 error = ENOTEMPTY;
2421 goto out;
2422 }
2423
2424 /*
2425 * Authorization.
2426 *
2427 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2428 * the node is moving between directories and we need rights to remove from the
2429 * old and add to the new.
2430 *
2431 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2432 *
2433 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2434 * implement the deferred-inherit bit.
2435 */
2436 {
2437 int moving = 0;
2438
2439 error = 0;
2440 if ((tvp != NULL) && vnode_isdir(tvp)) {
2441 if (tvp != fdvp)
2442 moving = 1;
2443 } else if (tdvp != fdvp) {
2444 moving = 1;
2445 }
2446 if (moving) {
2447 /* moving out of fdvp, must have delete rights */
2448 if ((error = nfsrv_authorize(fvp, fdvp, KAUTH_VNODE_DELETE, &context, fnxo, 0)) != 0)
2449 goto auth_exit;
2450 /* moving into tdvp or tvp, must have rights to add */
2451 if ((error = nfsrv_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
2452 NULL,
2453 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2454 &context, tnxo, 0)) != 0)
2455 goto auth_exit;
2456 } else {
2457 /* node staying in same directory, must be allowed to add new name */
2458 if ((error = nfsrv_authorize(fdvp, NULL,
2459 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
2460 &context, fnxo, 0)) != 0)
2461 goto auth_exit;
2462 }
2463 /* overwriting tvp */
2464 if ((tvp != NULL) && !vnode_isdir(tvp) &&
2465 ((error = nfsrv_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, &context, tnxo, 0)) != 0))
2466 goto auth_exit;
2467
2468 /* XXX more checks? */
2469
2470 auth_exit:
2471 /* authorization denied */
2472 if (error != 0)
2473 goto out;
2474 }
2475
2476 if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
2477 (tvp && (vnode_mount(fvp) != vnode_mount(tvp)))) {
2478 if (v3)
2479 error = EXDEV;
2480 else
2481 error = ENOTEMPTY;
2482 goto out;
2483 }
2484 /*
2485 * The following edge case is caught here:
2486 * (to cannot be a descendent of from)
2487 *
2488 * o fdvp
2489 * /
2490 * /
2491 * o fvp
2492 * \
2493 * \
2494 * o tdvp
2495 * /
2496 * /
2497 * o tvp
2498 */
2499 if (tdvp->v_parent == fvp) {
2500 if (v3)
2501 error = EXDEV;
2502 else
2503 error = ENOTEMPTY;
2504 goto out;
2505 }
2506 if (fvtype == VDIR && vnode_mountedhere(fvp)) {
2507 if (v3)
2508 error = EXDEV;
2509 else
2510 error = ENOTEMPTY;
2511 goto out;
2512 }
2513 /*
2514 * If source is the same as the destination (that is the
2515 * same vnode) then there is nothing to do...
2516 * EXCEPT if the underlying file system supports case
2517 * insensitivity and is case preserving. In this case
2518 * the file system needs to handle the special case of
2519 * getting the same vnode as target (fvp) and source (tvp).
2520 *
2521 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2522 * and _PC_CASE_PRESERVING can have this exception, and they need to
2523 * handle the special case of getting the same vnode as target and
2524 * source. NOTE: Then the target is unlocked going into vnop_rename,
2525 * so not to cause locking problems. There is a single reference on tvp.
2526 *
2527 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2528 * that correct behaviour then is just to remove the source (link)
2529 */
2530 if ((fvp == tvp) && (fdvp == tdvp)) {
2531 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2532 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2533 fromnd.ni_cnd.cn_namelen)) {
2534 goto out;
2535 }
2536 }
2537
2538 if (holding_mntlock && vnode_mount(fvp) != locked_mp) {
2539 /*
2540 * we're holding a reference and lock
2541 * on locked_mp, but it no longer matches
2542 * what we want to do... so drop our hold
2543 */
2544 mount_unlock_renames(locked_mp);
2545 mount_drop(locked_mp, 0);
2546 holding_mntlock = 0;
2547 }
2548 if (tdvp != fdvp && fvtype == VDIR) {
2549 /*
2550 * serialize renames that re-shape
2551 * the tree... if holding_mntlock is
2552 * set, then we're ready to go...
2553 * otherwise we
2554 * first need to drop the iocounts
2555 * we picked up, second take the
2556 * lock to serialize the access,
2557 * then finally start the lookup
2558 * process over with the lock held
2559 */
2560 if (!holding_mntlock) {
2561 /*
2562 * need to grab a reference on
2563 * the mount point before we
2564 * drop all the iocounts... once
2565 * the iocounts are gone, the mount
2566 * could follow
2567 */
2568 locked_mp = vnode_mount(fvp);
2569 mount_ref(locked_mp, 0);
2570
2571 /* make a copy of to path to pass to nfs_namei() again */
2572 MALLOC_ZONE(topath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2573 if (topath)
2574 bcopy(tond.ni_cnd.cn_pnbuf, topath, tolen + 1);
2575
2576 /*
2577 * nameidone has to happen before we vnode_put(tdvp)
2578 * since it may need to release the fs_nodelock on the tdvp
2579 */
2580 nameidone(&tond);
2581
2582 if (tvp)
2583 vnode_put(tvp);
2584 vnode_put(tdvp);
2585
2586 /* make a copy of from path to pass to nfs_namei() again */
2587 MALLOC_ZONE(frompath, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
2588 if (frompath)
2589 bcopy(fromnd.ni_cnd.cn_pnbuf, frompath, fromlen + 1);
2590
2591 /*
2592 * nameidone has to happen before we vnode_put(fdvp)
2593 * since it may need to release the fs_nodelock on the fdvp
2594 */
2595 nameidone(&fromnd);
2596
2597 vnode_put(fvp);
2598 vnode_put(fdvp);
2599
2600 if (fdirp) {
2601 vnode_put(fdirp);
2602 fdirp = NULL;
2603 }
2604 if (tdirp) {
2605 vnode_put(tdirp);
2606 tdirp = NULL;
2607 }
2608 mount_lock_renames(locked_mp);
2609 holding_mntlock = 1;
2610
2611 fvp = tvp = NULL;
2612 fdvp = tdvp = NULL;
2613
2614 fdirfor_ret = tdirfor_ret = 1;
2615
2616 if (!topath || !frompath) {
2617 /* we couldn't allocate a path, so bail */
2618 error = ENOMEM;
2619 goto out;
2620 }
2621
2622 goto retry;
2623 }
2624 } else {
2625 /*
2626 * when we dropped the iocounts to take
2627 * the lock, we allowed the identity of
2628 * the various vnodes to change... if they did,
2629 * we may no longer be dealing with a rename
2630 * that reshapes the tree... once we're holding
2631 * the iocounts, the vnodes can't change type
2632 * so we're free to drop the lock at this point
2633 * and continue on
2634 */
2635 if (holding_mntlock) {
2636 mount_unlock_renames(locked_mp);
2637 mount_drop(locked_mp, 0);
2638 holding_mntlock = 0;
2639 }
2640 }
2641
2642 // save these off so we can later verify that fvp is the same
2643 char *oname;
2644 vnode_t oparent;
2645 oname = fvp->v_name;
2646 oparent = fvp->v_parent;
2647
2648 error = VNOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2649 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd, &context);
2650 /*
2651 * fix up name & parent pointers. note that we first
2652 * check that fvp has the same name/parent pointers it
2653 * had before the rename call... this is a 'weak' check
2654 * at best...
2655 */
2656 if (oname == fvp->v_name && oparent == fvp->v_parent) {
2657 int update_flags;
2658 update_flags = VNODE_UPDATE_NAME;
2659 if (fdvp != tdvp)
2660 update_flags |= VNODE_UPDATE_PARENT;
2661 vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
2662 }
2663 out:
2664 if (holding_mntlock) {
2665 mount_unlock_renames(locked_mp);
2666 mount_drop(locked_mp, 0);
2667 holding_mntlock = 0;
2668 }
2669 if (tdvp) {
2670 /*
2671 * nameidone has to happen before we vnode_put(tdvp)
2672 * since it may need to release the fs_nodelock on the tdvp
2673 */
2674 nameidone(&tond);
2675 if (tvp)
2676 vnode_put(tvp);
2677 vnode_put(tdvp);
2678
2679 tdvp = NULL;
2680 }
2681 if (fdvp) {
2682 /*
2683 * nameidone has to happen before we vnode_put(fdvp)
2684 * since it may need to release the fs_nodelock on the fdvp
2685 */
2686 nameidone(&fromnd);
2687
2688 if (fvp)
2689 vnode_put(fvp);
2690 vnode_put(fdvp);
2691
2692 fdvp = NULL;
2693 }
2694 if (fdirp) {
2695 nfsm_srv_vattr_init(&fdiraft, v3);
2696 fdiraft_ret = vnode_getattr(fdirp, &fdiraft, &context);
2697 vnode_put(fdirp);
2698 fdirp = NULL;
2699 }
2700 if (tdirp) {
2701 nfsm_srv_vattr_init(&tdiraft, v3);
2702 tdiraft_ret = vnode_getattr(tdirp, &tdiraft, &context);
2703 vnode_put(tdirp);
2704 tdirp = NULL;
2705 }
2706 nfsm_reply(2 * NFSX_WCCDATA(v3));
2707 if (v3) {
2708 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2709 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2710 }
2711 if (frompath)
2712 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2713 if (topath)
2714 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2715 if (saved_cred)
2716 kauth_cred_rele(saved_cred);
2717 return (0);
2718
2719 nfsmout:
2720 if (holding_mntlock) {
2721 mount_unlock_renames(locked_mp);
2722 mount_drop(locked_mp, 0);
2723 }
2724 if (tdvp) {
2725 /*
2726 * nameidone has to happen before we vnode_put(tdvp)
2727 * since it may need to release the fs_nodelock on the tdvp
2728 */
2729 nameidone(&tond);
2730
2731 if (tvp)
2732 vnode_put(tvp);
2733 vnode_put(tdvp);
2734 }
2735 if (fdvp) {
2736 /*
2737 * nameidone has to happen before we vnode_put(fdvp)
2738 * since it may need to release the fs_nodelock on the fdvp
2739 */
2740 nameidone(&fromnd);
2741
2742 if (fvp)
2743 vnode_put(fvp);
2744 vnode_put(fdvp);
2745 }
2746 if (fdirp)
2747 vnode_put(fdirp);
2748 if (tdirp)
2749 vnode_put(tdirp);
2750 if (frompath)
2751 FREE_ZONE(frompath, MAXPATHLEN, M_NAMEI);
2752 if (topath)
2753 FREE_ZONE(topath, MAXPATHLEN, M_NAMEI);
2754 if (saved_cred)
2755 kauth_cred_rele(saved_cred);
2756 return (error);
2757 }
2758
2759 /*
2760 * nfs link service
2761 */
2762 int
2763 nfsrv_link(nfsd, slp, procp, mrq)
2764 struct nfsrv_descript *nfsd;
2765 struct nfssvc_sock *slp;
2766 proc_t procp;
2767 mbuf_t *mrq;
2768 {
2769 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2770 mbuf_t nam = nfsd->nd_nam;
2771 caddr_t dpos = nfsd->nd_dpos;
2772 struct nameidata nd;
2773 u_long *tl;
2774 long t1;
2775 caddr_t bpos;
2776 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2777 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2778 char *cp2;
2779 mbuf_t mb, mreq;
2780 vnode_t vp, xp, dvp, dirp = NULL;
2781 struct vnode_attr dirfor, diraft, at;
2782 struct nfs_filehandle nfh, dnfh;
2783 struct nfs_export *nx;
2784 struct nfs_export_options *nxo;
2785 struct vfs_context context;
2786
2787 vp = xp = dvp = NULL;
2788 nfsm_srvmtofh(&nfh);
2789 nfsm_srvmtofh(&dnfh);
2790 nfsm_srvnamesiz(len, v3);
2791 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
2792 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2793 nfsm_srvpostop_attr(getret, &at);
2794 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2795 return (0);
2796 }
2797 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
2798 vnode_put(vp);
2799 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2800 nfsm_srvpostop_attr(getret, &at);
2801 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2802 return (0);
2803 }
2804
2805 /* we're not allowed to link to directories... */
2806 if (vnode_vtype(vp) == VDIR) {
2807 error = EPERM; /* POSIX */
2808 goto out1;
2809 }
2810
2811 context.vc_proc = procp;
2812 context.vc_ucred = nfsd->nd_cr;
2813
2814 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2815 if ((error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LINKTARGET, &context, nxo, 0)) != 0)
2816 goto out1;
2817
2818 nd.ni_cnd.cn_nameiop = CREATE;
2819 nd.ni_cnd.cn_flags = LOCKPARENT;
2820 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2821 if (!error)
2822 error = nfs_namei(nfsd, &context, &nd, &dnfh, nam, FALSE, &dirp, &nx, &nxo);
2823 if (dirp) {
2824 if (v3) {
2825 nfsm_srv_pre_vattr_init(&dirfor, v3);
2826 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2827 } else {
2828 vnode_put(dirp);
2829 dirp = NULL;
2830 }
2831 }
2832 if (error)
2833 goto out1;
2834 dvp = nd.ni_dvp;
2835 xp = nd.ni_vp;
2836
2837 if (xp != NULL)
2838 error = EEXIST;
2839 else if (vnode_mount(vp) != vnode_mount(dvp))
2840 error = EXDEV;
2841 else
2842 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2843
2844 if (!error)
2845 error = VNOP_LINK(vp, dvp, &nd.ni_cnd, &context);
2846
2847 /*
2848 * nameidone has to happen before we vnode_put(dvp)
2849 * since it may need to release the fs_nodelock on the dvp
2850 */
2851 nameidone(&nd);
2852
2853 if (xp)
2854 vnode_put(xp);
2855 vnode_put(dvp);
2856 out1:
2857 if (v3) {
2858 nfsm_srv_vattr_init(&at, v3);
2859 getret = vnode_getattr(vp, &at, &context);
2860 }
2861 if (dirp) {
2862 nfsm_srv_vattr_init(&diraft, v3);
2863 diraft_ret = vnode_getattr(dirp, &diraft, &context);
2864 vnode_put(dirp);
2865 }
2866 vnode_put(vp);
2867
2868 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2869 if (v3) {
2870 nfsm_srvpostop_attr(getret, &at);
2871 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2872 return (0);
2873 }
2874 nfsmout:
2875 return (error);
2876 }
2877
2878 /*
2879 * nfs symbolic link service
2880 */
2881 int
2882 nfsrv_symlink(nfsd, slp, procp, mrq)
2883 struct nfsrv_descript *nfsd;
2884 struct nfssvc_sock *slp;
2885 proc_t procp;
2886 mbuf_t *mrq;
2887 {
2888 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
2889 mbuf_t nam = nfsd->nd_nam;
2890 caddr_t dpos = nfsd->nd_dpos;
2891 struct vnode_attr dirfor, diraft, postat;
2892 struct nameidata nd;
2893 struct vnode_attr va;
2894 struct vnode_attr *vap = &va;
2895 u_long *tl;
2896 long t1;
2897 struct nfsv2_sattr *sp;
2898 char *bpos, *linkdata = NULL, *cp2;
2899 int error = 0, len, linkdatalen;
2900 int dirfor_ret = 1, diraft_ret = 1;
2901 int v3 = (nfsd->nd_flag & ND_NFSV3);
2902 mbuf_t mb, mreq, mb2;
2903 vnode_t vp, dvp, dirp = NULL;
2904 struct nfs_filehandle nfh;
2905 struct nfs_export *nx;
2906 struct nfs_export_options *nxo;
2907 uio_t auio;
2908 char uio_buf[ UIO_SIZEOF(1) ];
2909 struct vfs_context context;
2910 uid_t saved_uid;
2911
2912 context.vc_proc = procp;
2913 context.vc_ucred = nfsd->nd_cr;
2914
2915 /*
2916 * Save the original credential UID in case they are
2917 * mapped and we need to map the IDs in the attributes.
2918 */
2919 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
2920
2921 nd.ni_cnd.cn_nameiop = 0;
2922 vp = dvp = NULL;
2923 nfsm_srvmtofh(&nfh);
2924 nfsm_srvnamesiz(len, v3);
2925
2926 nd.ni_cnd.cn_nameiop = CREATE;
2927 nd.ni_cnd.cn_flags = LOCKPARENT;
2928 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
2929 if (!error)
2930 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
2931 if (dirp) {
2932 if (v3) {
2933 nfsm_srv_pre_vattr_init(&dirfor, v3);
2934 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
2935 } else {
2936 vnode_put(dirp);
2937 dirp = NULL;
2938 }
2939 }
2940 if (error) {
2941 nd.ni_cnd.cn_nameiop = 0;
2942 goto out1;
2943 }
2944 dvp = nd.ni_dvp;
2945 vp = nd.ni_vp;
2946
2947 VATTR_INIT(vap);
2948 if (v3)
2949 nfsm_srvsattr(vap);
2950 nfsm_strsiz(linkdatalen, NFS_MAXPATHLEN, v3);
2951 MALLOC(linkdata, caddr_t, linkdatalen + 1, M_TEMP, M_WAITOK);
2952 if (!linkdata) {
2953 nameidone(&nd);
2954 nd.ni_cnd.cn_nameiop = 0;
2955 vnode_put(nd.ni_dvp);
2956 vnode_put(nd.ni_vp);
2957 error = ENOMEM;
2958 goto out;
2959 }
2960 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
2961 &uio_buf[0], sizeof(uio_buf));
2962 if (!auio) {
2963 nameidone(&nd);
2964 nd.ni_cnd.cn_nameiop = 0;
2965 vnode_put(nd.ni_dvp);
2966 vnode_put(nd.ni_vp);
2967 error = ENOMEM;
2968 goto out;
2969 }
2970 uio_addiov(auio, CAST_USER_ADDR_T(linkdata), linkdatalen);
2971 nfsm_mtouio(auio, linkdatalen);
2972 if (!v3) {
2973 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2974 VATTR_SET(vap, va_mode, fxdr_unsigned(u_short, sp->sa_mode));
2975 }
2976 *(linkdata + linkdatalen) = '\0';
2977 if (vp) {
2978 error = EEXIST;
2979 goto out;
2980 }
2981
2982 /*
2983 * If the credentials were mapped, we should
2984 * map the same values in the attributes.
2985 */
2986 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
2987 int ismember;
2988 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
2989 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
2990 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
2991 }
2992 VATTR_SET(vap, va_type, VLNK);
2993 VATTR_CLEAR_ACTIVE(vap, va_data_size);
2994 VATTR_CLEAR_ACTIVE(vap, va_access_time);
2995
2996 /* authorize before creating */
2997 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context, nxo, 0);
2998
2999 /* validate given attributes */
3000 if (!error) {
3001 error = vnode_authattr_new(dvp, vap, 0, &context);
3002 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3003 /*
3004 * Most NFS servers just ignore the UID/GID attributes, so we
3005 * try ignoring them if that'll help the request succeed.
3006 */
3007 VATTR_CLEAR_ACTIVE(vap, va_uid);
3008 VATTR_CLEAR_ACTIVE(vap, va_gid);
3009 error = vnode_authattr_new(dvp, vap, 0, &context);
3010 }
3011 }
3012 if (!error)
3013 error = VNOP_SYMLINK(dvp, &vp, &nd.ni_cnd, vap, linkdata, &context);
3014
3015 if (!error && v3) {
3016 if (vp == NULL) {
3017 nd.ni_cnd.cn_nameiop = LOOKUP;
3018 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
3019 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
3020 nd.ni_cnd.cn_context = &context;
3021 nd.ni_startdir = dvp;
3022 nd.ni_usedvp = dvp;
3023 error = lookup(&nd);
3024 if (!error)
3025 vp = nd.ni_vp;
3026 }
3027 if (!error) {
3028 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3029 if (!error) {
3030 nfsm_srv_vattr_init(&postat, v3);
3031 error = vnode_getattr(vp, &postat, &context);
3032 }
3033 }
3034 }
3035 out:
3036 /*
3037 * nameidone has to happen before we vnode_put(dvp)
3038 * since it may need to release the fs_nodelock on the dvp
3039 */
3040 nameidone(&nd);
3041 nd.ni_cnd.cn_nameiop = 0;
3042
3043 if (vp)
3044 vnode_put(vp);
3045 vnode_put(dvp);
3046 out1:
3047 if (linkdata)
3048 FREE(linkdata, M_TEMP);
3049 if (dirp) {
3050 nfsm_srv_vattr_init(&diraft, v3);
3051 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3052 vnode_put(dirp);
3053 }
3054 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3055 if (v3) {
3056 if (!error) {
3057 nfsm_srvpostop_fh(&nfh);
3058 nfsm_srvpostop_attr(0, &postat);
3059 }
3060 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3061 }
3062 return (0);
3063 nfsmout:
3064 if (nd.ni_cnd.cn_nameiop) {
3065 /*
3066 * nameidone has to happen before we vnode_put(dvp)
3067 * since it may need to release the fs_nodelock on the dvp
3068 */
3069 nameidone(&nd);
3070
3071 if (vp)
3072 vnode_put(vp);
3073 vnode_put(dvp);
3074 }
3075 if (dirp)
3076 vnode_put(dirp);
3077 if (linkdata)
3078 FREE(linkdata, M_TEMP);
3079 return (error);
3080 }
3081
3082 /*
3083 * nfs mkdir service
3084 */
3085 int
3086 nfsrv_mkdir(nfsd, slp, procp, mrq)
3087 struct nfsrv_descript *nfsd;
3088 struct nfssvc_sock *slp;
3089 proc_t procp;
3090 mbuf_t *mrq;
3091 {
3092 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3093 mbuf_t nam = nfsd->nd_nam;
3094 caddr_t dpos = nfsd->nd_dpos;
3095 struct vnode_attr dirfor, diraft, postat;
3096 struct vnode_attr va;
3097 struct vnode_attr *vap = &va;
3098 struct nfs_fattr *fp;
3099 struct nameidata nd;
3100 caddr_t cp;
3101 u_long *tl;
3102 long t1;
3103 caddr_t bpos;
3104 int error = 0, len;
3105 int dirfor_ret = 1, diraft_ret = 1;
3106 int v3 = (nfsd->nd_flag & ND_NFSV3);
3107 char *cp2;
3108 mbuf_t mb, mb2, mreq;
3109 vnode_t vp, dvp, dirp = NULL;
3110 struct nfs_filehandle nfh;
3111 struct nfs_export *nx;
3112 struct nfs_export_options *nxo;
3113 struct vfs_context context;
3114 uid_t saved_uid;
3115 kauth_acl_t xacl = NULL;
3116
3117 context.vc_proc = procp;
3118 context.vc_ucred = nfsd->nd_cr;
3119
3120 /*
3121 * Save the original credential UID in case they are
3122 * mapped and we need to map the IDs in the attributes.
3123 */
3124 saved_uid = kauth_cred_getuid(nfsd->nd_cr);
3125
3126 nd.ni_cnd.cn_nameiop = 0;
3127 vp = dvp = NULL;
3128 nfsm_srvmtofh(&nfh);
3129 nfsm_srvnamesiz(len, v3);
3130
3131 nd.ni_cnd.cn_nameiop = CREATE;
3132 nd.ni_cnd.cn_flags = LOCKPARENT;
3133 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3134 if (!error)
3135 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3136 if (dirp) {
3137 if (v3) {
3138 nfsm_srv_pre_vattr_init(&dirfor, v3);
3139 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3140 } else {
3141 vnode_put(dirp);
3142 dirp = NULL;
3143 }
3144 }
3145 if (error) {
3146 nd.ni_cnd.cn_nameiop = 0;
3147 nfsm_reply(NFSX_WCCDATA(v3));
3148 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3149 if (dirp)
3150 vnode_put(dirp);
3151 return (0);
3152 }
3153 dvp = nd.ni_dvp;
3154 vp = nd.ni_vp;
3155
3156 VATTR_INIT(vap);
3157 if (v3) {
3158 nfsm_srvsattr(vap);
3159 } else {
3160 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
3161 VATTR_SET(vap, va_mode, nfstov_mode(*tl++));
3162 }
3163 VATTR_SET(vap, va_type, VDIR);
3164
3165 if (vp != NULL) {
3166 /*
3167 * nameidone has to happen before we vnode_put(dvp)
3168 * since it may need to release the fs_nodelock on the dvp
3169 */
3170 nameidone(&nd);
3171
3172 vnode_put(dvp);
3173 vnode_put(vp);
3174 error = EEXIST;
3175 goto out;
3176 }
3177
3178 /*
3179 * If the credentials were mapped, we should
3180 * map the same values in the attributes.
3181 */
3182 if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nfsd->nd_cr) != saved_uid)) {
3183 int ismember;
3184 VATTR_SET(vap, va_uid, kauth_cred_getuid(nfsd->nd_cr));
3185 if (kauth_cred_ismember_gid(nfsd->nd_cr, vap->va_gid, &ismember) || !ismember)
3186 VATTR_SET(vap, va_gid, kauth_cred_getgid(nfsd->nd_cr));
3187 }
3188
3189 error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, &context, nxo, 0);
3190
3191 /* construct ACL and handle inheritance */
3192 if (!error) {
3193 error = kauth_acl_inherit(dvp,
3194 NULL,
3195 &xacl, /* isdir */
3196 1,
3197 &context);
3198
3199 if (!error && xacl != NULL)
3200 VATTR_SET(vap, va_acl, xacl);
3201 }
3202 VATTR_CLEAR_ACTIVE(vap, va_data_size);
3203 VATTR_CLEAR_ACTIVE(vap, va_access_time);
3204
3205 /* validate new-file security information */
3206 if (!error) {
3207 error = vnode_authattr_new(dvp, vap, 0, &context);
3208 if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
3209 /*
3210 * Most NFS servers just ignore the UID/GID attributes, so we
3211 * try ignoring them if that'll help the request succeed.
3212 */
3213 VATTR_CLEAR_ACTIVE(vap, va_uid);
3214 VATTR_CLEAR_ACTIVE(vap, va_gid);
3215 error = vnode_authattr_new(dvp, vap, 0, &context);
3216 }
3217 }
3218
3219 if (!error)
3220 error = VNOP_MKDIR(dvp, &vp, &nd.ni_cnd, vap, &context);
3221
3222 if (!error && !VATTR_ALL_SUPPORTED(vap))
3223 /*
3224 * If some of the requested attributes weren't handled by the VNOP,
3225 * use our fallback code.
3226 */
3227 error = vnode_setattr_fallback(vp, vap, &context);
3228
3229 if (xacl != NULL)
3230 kauth_acl_free(xacl);
3231
3232 if (!error) {
3233 error = nfsrv_vptofh(nx, !v3, NULL, vp, &context, &nfh);
3234 if (!error) {
3235 nfsm_srv_vattr_init(&postat, v3);
3236 error = vnode_getattr(vp, &postat, &context);
3237 }
3238 vnode_put(vp);
3239 vp = NULL;
3240 }
3241 /*
3242 * nameidone has to happen before we vnode_put(dvp)
3243 * since it may need to release the fs_nodelock on the dvp
3244 */
3245 nameidone(&nd);
3246
3247 vnode_put(dvp);
3248 out:
3249 nd.ni_cnd.cn_nameiop = 0;
3250
3251 if (dirp) {
3252 nfsm_srv_vattr_init(&diraft, v3);
3253 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3254 vnode_put(dirp);
3255 }
3256 nfsm_reply(NFSX_SRVFH(v3, &nfh) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
3257 if (v3) {
3258 if (!error) {
3259 nfsm_srvpostop_fh(&nfh);
3260 nfsm_srvpostop_attr(0, &postat);
3261 }
3262 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3263 } else {
3264 nfsm_srvfhtom(&nfh, v3);
3265 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
3266 nfsm_srvfillattr(&postat, fp);
3267 }
3268 return (0);
3269 nfsmout:
3270 if (nd.ni_cnd.cn_nameiop) {
3271 /*
3272 * nameidone has to happen before we vnode_put(dvp)
3273 * since it may need to release the fs_nodelock on the dvp
3274 */
3275 nameidone(&nd);
3276 vnode_put(dvp);
3277 if (vp)
3278 vnode_put(vp);
3279 }
3280 if (dirp)
3281 vnode_put(dirp);
3282 return (error);
3283 }
3284
3285 /*
3286 * nfs rmdir service
3287 */
3288 int
3289 nfsrv_rmdir(nfsd, slp, procp, mrq)
3290 struct nfsrv_descript *nfsd;
3291 struct nfssvc_sock *slp;
3292 proc_t procp;
3293 mbuf_t *mrq;
3294 {
3295 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3296 mbuf_t nam = nfsd->nd_nam;
3297 caddr_t dpos = nfsd->nd_dpos;
3298 u_long *tl;
3299 long t1;
3300 caddr_t bpos;
3301 int error = 0, len;
3302 int dirfor_ret = 1, diraft_ret = 1;
3303 int v3 = (nfsd->nd_flag & ND_NFSV3);
3304 char *cp2;
3305 mbuf_t mb, mreq;
3306 vnode_t vp, dvp, dirp = NULL;
3307 struct vnode_attr dirfor, diraft;
3308 struct nfs_filehandle nfh;
3309 struct nfs_export *nx;
3310 struct nfs_export_options *nxo;
3311 struct nameidata nd;
3312 struct vfs_context context;
3313
3314 context.vc_proc = procp;
3315 context.vc_ucred = nfsd->nd_cr;
3316
3317 vp = dvp = NULL;
3318 nfsm_srvmtofh(&nfh);
3319 nfsm_srvnamesiz(len, v3);
3320
3321 nd.ni_cnd.cn_nameiop = DELETE;
3322 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
3323 error = nfsm_path_mbuftond(&md, &dpos, v3, FALSE, &len, &nd);
3324 if (!error)
3325 error = nfs_namei(nfsd, &context, &nd, &nfh, nam, FALSE, &dirp, &nx, &nxo);
3326 if (dirp) {
3327 if (v3) {
3328 nfsm_srv_pre_vattr_init(&dirfor, v3);
3329 dirfor_ret = vnode_getattr(dirp, &dirfor, &context);
3330 } else {
3331 vnode_put(dirp);
3332 dirp = NULL;
3333 }
3334 }
3335 if (error) {
3336 nfsm_reply(NFSX_WCCDATA(v3));
3337 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3338 if (dirp)
3339 vnode_put(dirp);
3340 return (0);
3341 }
3342 dvp = nd.ni_dvp;
3343 vp = nd.ni_vp;
3344
3345 if (vnode_vtype(vp) != VDIR) {
3346 error = ENOTDIR;
3347 goto out;
3348 }
3349 /*
3350 * No rmdir "." please.
3351 */
3352 if (dvp == vp) {
3353 error = EINVAL;
3354 goto out;
3355 }
3356 /*
3357 * The root of a mounted filesystem cannot be deleted.
3358 */
3359 if (vnode_isvroot(vp))
3360 error = EBUSY;
3361 if (!error)
3362 error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, &context, nxo, 0);
3363 if (!error)
3364 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, &context);
3365 out:
3366 /*
3367 * nameidone has to happen before we vnode_put(dvp)
3368 * since it may need to release the fs_nodelock on the dvp
3369 */
3370 nameidone(&nd);
3371
3372 vnode_put(dvp);
3373 vnode_put(vp);
3374
3375 if (dirp) {
3376 nfsm_srv_vattr_init(&diraft, v3);
3377 diraft_ret = vnode_getattr(dirp, &diraft, &context);
3378 vnode_put(dirp);
3379 }
3380 nfsm_reply(NFSX_WCCDATA(v3));
3381 if (v3) {
3382 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
3383 return (0);
3384 }
3385 nfsmout:
3386 return (error);
3387 }
3388
3389 /*
3390 * nfs readdir service
3391 * - mallocs what it thinks is enough to read
3392 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3393 * - calls VNOP_READDIR()
3394 * - loops around building the reply
3395 * if the output generated exceeds count break out of loop
3396 * The nfsm_clget macro is used here so that the reply will be packed
3397 * tightly in mbuf clusters.
3398 * - it only knows that it has encountered eof when the VNOP_READDIR()
3399 * reads nothing
3400 * - as such one readdir rpc will return eof false although you are there
3401 * and then the next will return eof
3402 * - it trims out records with d_fileno == 0
3403 * this doesn't matter for Unix clients, but they might confuse clients
3404 * for other os'.
3405 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3406 * than requested, but this may not apply to all filesystems. For
3407 * example, client NFS does not { although it is never remote mounted
3408 * anyhow }
3409 * The alternate call nfsrv_readdirplus() does lookups as well.
3410 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3411 * are supposed to cover. For readdir, the count is the total number of
3412 * bytes included in everything from the directory's postopattr through
3413 * the EOF flag. For readdirplus, the maxcount is the same, and the
3414 * dircount includes all that except for the entry attributes and handles.
3415 */
3416
3417 int
3418 nfsrv_readdir(nfsd, slp, procp, mrq)
3419 struct nfsrv_descript *nfsd;
3420 struct nfssvc_sock *slp;
3421 proc_t procp;
3422 mbuf_t *mrq;
3423 {
3424 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3425 mbuf_t nam = nfsd->nd_nam;
3426 caddr_t dpos = nfsd->nd_dpos;
3427 char *bp, *be;
3428 mbuf_t mp;
3429 struct direntry *dp;
3430 caddr_t cp;
3431 u_long *tl;
3432 long t1;
3433 caddr_t bpos;
3434 mbuf_t mb, mb2, mreq, mp2;
3435 char *cpos, *cend, *cp2, *rbuf;
3436 vnode_t vp;
3437 struct vnode_attr at;
3438 struct nfs_filehandle nfh;
3439 struct nfs_export *nx;
3440 struct nfs_export_options *nxo;
3441 uio_t auio;
3442 char uio_buf[ UIO_SIZEOF(1) ];
3443 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3444 int siz, count, fullsiz, eofflag, nentries = 0;
3445 int v3 = (nfsd->nd_flag & ND_NFSV3);
3446 u_quad_t off, toff, verf;
3447 nfsuint64 tquad;
3448 int vnopflag;
3449 struct vfs_context context;
3450
3451 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3452
3453 nfsm_srvmtofh(&nfh);
3454 if (v3) {
3455 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
3456 fxdr_hyper(tl, &toff);
3457 tl += 2;
3458 fxdr_hyper(tl, &verf);
3459 tl += 2;
3460 } else {
3461 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
3462 toff = fxdr_unsigned(u_quad_t, *tl++);
3463 }
3464 off = toff;
3465 count = fxdr_unsigned(int, *tl);
3466 siz = ((count + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3467 xfer = NFS_SRVMAXDATA(nfsd);
3468 if (siz > xfer)
3469 siz = xfer;
3470 fullsiz = siz;
3471 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
3472 nfsm_reply(NFSX_UNSIGNED);
3473 nfsm_srvpostop_attr(getret, &at);
3474 return (0);
3475 }
3476 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3477 vnode_put(vp);
3478 nfsm_reply(NFSX_UNSIGNED);
3479 nfsm_srvpostop_attr(getret, &at);
3480 return (0);
3481 }
3482 context.vc_proc = procp;
3483 context.vc_ucred = nfsd->nd_cr;
3484 if (!v3 || (nxo->nxo_flags & NX_32BITCLIENTS))
3485 vnopflag |= VNODE_READDIR_SEEKOFF32;
3486 if (v3) {
3487 nfsm_srv_vattr_init(&at, v3);
3488 error = getret = vnode_getattr(vp, &at, &context);
3489 if (!error && toff && verf && verf != at.va_filerev)
3490 error = NFSERR_BAD_COOKIE;
3491 }
3492 if (!error)
3493 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3494 if (error) {
3495 vnode_put(vp);
3496 nfsm_reply(NFSX_POSTOPATTR(v3));
3497 nfsm_srvpostop_attr(getret, &at);
3498 return (0);
3499 }
3500 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3501 if (!rbuf) {
3502 error = ENOMEM;
3503 vnode_put(vp);
3504 nfsm_reply(NFSX_POSTOPATTR(v3));
3505 nfsm_srvpostop_attr(getret, &at);
3506 return (0);
3507 }
3508 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3509 &uio_buf[0], sizeof(uio_buf));
3510 if (!auio) {
3511 error = ENOMEM;
3512 FREE(rbuf, M_TEMP);
3513 vnode_put(vp);
3514 nfsm_reply(NFSX_POSTOPATTR(v3));
3515 nfsm_srvpostop_attr(getret, &at);
3516 return (0);
3517 }
3518 again:
3519 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3520 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3521
3522 eofflag = 0;
3523 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3524 off = uio_offset(auio);
3525
3526 if (v3) {
3527 nfsm_srv_vattr_init(&at, v3);
3528 getret = vnode_getattr(vp, &at, &context);
3529 if (!error)
3530 error = getret;
3531 }
3532 if (error) {
3533 vnode_put(vp);
3534 FREE(rbuf, M_TEMP);
3535 nfsm_reply(NFSX_POSTOPATTR(v3));
3536 nfsm_srvpostop_attr(getret, &at);
3537 return (0);
3538 }
3539 if (uio_resid(auio) != 0) {
3540 // LP64todo - fix this
3541 siz -= uio_resid(auio);
3542
3543 /*
3544 * If nothing read, return eof
3545 * rpc reply
3546 */
3547 if (siz == 0) {
3548 vnode_put(vp);
3549 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
3550 2 * NFSX_UNSIGNED);
3551 if (v3) {
3552 nfsm_srvpostop_attr(getret, &at);
3553 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3554 txdr_hyper(&at.va_filerev, tl);
3555 tl += 2;
3556 } else
3557 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3558 *tl++ = nfs_false;
3559 *tl = nfs_true;
3560 FREE(rbuf, M_TEMP);
3561 return (0);
3562 }
3563 }
3564
3565 /*
3566 * Check for degenerate cases of nothing useful read.
3567 * If so go try again
3568 */
3569 cpos = rbuf;
3570 cend = rbuf + siz;
3571 dp = (struct direntry *)cpos;
3572 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3573 cpos += dp->d_reclen;
3574 dp = (struct direntry *)cpos;
3575 nentries--;
3576 }
3577 if (cpos >= cend || nentries == 0) {
3578 toff = off;
3579 siz = fullsiz;
3580 goto again;
3581 }
3582
3583 vnode_put(vp);
3584 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
3585 if (v3) {
3586 len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3587 nfsm_srvpostop_attr(getret, &at);
3588 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3589 txdr_hyper(&at.va_filerev, tl);
3590 } else
3591 len = 2 * NFSX_UNSIGNED;
3592 mp = mp2 = mb;
3593 bp = bpos;
3594 be = bp + mbuf_trailingspace(mp);
3595
3596 /* Loop through the records and build reply */
3597 while (cpos < cend && nentries > 0) {
3598 if (dp->d_fileno != 0) {
3599 nlen = dp->d_namlen;
3600 if (!v3 && (nlen > NFS_MAXNAMLEN))
3601 nlen = NFS_MAXNAMLEN;
3602 rem = nfsm_rndup(nlen)-nlen;
3603 len += (4 * NFSX_UNSIGNED + nlen + rem);
3604 if (v3)
3605 len += 2 * NFSX_UNSIGNED;
3606 if (len > count) {
3607 eofflag = 0;
3608 break;
3609 }
3610 /*
3611 * Build the directory record xdr from
3612 * the direntry entry.
3613 */
3614 nfsm_clget;
3615 *tl = nfs_true;
3616 bp += NFSX_UNSIGNED;
3617 nfsm_clget;
3618 if (v3) {
3619 txdr_hyper(&dp->d_fileno, &tquad);
3620 *tl = tquad.nfsuquad[0];
3621 bp += NFSX_UNSIGNED;
3622 nfsm_clget;
3623 *tl = tquad.nfsuquad[1];
3624 bp += NFSX_UNSIGNED;
3625 } else {
3626 *tl = txdr_unsigned(dp->d_fileno);
3627 bp += NFSX_UNSIGNED;
3628 }
3629 nfsm_clget;
3630 *tl = txdr_unsigned(nlen);
3631 bp += NFSX_UNSIGNED;
3632
3633 /* And loop around copying the name */
3634 xfer = nlen;
3635 cp = dp->d_name;
3636 while (xfer > 0) {
3637 nfsm_clget;
3638 if ((bp+xfer) > be)
3639 tsiz = be-bp;
3640 else
3641 tsiz = xfer;
3642 bcopy(cp, bp, tsiz);
3643 bp += tsiz;
3644 xfer -= tsiz;
3645 if (xfer > 0)
3646 cp += tsiz;
3647 }
3648 /* And null pad to a long boundary */
3649 for (i = 0; i < rem; i++)
3650 *bp++ = '\0';
3651
3652 /* Finish off the record with the cookie */
3653 nfsm_clget;
3654 if (v3) {
3655 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3656 dp->d_seekoff &= 0x00000000ffffffffULL;
3657 txdr_hyper(&dp->d_seekoff, &tquad);
3658 *tl = tquad.nfsuquad[0];
3659 bp += NFSX_UNSIGNED;
3660 nfsm_clget;
3661 *tl = tquad.nfsuquad[1];
3662 bp += NFSX_UNSIGNED;
3663 } else {
3664 *tl = txdr_unsigned(dp->d_seekoff);
3665 bp += NFSX_UNSIGNED;
3666 }
3667 }
3668 cpos += dp->d_reclen;
3669 dp = (struct direntry *)cpos;
3670 nentries--;
3671 }
3672 nfsm_clget;
3673 *tl = nfs_false;
3674 bp += NFSX_UNSIGNED;
3675 nfsm_clget;
3676 if (eofflag)
3677 *tl = nfs_true;
3678 else
3679 *tl = nfs_false;
3680 bp += NFSX_UNSIGNED;
3681 if (mp != mb) {
3682 if (bp < be)
3683 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
3684 } else
3685 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
3686 FREE(rbuf, M_TEMP);
3687 nfsmout:
3688 return (error);
3689 }
3690
3691 struct flrep {
3692 nfsuint64 fl_off;
3693 u_long fl_postopok;
3694 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
3695 u_long fl_fhok;
3696 u_long fl_fhsize;
3697 u_long fl_nfh[NFSX_V3FHMAX / sizeof (u_long)];
3698 };
3699
3700 int
3701 nfsrv_readdirplus(nfsd, slp, procp, mrq)
3702 struct nfsrv_descript *nfsd;
3703 struct nfssvc_sock *slp;
3704 proc_t procp;
3705 mbuf_t *mrq;
3706 {
3707 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
3708 mbuf_t nam = nfsd->nd_nam;
3709 caddr_t dpos = nfsd->nd_dpos;
3710 char *bp, *be;
3711 mbuf_t mp;
3712 struct direntry *dp;
3713 caddr_t cp;
3714 u_long *tl;
3715 long t1;
3716 caddr_t bpos;
3717 mbuf_t mb, mb2, mreq, mp2;
3718 char *cpos, *cend, *cp2, *rbuf;
3719 vnode_t vp, nvp;
3720 struct flrep fl;
3721 struct nfs_filehandle dnfh, *nfhp = (struct nfs_filehandle *)&fl.fl_fhsize;
3722 u_long fhsize;
3723 struct nfs_export *nx;
3724 struct nfs_export_options *nxo;
3725 uio_t auio;
3726 char uio_buf[ UIO_SIZEOF(1) ];
3727 struct vnode_attr va, at, *vap = &va;
3728 struct nfs_fattr *fp;
3729 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3730 int siz, count, fullsiz, eofflag, dirlen, nentries = 0, isdotdot;
3731 u_quad_t off, toff, verf;
3732 nfsuint64 tquad;
3733 int vnopflag;
3734 struct vfs_context context;
3735
3736 vnopflag = VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF;
3737 vp = NULL;
3738 nfsm_srvmtofh(&dnfh);
3739 nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
3740 fxdr_hyper(tl, &toff);
3741 tl += 2;
3742 fxdr_hyper(tl, &verf);
3743 tl += 2;
3744 siz = fxdr_unsigned(int, *tl++);
3745 count = fxdr_unsigned(int, *tl);
3746 off = toff;
3747 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3748 xfer = NFS_SRVMAXDATA(nfsd);
3749 if (siz > xfer)
3750 siz = xfer;
3751 fullsiz = siz;
3752 if ((error = nfsrv_fhtovp(&dnfh, nam, TRUE, &vp, &nx, &nxo))) {
3753 nfsm_reply(NFSX_UNSIGNED);
3754 nfsm_srvpostop_attr(getret, &at);
3755 return (0);
3756 }
3757 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
3758 vnode_put(vp);
3759 nfsm_reply(NFSX_UNSIGNED);
3760 nfsm_srvpostop_attr(getret, &at);
3761 return (0);
3762 }
3763 context.vc_proc = procp;
3764 context.vc_ucred = nfsd->nd_cr;
3765 if (nxo->nxo_flags & NX_32BITCLIENTS)
3766 vnopflag |= VNODE_READDIR_SEEKOFF32;
3767 nfsm_srv_vattr_init(&at, 1);
3768 error = getret = vnode_getattr(vp, &at, &context);
3769 if (!error && toff && verf && verf != at.va_filerev)
3770 error = NFSERR_BAD_COOKIE;
3771 if (!error)
3772 error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_LIST_DIRECTORY, &context, nxo, 0);
3773 if (error) {
3774 vnode_put(vp);
3775 vp = NULL;
3776 nfsm_reply(NFSX_V3POSTOPATTR);
3777 nfsm_srvpostop_attr(getret, &at);
3778 return (0);
3779 }
3780 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3781 if (!rbuf) {
3782 error = ENOMEM;
3783 vnode_put(vp);
3784 vp = NULL;
3785 nfsm_reply(NFSX_V3POSTOPATTR);
3786 nfsm_srvpostop_attr(getret, &at);
3787 return (0);
3788 }
3789 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
3790 &uio_buf[0], sizeof(uio_buf));
3791 if (!auio) {
3792 error = ENOMEM;
3793 FREE(rbuf, M_TEMP);
3794 vnode_put(vp);
3795 vp = NULL;
3796 nfsm_reply(NFSX_V3POSTOPATTR);
3797 nfsm_srvpostop_attr(getret, &at);
3798 return (0);
3799 }
3800 again:
3801 uio_reset(auio, off, UIO_SYSSPACE, UIO_READ);
3802 uio_addiov(auio, CAST_USER_ADDR_T(rbuf), fullsiz);
3803 eofflag = 0;
3804 error = VNOP_READDIR(vp, auio, vnopflag, &eofflag, &nentries, &context);
3805 off = uio_offset(auio);
3806 nfsm_srv_vattr_init(&at, 1);
3807 getret = vnode_getattr(vp, &at, &context);
3808
3809 if (!error)
3810 error = getret;
3811 if (error) {
3812 vnode_put(vp);
3813 vp = NULL;
3814 FREE(rbuf, M_TEMP);
3815 nfsm_reply(NFSX_V3POSTOPATTR);
3816 nfsm_srvpostop_attr(getret, &at);
3817 return (0);
3818 }
3819 if (uio_resid(auio) != 0) {
3820 // LP64todo - fix this
3821 siz -= uio_resid(auio);
3822
3823 /*
3824 * If nothing read, return eof
3825 * rpc reply
3826 */
3827 if (siz == 0) {
3828 vnode_put(vp);
3829 vp = NULL;
3830 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3831 2 * NFSX_UNSIGNED);
3832 nfsm_srvpostop_attr(getret, &at);
3833 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
3834 txdr_hyper(&at.va_filerev, tl);
3835 tl += 2;
3836 *tl++ = nfs_false;
3837 *tl = nfs_true;
3838 FREE(rbuf, M_TEMP);
3839 return (0);
3840 }
3841 }
3842
3843 /*
3844 * Check for degenerate cases of nothing useful read.
3845 * If so go try again
3846 */
3847 cpos = rbuf;
3848 cend = rbuf + siz;
3849 dp = (struct direntry *)cpos;
3850 while (dp->d_fileno == 0 && cpos < cend && nentries > 0) {
3851 cpos += dp->d_reclen;
3852 dp = (struct direntry *)cpos;
3853 nentries--;
3854 }
3855 if (cpos >= cend || nentries == 0) {
3856 toff = off;
3857 siz = fullsiz;
3858 goto again;
3859 }
3860
3861 /*
3862 * Probe one of the directory entries to see if the filesystem
3863 * supports VGET.
3864 */
3865 if ((error = VFS_VGET(vnode_mount(vp), (ino64_t)dp->d_fileno, &nvp, &context))) {
3866 if (error == ENOTSUP) /* let others get passed back */
3867 error = NFSERR_NOTSUPP;
3868 vnode_put(vp);
3869 vp = NULL;
3870 FREE(rbuf, M_TEMP);
3871 nfsm_reply(NFSX_V3POSTOPATTR);
3872 nfsm_srvpostop_attr(getret, &at);
3873 return (0);
3874 }
3875 vnode_put(nvp);
3876
3877 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3878 nfsm_reply(count);
3879 nfsm_srvpostop_attr(getret, &at);
3880 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
3881 txdr_hyper(&at.va_filerev, tl);
3882 mp = mp2 = mb;
3883 bp = bpos;
3884 be = bp + mbuf_trailingspace(mp);
3885
3886 /* Loop through the records and build reply */
3887 while (cpos < cend && nentries > 0) {
3888 if (dp->d_fileno != 0) {
3889 nlen = dp->d_namlen;
3890 rem = nfsm_rndup(nlen)-nlen;
3891
3892 /*
3893 * Got to get the vnode for lookup per entry.
3894 */
3895 if (VFS_VGET(vnode_mount(vp), (ino64_t)dp->d_fileno, &nvp, &context))
3896 goto invalid;
3897 isdotdot = ((dp->d_namlen == 2) &&
3898 (dp->d_name[0] == '.') && (dp->d_name[1] == '.'));
3899 if (nfsrv_vptofh(nx, 0, (isdotdot ? &dnfh : NULL), nvp, &context, nfhp)) {
3900 // XXX file handle is optional, so we should be able to
3901 // XXX return this entry without the file handle
3902 vnode_put(nvp);
3903 goto invalid;
3904 }
3905 nfsm_srv_vattr_init(vap, 1);
3906 if (vnode_getattr(nvp, vap, &context)) {
3907 // XXX attributes are optional, so we should be able to
3908 // XXX return this entry without the attributes
3909 vnode_put(nvp);
3910 goto invalid;
3911 }
3912 vnode_put(nvp);
3913
3914 /*
3915 * If either the dircount or maxcount will be
3916 * exceeded, get out now. Both of these lengths
3917 * are calculated conservatively, including all
3918 * XDR overheads.
3919 */
3920 len += (8 * NFSX_UNSIGNED + nlen + rem + nfhp->nfh_len +
3921 NFSX_V3POSTOPATTR);
3922 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3923 if (len > count || dirlen > fullsiz) {
3924 eofflag = 0;
3925 break;
3926 }
3927
3928 /*
3929 * Build the directory record xdr from
3930 * the direntry entry.
3931 */
3932 fp = (struct nfs_fattr *)&fl.fl_fattr;
3933 nfsm_srvfillattr(vap, fp);
3934 fhsize = nfhp->nfh_len;
3935 fl.fl_fhsize = txdr_unsigned(fhsize);
3936 fl.fl_fhok = nfs_true;
3937 fl.fl_postopok = nfs_true;
3938 if (vnopflag & VNODE_READDIR_SEEKOFF32)
3939 dp->d_seekoff &= 0x00000000ffffffffULL;
3940 txdr_hyper(&dp->d_seekoff, &fl.fl_off);
3941
3942 nfsm_clget;
3943 *tl = nfs_true;
3944 bp += NFSX_UNSIGNED;
3945
3946 nfsm_clget;
3947 txdr_hyper(&dp->d_fileno, &tquad);
3948 *tl = tquad.nfsuquad[0];
3949 bp += NFSX_UNSIGNED;
3950 nfsm_clget;
3951 *tl = tquad.nfsuquad[1];
3952 bp += NFSX_UNSIGNED;
3953
3954 nfsm_clget;
3955 *tl = txdr_unsigned(nlen);
3956 bp += NFSX_UNSIGNED;
3957
3958 /* And loop around copying the name */
3959 xfer = nlen;
3960 cp = dp->d_name;
3961 while (xfer > 0) {
3962 nfsm_clget;
3963 if ((bp + xfer) > be)
3964 tsiz = be - bp;
3965 else
3966 tsiz = xfer;
3967 bcopy(cp, bp, tsiz);
3968 bp += tsiz;
3969 xfer -= tsiz;
3970 if (xfer > 0)
3971 cp += tsiz;
3972 }
3973 /* And null pad to a long boundary */
3974 for (i = 0; i < rem; i++)
3975 *bp++ = '\0';
3976
3977 /*
3978 * Now copy the flrep structure out.
3979 */
3980 xfer = sizeof(struct flrep) - sizeof(fl.fl_nfh) + fhsize;
3981 cp = (caddr_t)&fl;
3982 while (xfer > 0) {
3983 nfsm_clget;
3984 if ((bp + xfer) > be)
3985 tsiz = be - bp;
3986 else
3987 tsiz = xfer;
3988 bcopy(cp, bp, tsiz);
3989 bp += tsiz;
3990 xfer -= tsiz;
3991 if (xfer > 0)
3992 cp += tsiz;
3993 }
3994 }
3995 invalid:
3996 cpos += dp->d_reclen;
3997 dp = (struct direntry *)cpos;
3998 nentries--;
3999 }
4000 vnode_put(vp);
4001 vp = NULL;
4002 nfsm_clget;
4003 *tl = nfs_false;
4004 bp += NFSX_UNSIGNED;
4005 nfsm_clget;
4006 if (eofflag)
4007 *tl = nfs_true;
4008 else
4009 *tl = nfs_false;
4010 bp += NFSX_UNSIGNED;
4011 if (mp != mb) {
4012 if (bp < be)
4013 mbuf_setlen(mp, bp - (char*)mbuf_data(mp));
4014 } else
4015 mbuf_setlen(mp, mbuf_len(mp) + (bp - bpos));
4016 FREE(rbuf, M_TEMP);
4017 nfsmout:
4018 if (vp)
4019 vnode_put(vp);
4020 return (error);
4021 }
4022
4023 /*
4024 * nfs commit service
4025 */
4026 int
4027 nfsrv_commit(nfsd, slp, procp, mrq)
4028 struct nfsrv_descript *nfsd;
4029 struct nfssvc_sock *slp;
4030 proc_t procp;
4031 mbuf_t *mrq;
4032 {
4033 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4034 mbuf_t nam = nfsd->nd_nam;
4035 caddr_t dpos = nfsd->nd_dpos;
4036 struct vnode_attr bfor, aft;
4037 vnode_t vp;
4038 struct nfs_filehandle nfh;
4039 struct nfs_export *nx;
4040 struct nfs_export_options *nxo;
4041 u_long *tl;
4042 long t1;
4043 caddr_t bpos;
4044 int error = 0, for_ret = 1, aft_ret = 1, count;
4045 char *cp2;
4046 mbuf_t mb, mb2, mreq;
4047 u_quad_t off;
4048 struct vfs_context context;
4049
4050 nfsm_srvmtofh(&nfh);
4051 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
4052
4053 /*
4054 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4055 * count parameters, so these arguments are useless (someday maybe).
4056 */
4057 fxdr_hyper(tl, &off);
4058 tl += 2;
4059 count = fxdr_unsigned(int, *tl);
4060 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4061 nfsm_reply(2 * NFSX_UNSIGNED);
4062 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4063 return (0);
4064 }
4065 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4066 vnode_put(vp);
4067 nfsm_reply(2 * NFSX_UNSIGNED);
4068 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4069 return (0);
4070 }
4071 context.vc_proc = procp;
4072 context.vc_ucred = nfsd->nd_cr;
4073
4074 nfsm_srv_pre_vattr_init(&bfor, 1);
4075 for_ret = vnode_getattr(vp, &bfor, &context);
4076 error = VNOP_FSYNC(vp, MNT_WAIT, &context);
4077 nfsm_srv_vattr_init(&aft, 1);
4078 aft_ret = vnode_getattr(vp, &aft, &context);
4079 vnode_put(vp);
4080 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
4081 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
4082 if (!error) {
4083 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
4084 *tl++ = txdr_unsigned(boottime_sec());
4085 *tl = txdr_unsigned(0);
4086 } else
4087 return (0);
4088 nfsmout:
4089 return (error);
4090 }
4091
4092 /*
4093 * nfs statfs service
4094 */
4095 int
4096 nfsrv_statfs(nfsd, slp, procp, mrq)
4097 struct nfsrv_descript *nfsd;
4098 struct nfssvc_sock *slp;
4099 proc_t procp;
4100 mbuf_t *mrq;
4101 {
4102 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4103 mbuf_t nam = nfsd->nd_nam;
4104 caddr_t dpos = nfsd->nd_dpos;
4105 struct vfs_attr va;
4106 struct nfs_statfs *sfp;
4107 u_long *tl;
4108 long t1;
4109 caddr_t bpos;
4110 int error = 0, getret = 1;
4111 int v3 = (nfsd->nd_flag & ND_NFSV3);
4112 char *cp2;
4113 mbuf_t mb, mb2, mreq;
4114 vnode_t vp;
4115 struct vnode_attr at;
4116 struct nfs_filehandle nfh;
4117 struct nfs_export *nx;
4118 struct nfs_export_options *nxo;
4119 u_quad_t tval;
4120 off_t blksize;
4121 struct vfs_context context;
4122
4123 nfsm_srvmtofh(&nfh);
4124 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4125 nfsm_reply(NFSX_UNSIGNED);
4126 nfsm_srvpostop_attr(getret, &at);
4127 return (0);
4128 }
4129 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4130 vnode_put(vp);
4131 nfsm_reply(NFSX_UNSIGNED);
4132 nfsm_srvpostop_attr(getret, &at);
4133 return (0);
4134 }
4135 context.vc_proc = procp;
4136 context.vc_ucred = nfsd->nd_cr;
4137
4138 VFSATTR_INIT(&va);
4139 VFSATTR_WANTED(&va, f_blocks);
4140 VFSATTR_WANTED(&va, f_bavail);
4141 VFSATTR_WANTED(&va, f_files);
4142 VFSATTR_WANTED(&va, f_ffree);
4143 error = vfs_getattr(vnode_mount(vp), &va, &context);
4144 blksize = vnode_mount(vp)->mnt_vfsstat.f_bsize;
4145 nfsm_srv_vattr_init(&at, v3);
4146 getret = vnode_getattr(vp, &at, &context);
4147 vnode_put(vp);
4148 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
4149 if (v3)
4150 nfsm_srvpostop_attr(getret, &at);
4151 if (error)
4152 return (0);
4153 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
4154 if (v3) {
4155 tval = (u_quad_t)(va.f_blocks * blksize);
4156 txdr_hyper(&tval, &sfp->sf_tbytes);
4157 tval = (u_quad_t)(va.f_bfree * blksize);
4158 txdr_hyper(&tval, &sfp->sf_fbytes);
4159 tval = (u_quad_t)(va.f_bavail * blksize);
4160 txdr_hyper(&tval, &sfp->sf_abytes);
4161 txdr_hyper(&va.f_files, &sfp->sf_tfiles);
4162 txdr_hyper(&va.f_ffree, &sfp->sf_ffiles);
4163 txdr_hyper(&va.f_ffree, &sfp->sf_afiles);
4164 sfp->sf_invarsec = 0;
4165 } else {
4166 sfp->sf_tsize = txdr_unsigned(NFS_V2MAXDATA);
4167 sfp->sf_bsize = txdr_unsigned((unsigned)blksize);
4168 sfp->sf_blocks = txdr_unsigned((unsigned)va.f_blocks);
4169 sfp->sf_bfree = txdr_unsigned((unsigned)va.f_bfree);
4170 sfp->sf_bavail = txdr_unsigned((unsigned)va.f_bavail);
4171 }
4172 nfsmout:
4173 return (error);
4174 }
4175
4176 /*
4177 * nfs fsinfo service
4178 */
4179 int
4180 nfsrv_fsinfo(nfsd, slp, procp, mrq)
4181 struct nfsrv_descript *nfsd;
4182 struct nfssvc_sock *slp;
4183 proc_t procp;
4184 mbuf_t *mrq;
4185 {
4186 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4187 mbuf_t nam = nfsd->nd_nam;
4188 caddr_t dpos = nfsd->nd_dpos;
4189 u_long *tl;
4190 struct nfsv3_fsinfo *sip;
4191 long t1;
4192 caddr_t bpos;
4193 int error = 0, getret = 1, prefsize, maxsize;
4194 char *cp2;
4195 mbuf_t mb, mb2, mreq;
4196 vnode_t vp;
4197 struct vnode_attr at;
4198 struct nfs_filehandle nfh;
4199 struct nfs_export *nx;
4200 struct nfs_export_options *nxo;
4201 struct vfs_context context;
4202
4203 nfsm_srvmtofh(&nfh);
4204 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4205 nfsm_reply(NFSX_UNSIGNED);
4206 nfsm_srvpostop_attr(getret, &at);
4207 return (0);
4208 }
4209 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4210 vnode_put(vp);
4211 nfsm_reply(NFSX_UNSIGNED);
4212 nfsm_srvpostop_attr(getret, &at);
4213 return (0);
4214 }
4215 context.vc_proc = procp;
4216 context.vc_ucred = nfsd->nd_cr;
4217
4218 nfsm_srv_vattr_init(&at, 1);
4219 getret = vnode_getattr(vp, &at, &context);
4220 vnode_put(vp);
4221 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
4222 nfsm_srvpostop_attr(getret, &at);
4223 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
4224
4225 /*
4226 * XXX
4227 * There should be file system VFS OP(s) to get this information.
4228 * For now, assume our usual NFS defaults.
4229 */
4230 if (slp->ns_sotype == SOCK_DGRAM) {
4231 maxsize = NFS_MAXDGRAMDATA;
4232 prefsize = NFS_PREFDGRAMDATA;
4233 } else
4234 maxsize = prefsize = NFS_MAXDATA;
4235 sip->fs_rtmax = txdr_unsigned(maxsize);
4236 sip->fs_rtpref = txdr_unsigned(prefsize);
4237 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
4238 sip->fs_wtmax = txdr_unsigned(maxsize);
4239 sip->fs_wtpref = txdr_unsigned(prefsize);
4240 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
4241 sip->fs_dtpref = txdr_unsigned(prefsize);
4242 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
4243 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
4244 sip->fs_timedelta.nfsv3_sec = 0;
4245 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
4246 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
4247 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
4248 NFSV3FSINFO_CANSETTIME);
4249 nfsmout:
4250 return (error);
4251 }
4252
4253 /*
4254 * nfs pathconf service
4255 */
4256 int
4257 nfsrv_pathconf(nfsd, slp, procp, mrq)
4258 struct nfsrv_descript *nfsd;
4259 struct nfssvc_sock *slp;
4260 proc_t procp;
4261 mbuf_t *mrq;
4262 {
4263 mbuf_t mrep = nfsd->nd_mrep, md = nfsd->nd_md;
4264 mbuf_t nam = nfsd->nd_nam;
4265 caddr_t dpos = nfsd->nd_dpos;
4266 u_long *tl;
4267 struct nfsv3_pathconf *pc;
4268 long t1;
4269 caddr_t bpos;
4270 int error = 0, getret = 1, linkmax, namemax;
4271 int chownres, notrunc, case_sensitive, case_preserving;
4272 char *cp2;
4273 mbuf_t mb, mb2, mreq;
4274 vnode_t vp;
4275 struct vnode_attr at;
4276 struct nfs_filehandle nfh;
4277 struct nfs_export *nx;
4278 struct nfs_export_options *nxo;
4279 struct vfs_context context;
4280
4281 nfsm_srvmtofh(&nfh);
4282 if ((error = nfsrv_fhtovp(&nfh, nam, TRUE, &vp, &nx, &nxo))) {
4283 nfsm_reply(NFSX_UNSIGNED);
4284 nfsm_srvpostop_attr(getret, &at);
4285 return (0);
4286 }
4287 if ((error = nfsrv_credcheck(nfsd, nx, nxo))) {
4288 vnode_put(vp);
4289 nfsm_reply(NFSX_UNSIGNED);
4290 nfsm_srvpostop_attr(getret, &at);
4291 return (0);
4292 }
4293 context.vc_proc = procp;
4294 context.vc_ucred = nfsd->nd_cr;
4295
4296 error = VNOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax, &context);
4297 if (!error)
4298 error = VNOP_PATHCONF(vp, _PC_NAME_MAX, &namemax, &context);
4299 if (!error)
4300 error = VNOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres, &context);
4301 if (!error)
4302 error = VNOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc, &context);
4303 if (!error)
4304 error = VNOP_PATHCONF(vp, _PC_CASE_SENSITIVE, &case_sensitive, &context);
4305 if (!error)
4306 error = VNOP_PATHCONF(vp, _PC_CASE_PRESERVING, &case_preserving, &context);
4307 nfsm_srv_vattr_init(&at, 1);
4308 getret = vnode_getattr(vp, &at, &context);
4309 vnode_put(vp);
4310 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
4311 nfsm_srvpostop_attr(getret, &at);
4312 if (error)
4313 return (0);
4314 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
4315
4316 pc->pc_linkmax = txdr_unsigned(linkmax);
4317 pc->pc_namemax = txdr_unsigned(namemax);
4318 pc->pc_notrunc = txdr_unsigned(notrunc);
4319 pc->pc_chownrestricted = txdr_unsigned(chownres);
4320 pc->pc_caseinsensitive = txdr_unsigned(!case_sensitive);
4321 pc->pc_casepreserving = txdr_unsigned(case_preserving);
4322
4323 nfsmout:
4324 return (error);
4325 }
4326
4327 /*
4328 * Null operation, used by clients to ping server
4329 */
4330 /* ARGSUSED */
4331 int
4332 nfsrv_null(
4333 struct nfsrv_descript *nfsd,
4334 struct nfssvc_sock *slp,
4335 __unused proc_t procp,
4336 mbuf_t *mrq)
4337 {
4338 mbuf_t mrep = nfsd->nd_mrep;
4339 caddr_t bpos;
4340 int error = NFSERR_RETVOID;
4341 mbuf_t mb, mreq;
4342
4343 nfsm_reply(0);
4344 nfsmout:
4345 return (0);
4346 }
4347
4348 /*
4349 * No operation, used for obsolete procedures
4350 */
4351 /* ARGSUSED */
4352 int
4353 nfsrv_noop(
4354 struct nfsrv_descript *nfsd,
4355 struct nfssvc_sock *slp,
4356 __unused proc_t procp,
4357 mbuf_t *mrq)
4358 {
4359 mbuf_t mrep = nfsd->nd_mrep;
4360 caddr_t bpos;
4361 int error;
4362 mbuf_t mb, mreq;
4363
4364 if (nfsd->nd_repstat)
4365 error = nfsd->nd_repstat;
4366 else
4367 error = EPROCUNAVAIL;
4368 nfsm_reply(0);
4369 nfsmout:
4370 return (0);
4371 }
4372
4373 /*
4374 * Perform access checking for vnodes obtained from file handles that would
4375 * refer to files already opened by a Unix client. You cannot just use
4376 * vnode_authorize() for two reasons.
4377 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4378 * 2 - The owner is to be given access irrespective of mode bits so that
4379 * processes that chmod after opening a file don't break. I don't like
4380 * this because it opens a security hole, but since the nfs server opens
4381 * a security hole the size of a barn door anyhow, what the heck.
4382 *
4383 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4384 * will return EPERM instead of EACCESS. EPERM is always an error.
4385 */
4386
4387 static int
4388 nfsrv_authorize(
4389 vnode_t vp,
4390 vnode_t dvp,
4391 kauth_action_t action,
4392 vfs_context_t context,
4393 struct nfs_export_options *nxo,
4394 int override)
4395 {
4396 struct vnode_attr vattr;
4397 int error;
4398
4399 if (action & KAUTH_VNODE_WRITE_RIGHTS) {
4400 /*
4401 * Disallow write attempts on read-only exports;
4402 * unless the file is a socket or a block or character
4403 * device resident on the file system.
4404 */
4405 if (nxo->nxo_flags & NX_READONLY) {
4406 switch (vnode_vtype(vp)) {
4407 case VREG: case VDIR: case VLNK: case VCPLX:
4408 return (EROFS);
4409 default:
4410 break;
4411 }
4412 }
4413 }
4414 error = vnode_authorize(vp, dvp, action, context);
4415 /*
4416 * Allow certain operations for the owner (reads and writes
4417 * on files that are already open). Picking up from FreeBSD.
4418 */
4419 if (override && (error == EACCES)) {
4420 VATTR_INIT(&vattr);
4421 VATTR_WANTED(&vattr, va_uid);
4422 if ((vnode_getattr(vp, &vattr, context) == 0) &&
4423 (kauth_cred_getuid(vfs_context_ucred(context)) == vattr.va_uid))
4424 error = 0;
4425 }
4426 return error;
4427 }
4428 #endif /* NFS_NOSERVER */
4429