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