nfs_serv.c revision 1.177.4.1 1 /* $NetBSD: nfs_serv.c,v 1.177.4.1 2023/03/30 11:59:24 martin Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95
35 */
36
37 /*
38 * nfs version 2 and 3 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request
42 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
43 * 3 - build the rpc reply in an mbuf list
44 * nb:
45 * - do not mix the phases, since the nfsm_?? macros can return failures
46 * on a bad rpc or similar and do not do any vrele() or vput()'s
47 *
48 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
49 * error number iff error != 0 whereas
50 * returning an error from the server function implies a fatal error
51 * such as a badly constructed rpc request that should be dropped without
52 * a reply.
53 * For Version 3, nfsm_reply() does not return for the error case, since
54 * most version 3 rpcs return more than the status for error cases.
55 */
56
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: nfs_serv.c,v 1.177.4.1 2023/03/30 11:59:24 martin Exp $");
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/proc.h>
63 #include <sys/file.h>
64 #include <sys/namei.h>
65 #include <sys/vnode.h>
66 #include <sys/mount.h>
67 #include <sys/fstrans.h>
68 #include <sys/socket.h>
69 #include <sys/socketvar.h>
70 #include <sys/mbuf.h>
71 #include <sys/dirent.h>
72 #include <sys/stat.h>
73 #include <sys/kernel.h>
74 #include <sys/hash.h>
75 #include <sys/kauth.h>
76 #include <sys/module.h>
77 #include <sys/syscall.h>
78 #include <sys/syscallargs.h>
79 #include <sys/syscallvar.h>
80
81 #include <uvm/uvm.h>
82
83 #include <nfs/nfsproto.h>
84 #include <nfs/rpcv2.h>
85 #include <nfs/nfs.h>
86 #include <nfs/xdr_subs.h>
87 #include <nfs/nfsm_subs.h>
88 #include <nfs/nfs_var.h>
89
90 MODULE(MODULE_CLASS_MISC, nfsserver, "nfs");
91
92 /* Global vars */
93 extern u_int32_t nfs_xdrneg1;
94 extern u_int32_t nfs_false, nfs_true;
95 extern const enum vtype nv3tov_type[8];
96 extern struct nfsstats nfsstats;
97 extern const nfstype nfsv2_type[9];
98 extern const nfstype nfsv3_type[9];
99 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
100 bool nfsd_use_loan = true; /* use page-loan for READ OP */
101
102 #define nqsrv_getl(vp, rw) /* nothing */
103
104 static const struct syscall_package nfsserver_syscalls[] = {
105 { SYS_nfssvc, 0, (sy_call_t *)sys_nfssvc },
106 { 0, 0, NULL },
107 };
108
109 static int
110 nfsserver_modcmd(modcmd_t cmd, void *arg)
111 {
112 extern struct vfs_hooks nfs_export_hooks; /* XXX */
113 int error;
114
115 switch (cmd) {
116 case MODULE_CMD_INIT:
117 error = syscall_establish(NULL, nfsserver_syscalls);
118 if (error != 0) {
119 return error;
120 }
121 nfs_init(); /* XXX for monolithic kernel */
122 netexport_init();
123 nfsrv_initcache(); /* Init the server request cache */
124 nfsrv_init(0); /* Init server data structures */
125 vfs_hooks_attach(&nfs_export_hooks);
126 nfs_timer_srvinit(nfsrv_timer);
127 return 0;
128 case MODULE_CMD_FINI:
129 error = syscall_disestablish(NULL, nfsserver_syscalls);
130 if (error != 0) {
131 return error;
132 }
133 /*
134 * Kill export list before detaching VFS hooks, so we
135 * we don't leak state due to a concurrent umount().
136 */
137 netexport_fini();
138 vfs_hooks_detach(&nfs_export_hooks);
139
140 /* Kill timer before server goes away. */
141 nfs_timer_srvfini();
142 nfsrv_fini();
143
144 /* Server uses server cache, so kill cache last. */
145 nfsrv_finicache();
146 nfs_fini();
147 return 0;
148 case MODULE_CMD_AUTOUNLOAD:
149 if (netexport_hasexports())
150 return EBUSY;
151 /*FALLTHROUGH*/
152 default:
153 return ENOTTY;
154 }
155 }
156
157 /*
158 * nfs v3 access service
159 */
160 int
161 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
162 {
163 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
164 struct mbuf *nam = nfsd->nd_nam;
165 char *dpos = nfsd->nd_dpos;
166 kauth_cred_t cred = nfsd->nd_cr;
167 struct vnode *vp;
168 nfsrvfh_t nsfh;
169 u_int32_t *tl;
170 int32_t t1;
171 char *bpos;
172 int error = 0, rdonly, cache = 0, getret;
173 char *cp2;
174 struct mbuf *mb, *mreq __unused;
175 struct vattr va;
176 u_long inmode, testmode, outmode;
177 u_quad_t frev;
178
179 nfsm_srvmtofh(&nsfh);
180 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
181 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, &rdonly,
182 (nfsd->nd_flag & ND_KERBAUTH), false);
183 if (error) {
184 nfsm_reply(NFSX_UNSIGNED);
185 nfsm_srvpostop_attr(1, (struct vattr *)0);
186 return (0);
187 }
188 inmode = fxdr_unsigned(u_int32_t, *tl);
189 outmode = 0;
190 if ((inmode & NFSV3ACCESS_READ) &&
191 nfsrv_access(vp, VREAD, cred, rdonly, lwp, 0) == 0)
192 outmode |= NFSV3ACCESS_READ;
193 if (vp->v_type != VDIR) {
194 testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
195 if (testmode &&
196 nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 0) == 0)
197 outmode |= testmode;
198 if ((inmode & NFSV3ACCESS_EXECUTE) &&
199 nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0) == 0)
200 outmode |= NFSV3ACCESS_EXECUTE;
201 } else {
202 testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
203 NFSV3ACCESS_DELETE);
204 if (testmode &&
205 nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 0) == 0)
206 outmode |= testmode;
207 if ((inmode & NFSV3ACCESS_LOOKUP) &&
208 nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0) == 0)
209 outmode |= NFSV3ACCESS_LOOKUP;
210 }
211 getret = VOP_GETATTR(vp, &va, cred);
212 vput(vp);
213 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
214 nfsm_srvpostop_attr(getret, &va);
215 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
216 *tl = txdr_unsigned(outmode);
217 nfsm_srvdone;
218 }
219
220 /*
221 * nfs getattr service
222 */
223 int
224 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
225 {
226 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
227 struct mbuf *nam = nfsd->nd_nam;
228 char *dpos = nfsd->nd_dpos;
229 kauth_cred_t cred = nfsd->nd_cr;
230 struct nfs_fattr *fp;
231 struct vattr va;
232 struct vnode *vp;
233 nfsrvfh_t nsfh;
234 u_int32_t *tl;
235 int32_t t1;
236 char *bpos;
237 int error = 0, rdonly, cache = 0;
238 char *cp2;
239 struct mbuf *mb, *mreq __unused;
240 u_quad_t frev;
241
242 nfsm_srvmtofh(&nsfh);
243 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, &rdonly,
244 (nfsd->nd_flag & ND_KERBAUTH), false);
245 if (error) {
246 nfsm_reply(0);
247 return (0);
248 }
249 nqsrv_getl(vp, ND_READ);
250 error = VOP_GETATTR(vp, &va, cred);
251 vput(vp);
252 nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
253 if (error)
254 return (0);
255 nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
256 nfsm_srvfillattr(&va, fp);
257 nfsm_srvdone;
258 }
259
260 /*
261 * nfs setattr service
262 */
263 int
264 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
265 {
266 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
267 struct mbuf *nam = nfsd->nd_nam;
268 char *dpos = nfsd->nd_dpos;
269 kauth_cred_t cred = nfsd->nd_cr;
270 struct vattr va, preat;
271 struct nfsv2_sattr *sp;
272 struct nfs_fattr *fp;
273 struct vnode *vp;
274 nfsrvfh_t nsfh;
275 u_int32_t *tl;
276 int32_t t1;
277 char *bpos;
278 int error = 0, rdonly, cache = 0, preat_ret = 1, postat_ret = 1;
279 int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
280 char *cp2;
281 struct mbuf *mb, *mreq __unused;
282 u_quad_t frev;
283 struct timespec guard;
284
285 memset(&guard, 0, sizeof guard); /* XXX gcc */
286
287 nfsm_srvmtofh(&nsfh);
288 vattr_null(&va);
289 if (v3) {
290 nfsm_srvsattr(&va);
291 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
292 gcheck = fxdr_unsigned(int, *tl);
293 if (gcheck) {
294 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
295 fxdr_nfsv3time(tl, &guard);
296 }
297 } else {
298 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
299 /*
300 * Nah nah nah nah na nah
301 * There is a bug in the Sun client that puts 0xffff in the mode
302 * field of sattr when it should put in 0xffffffff. The u_short
303 * doesn't sign extend.
304 * --> check the low order 2 bytes for 0xffff
305 */
306 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
307 va.va_mode = nfstov_mode(sp->sa_mode);
308 if (sp->sa_uid != nfs_xdrneg1)
309 va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
310 if (sp->sa_gid != nfs_xdrneg1)
311 va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
312 if (sp->sa_size != nfs_xdrneg1)
313 va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
314 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
315 #ifdef notyet
316 fxdr_nfsv2time(&sp->sa_atime, &va.va_atime);
317 #else
318 va.va_atime.tv_sec =
319 fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
320 va.va_atime.tv_nsec = 0;
321 #endif
322 }
323 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
324 fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime);
325
326 }
327
328 /*
329 * Now that we have all the fields, lets do it.
330 */
331 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, &rdonly,
332 (nfsd->nd_flag & ND_KERBAUTH), false);
333 if (error) {
334 nfsm_reply(2 * NFSX_UNSIGNED);
335 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
336 return (0);
337 }
338 nqsrv_getl(vp, ND_WRITE);
339 if (v3) {
340 error = preat_ret = VOP_GETATTR(vp, &preat, cred);
341 if (!error && gcheck &&
342 (preat.va_ctime.tv_sec != guard.tv_sec ||
343 preat.va_ctime.tv_nsec != guard.tv_nsec))
344 error = NFSERR_NOT_SYNC;
345 if (error) {
346 vput(vp);
347 nfsm_reply(NFSX_WCCDATA(v3));
348 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
349 return (0);
350 }
351 }
352
353 /*
354 * If the size is being changed write acces is required, otherwise
355 * just check for a read only file system.
356 */
357 if (va.va_size == ((u_quad_t)((quad_t) -1))) {
358 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
359 error = EROFS;
360 goto out;
361 }
362 } else {
363 if (vp->v_type == VDIR) {
364 error = EISDIR;
365 goto out;
366 } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
367 lwp, 0)) != 0)
368 goto out;
369 }
370 error = VOP_SETATTR(vp, &va, cred);
371 postat_ret = VOP_GETATTR(vp, &va, cred);
372 if (!error)
373 error = postat_ret;
374 out:
375 vput(vp);
376 nfsm_reply(NFSX_WCCORFATTR(v3));
377 if (v3) {
378 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
379 return (0);
380 } else {
381 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
382 nfsm_srvfillattr(&va, fp);
383 }
384 nfsm_srvdone;
385 }
386
387 /*
388 * nfs lookup rpc
389 */
390 int
391 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
392 {
393 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
394 struct mbuf *nam = nfsd->nd_nam;
395 char *dpos = nfsd->nd_dpos;
396 kauth_cred_t cred = nfsd->nd_cr;
397 struct nfs_fattr *fp;
398 struct nameidata nd, ind, *ndp = &nd;
399 struct pathbuf *ipb = NULL;
400 struct vnode *vp, *dirp;
401 nfsrvfh_t nsfh;
402 char *cp;
403 u_int32_t *tl;
404 int32_t t1;
405 char *bpos;
406 int error = 0, cache = 0, dirattr_ret = 1;
407 uint32_t len;
408 int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
409 char *cp2;
410 struct mbuf *mb, *mreq __unused;
411 struct vattr va, dirattr;
412 u_quad_t frev;
413
414 nfsm_srvmtofh(&nsfh);
415 nfsm_srvnamesiz(len);
416
417 pubflag = nfs_ispublicfh(&nsfh);
418
419 nd.ni_cnd.cn_cred = cred;
420 nd.ni_cnd.cn_nameiop = LOOKUP;
421 nd.ni_cnd.cn_flags = LOCKLEAF;
422 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
423 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
424
425 if (!error && pubflag) {
426 if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL &&
427 (ipb = pathbuf_create(nfs_pub.np_index)) != NULL) {
428 /*
429 * Setup call to lookup() to see if we can find
430 * the index file. Arguably, this doesn't belong
431 * in a kernel.. Ugh.
432 */
433 ind = nd;
434 VOP_UNLOCK(nd.ni_vp);
435 ind.ni_pathbuf = ipb;
436
437 error = lookup_for_nfsd_index(&ind, nd.ni_vp);
438 if (!error) {
439 /*
440 * Found an index file. Get rid of
441 * the old references.
442 */
443 if (dirp)
444 vrele(dirp);
445 dirp = nd.ni_vp;
446 ndp = &ind;
447 } else
448 error = 0;
449 }
450 /*
451 * If the public filehandle was used, check that this lookup
452 * didn't result in a filehandle outside the publicly exported
453 * filesystem.
454 */
455
456 if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) {
457 vput(nd.ni_vp);
458 error = EPERM;
459 }
460 }
461
462 if (error) {
463 if (nd.ni_pathbuf != NULL) {
464 pathbuf_destroy(nd.ni_pathbuf);
465 }
466 if (ipb != NULL) {
467 pathbuf_destroy(ipb);
468 }
469 if (dirp) {
470 if (v3) {
471 vn_lock(dirp, LK_SHARED | LK_RETRY);
472 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred);
473 vput(dirp);
474 } else
475 vrele(dirp);
476 }
477 nfsm_reply(NFSX_POSTOPATTR(v3));
478 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
479 return (0);
480 }
481
482 nqsrv_getl(ndp->ni_startdir, ND_READ);
483 pathbuf_destroy(nd.ni_pathbuf);
484 if (ipb != NULL) {
485 pathbuf_destroy(ipb);
486 }
487 vp = ndp->ni_vp;
488 error = nfsrv_composefh(vp, &nsfh, v3);
489 if (!error)
490 error = VOP_GETATTR(vp, &va, cred);
491 vput(vp);
492 if (dirp) {
493 if (v3) {
494 vn_lock(dirp, LK_SHARED | LK_RETRY);
495 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred);
496 vput(dirp);
497 } else
498 vrele(dirp);
499 }
500 nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPORFATTR(v3) +
501 NFSX_POSTOPATTR(v3));
502 if (error) {
503 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
504 return (0);
505 }
506 nfsm_srvfhtom(&nsfh, v3);
507 if (v3) {
508 nfsm_srvpostop_attr(0, &va);
509 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
510 } else {
511 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
512 nfsm_srvfillattr(&va, fp);
513 }
514 nfsm_srvdone;
515 }
516
517 /*
518 * nfs readlink service
519 */
520 int
521 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
522 {
523 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
524 struct mbuf *nam = nfsd->nd_nam;
525 char *dpos = nfsd->nd_dpos;
526 kauth_cred_t cred = nfsd->nd_cr;
527 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
528 struct iovec *ivp = iv;
529 struct mbuf *mp;
530 u_int32_t *tl;
531 int32_t t1;
532 char *bpos;
533 int error = 0, rdonly, cache = 0, i, padlen, getret;
534 uint32_t len;
535 int v3 = (nfsd->nd_flag & ND_NFSV3);
536 char *cp2;
537 struct mbuf *mb, *mp2 = NULL, *mp3 = NULL, *mreq __unused;
538 struct vnode *vp;
539 struct vattr attr;
540 nfsrvfh_t nsfh;
541 struct uio io, *uiop = &io;
542 u_quad_t frev;
543
544 nfsm_srvmtofh(&nsfh);
545 len = 0;
546 i = 0;
547 while (len < NFS_MAXPATHLEN) {
548 mp = m_get(M_WAIT, MT_DATA);
549 MCLAIM(mp, &nfs_mowner);
550 m_clget(mp, M_WAIT);
551 mp->m_len = NFSMSIZ(mp);
552 if (len == 0)
553 mp3 = mp2 = mp;
554 else {
555 mp2->m_next = mp;
556 mp2 = mp;
557 }
558 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
559 mp->m_len = NFS_MAXPATHLEN-len;
560 len = NFS_MAXPATHLEN;
561 } else
562 len += mp->m_len;
563 ivp->iov_base = mtod(mp, void *);
564 ivp->iov_len = mp->m_len;
565 i++;
566 ivp++;
567 }
568 uiop->uio_iov = iv;
569 uiop->uio_iovcnt = i;
570 uiop->uio_offset = 0;
571 uiop->uio_resid = len;
572 uiop->uio_rw = UIO_READ;
573 UIO_SETUP_SYSSPACE(uiop);
574 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
575 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
576 if (error) {
577 m_freem(mp3);
578 nfsm_reply(2 * NFSX_UNSIGNED);
579 nfsm_srvpostop_attr(1, (struct vattr *)0);
580 return (0);
581 }
582 if (vp->v_type != VLNK) {
583 if (v3)
584 error = EINVAL;
585 else
586 error = ENXIO;
587 goto out;
588 }
589 nqsrv_getl(vp, ND_READ);
590 error = VOP_READLINK(vp, uiop, cred);
591 out:
592 getret = VOP_GETATTR(vp, &attr, cred);
593 vput(vp);
594 if (error)
595 m_freem(mp3);
596 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
597 if (v3) {
598 nfsm_srvpostop_attr(getret, &attr);
599 if (error)
600 return (0);
601 }
602 len -= uiop->uio_resid;
603 padlen = nfsm_padlen(len);
604 if (len == 0) {
605 m_freem(mp3);
606 mp3 = NULL;
607 } else if (uiop->uio_resid || padlen)
608 nfs_zeropad(mp3, uiop->uio_resid, padlen);
609 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
610 *tl = txdr_unsigned(len);
611 mb->m_next = mp3;
612 nfsm_srvdone;
613 }
614
615 /*
616 * nfs read service
617 */
618 int
619 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
620 {
621 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
622 struct mbuf *nam = nfsd->nd_nam;
623 char *dpos = nfsd->nd_dpos;
624 kauth_cred_t cred = nfsd->nd_cr;
625 struct mbuf *m;
626 struct nfs_fattr *fp;
627 u_int32_t *tl;
628 int32_t t1;
629 int i;
630 char *bpos;
631 int error = 0, rdonly, cache = 0, getret;
632 int v3 = (nfsd->nd_flag & ND_NFSV3);
633 uint32_t reqlen, len, cnt, left;
634 int padlen;
635 char *cp2;
636 struct mbuf *mb, *mreq;
637 struct vnode *vp;
638 nfsrvfh_t nsfh;
639 struct uio io, *uiop = &io;
640 struct vattr va;
641 off_t off;
642 u_quad_t frev;
643
644 nfsm_srvmtofh(&nsfh);
645 if (v3) {
646 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
647 off = fxdr_hyper(tl);
648 } else {
649 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
650 off = (off_t)fxdr_unsigned(u_int32_t, *tl);
651 }
652 nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
653 reqlen = fxdr_unsigned(uint32_t, *tl);
654 reqlen = MIN(reqlen, NFS_SRVMAXDATA(nfsd));
655 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
656 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
657 if (error) {
658 nfsm_reply(2 * NFSX_UNSIGNED);
659 nfsm_srvpostop_attr(1, (struct vattr *)0);
660 return (0);
661 }
662 if (vp->v_type != VREG) {
663 if (v3)
664 error = EINVAL;
665 else
666 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
667 }
668 if (!error) {
669 nqsrv_getl(vp, ND_READ);
670 if ((error = nfsrv_access(vp, VREAD, cred, rdonly, lwp, 1)) != 0)
671 error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 1);
672 }
673 getret = VOP_GETATTR(vp, &va, cred);
674 if (!error)
675 error = getret;
676 if (error) {
677 vput(vp);
678 nfsm_reply(NFSX_POSTOPATTR(v3));
679 nfsm_srvpostop_attr(getret, &va);
680 return (0);
681 }
682 if (off >= va.va_size)
683 cnt = 0;
684 else if ((off + reqlen) > va.va_size)
685 cnt = va.va_size - off;
686 else
687 cnt = reqlen;
688 nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
689 if (v3) {
690 nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
691 *tl++ = nfs_true;
692 fp = (struct nfs_fattr *)tl;
693 tl += (NFSX_V3FATTR / sizeof (u_int32_t));
694 } else {
695 nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED);
696 fp = (struct nfs_fattr *)tl;
697 tl += (NFSX_V2FATTR / sizeof (u_int32_t));
698 }
699 len = left = cnt;
700 if (cnt > 0) {
701 if (nfsd_use_loan) {
702 struct vm_page **pgpp;
703 voff_t pgoff = trunc_page(off);
704 int npages;
705 vaddr_t lva;
706
707 npages = (round_page(off + cnt) - pgoff) >> PAGE_SHIFT;
708 KASSERT(npages <= M_EXT_MAXPAGES); /* XXX */
709
710 /* allocate kva for mbuf data */
711 lva = sokvaalloc(pgoff, npages << PAGE_SHIFT,
712 slp->ns_so);
713 if (lva == 0) {
714 /* fall back to VOP_READ */
715 goto loan_fail;
716 }
717
718 /* allocate mbuf */
719 m = m_get(M_WAIT, MT_DATA);
720 MCLAIM(m, &nfs_mowner);
721 pgpp = m->m_ext.ext_pgs;
722
723 /* loan pages */
724 error = uvm_loanuobjpages(&vp->v_uobj, pgoff, npages,
725 pgpp);
726 if (error) {
727 sokvafree(lva, npages << PAGE_SHIFT);
728 m_free(m);
729 if (error == EBUSY)
730 goto loan_fail;
731 goto read_error;
732 }
733
734 /* associate kva to mbuf */
735 MEXTADD(m, (void *)(lva + ((vaddr_t)off & PAGE_MASK)),
736 cnt, M_MBUF, soloanfree, slp->ns_so);
737 m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;
738 m->m_len = cnt;
739
740 /* map pages */
741 for (i = 0; i < npages; i++) {
742 pmap_kenter_pa(lva, VM_PAGE_TO_PHYS(pgpp[i]),
743 VM_PROT_READ, 0);
744 lva += PAGE_SIZE;
745 }
746
747 pmap_update(pmap_kernel());
748
749 mb->m_next = m;
750 mb = m;
751 error = 0;
752 uiop->uio_resid = 0;
753 } else {
754 struct iovec *iv;
755 struct iovec *iv2;
756 struct mbuf *m2;
757 int siz;
758 loan_fail:
759 /*
760 * Generate the mbuf list with the uio_iov ref. to it.
761 */
762 i = 0;
763 m = m2 = mb;
764 while (left > 0) {
765 siz = uimin(M_TRAILINGSPACE(m), left);
766 if (siz > 0) {
767 left -= siz;
768 i++;
769 }
770 if (left > 0) {
771 m = m_get(M_WAIT, MT_DATA);
772 MCLAIM(m, &nfs_mowner);
773 m_clget(m, M_WAIT);
774 m->m_len = 0;
775 m2->m_next = m;
776 m2 = m;
777 }
778 }
779 iv = malloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK);
780 uiop->uio_iov = iv2 = iv;
781 m = mb;
782 left = cnt;
783 i = 0;
784 while (left > 0) {
785 if (m == NULL)
786 panic("nfsrv_read iov");
787 siz = uimin(M_TRAILINGSPACE(m), left);
788 if (siz > 0) {
789 iv->iov_base = mtod(m, char *) +
790 m->m_len;
791 iv->iov_len = siz;
792 m->m_len += siz;
793 left -= siz;
794 iv++;
795 i++;
796 }
797 m = m->m_next;
798 }
799 uiop->uio_iovcnt = i;
800 uiop->uio_offset = off;
801 uiop->uio_resid = cnt;
802 uiop->uio_rw = UIO_READ;
803 UIO_SETUP_SYSSPACE(uiop);
804 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
805 free((void *)iv2, M_TEMP);
806 }
807 read_error:
808 if (error || (getret = VOP_GETATTR(vp, &va, cred)) != 0){
809 if (!error)
810 error = getret;
811 m_freem(mreq);
812 vput(vp);
813 nfsm_reply(NFSX_POSTOPATTR(v3));
814 nfsm_srvpostop_attr(getret, &va);
815 return (0);
816 }
817 } else {
818 uiop->uio_resid = 0;
819 }
820 vput(vp);
821 nfsm_srvfillattr(&va, fp);
822 len -= uiop->uio_resid;
823 padlen = nfsm_padlen(len);
824 if (uiop->uio_resid || padlen)
825 nfs_zeropad(mb, uiop->uio_resid, padlen);
826 if (v3) {
827 /* count */
828 *tl++ = txdr_unsigned(len);
829 /* eof */
830 if (off + len >= va.va_size)
831 *tl++ = nfs_true;
832 else
833 *tl++ = nfs_false;
834 }
835 *tl = txdr_unsigned(len);
836 nfsm_srvdone;
837 }
838
839 /*
840 * nfs write service
841 */
842 int
843 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
844 {
845 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
846 struct mbuf *nam = nfsd->nd_nam;
847 char *dpos = nfsd->nd_dpos;
848 kauth_cred_t cred = nfsd->nd_cr;
849 struct iovec *ivp;
850 int i, cnt;
851 struct mbuf *mp;
852 struct nfs_fattr *fp;
853 struct iovec *iv;
854 struct vattr va, forat;
855 u_int32_t *tl;
856 int32_t t1;
857 char *bpos;
858 int error = 0, rdonly, cache = 0, len, forat_ret = 1;
859 int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
860 int stable = NFSV3WRITE_FILESYNC;
861 int v3 = (nfsd->nd_flag & ND_NFSV3);
862 char *cp2;
863 struct mbuf *mb, *mreq __unused;
864 struct vnode *vp;
865 nfsrvfh_t nsfh;
866 struct uio io, *uiop = &io;
867 off_t off;
868 u_quad_t frev;
869
870 if (mrep == NULL) {
871 *mrq = NULL;
872 return (0);
873 }
874 nfsm_srvmtofh(&nsfh);
875 if (v3) {
876 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
877 off = fxdr_hyper(tl);
878 tl += 3;
879 stable = fxdr_unsigned(int, *tl++);
880 } else {
881 nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
882 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
883 tl += 2;
884 }
885 retlen = len = fxdr_unsigned(int32_t, *tl);
886 cnt = i = 0;
887
888 /*
889 * For NFS Version 2, it is not obvious what a write of zero length
890 * should do, but I might as well be consistent with Version 3,
891 * which is to return ok so long as there are no permission problems.
892 */
893 if (len > 0) {
894 zeroing = 1;
895 mp = mrep;
896 while (mp) {
897 if (mp == md) {
898 zeroing = 0;
899 adjust = dpos - mtod(mp, char *);
900 mp->m_len -= adjust;
901 if (mp->m_len > 0 && adjust > 0)
902 NFSMADV(mp, adjust);
903 }
904 if (zeroing)
905 mp->m_len = 0;
906 else if (mp->m_len > 0) {
907 i += mp->m_len;
908 if (i > len) {
909 mp->m_len -= (i - len);
910 zeroing = 1;
911 }
912 if (mp->m_len > 0)
913 cnt++;
914 }
915 mp = mp->m_next;
916 }
917 }
918 if (len > NFS_MAXDATA || len < 0 || i < len) {
919 error = EIO;
920 nfsm_reply(2 * NFSX_UNSIGNED);
921 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
922 return (0);
923 }
924 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
925 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
926 if (error) {
927 nfsm_reply(2 * NFSX_UNSIGNED);
928 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
929 return (0);
930 }
931 if (v3)
932 forat_ret = VOP_GETATTR(vp, &forat, cred);
933 if (vp->v_type != VREG) {
934 if (v3)
935 error = EINVAL;
936 else
937 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
938 }
939 if (!error) {
940 nqsrv_getl(vp, ND_WRITE);
941 error = nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 1);
942 }
943 if (error) {
944 vput(vp);
945 nfsm_reply(NFSX_WCCDATA(v3));
946 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
947 return (0);
948 }
949
950 if (len > 0) {
951 ivp = malloc(cnt * sizeof (struct iovec), M_TEMP, M_WAITOK);
952 uiop->uio_iov = iv = ivp;
953 uiop->uio_iovcnt = cnt;
954 mp = mrep;
955 while (mp) {
956 if (mp->m_len > 0) {
957 ivp->iov_base = mtod(mp, void *);
958 ivp->iov_len = mp->m_len;
959 ivp++;
960 }
961 mp = mp->m_next;
962 }
963
964 /*
965 * XXX
966 * The IO_METASYNC flag indicates that all metadata (and not
967 * just enough to ensure data integrity) must be written to
968 * stable storage synchronously.
969 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
970 */
971 if (stable == NFSV3WRITE_UNSTABLE)
972 ioflags = IO_NODELOCKED;
973 else if (stable == NFSV3WRITE_DATASYNC)
974 ioflags = (IO_SYNC | IO_NODELOCKED);
975 else
976 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
977 uiop->uio_resid = len;
978 uiop->uio_rw = UIO_WRITE;
979 uiop->uio_offset = off;
980 UIO_SETUP_SYSSPACE(uiop);
981 error = VOP_WRITE(vp, uiop, ioflags, cred);
982 nfsstats.srvvop_writes++;
983 free(iv, M_TEMP);
984 }
985 aftat_ret = VOP_GETATTR(vp, &va, cred);
986 vput(vp);
987 if (!error)
988 error = aftat_ret;
989 nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
990 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
991 if (v3) {
992 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
993 if (error)
994 return (0);
995 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
996 *tl++ = txdr_unsigned(retlen);
997 if (stable == NFSV3WRITE_UNSTABLE)
998 *tl++ = txdr_unsigned(stable);
999 else
1000 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
1001 /*
1002 * Actually, there is no need to txdr these fields,
1003 * but it may make the values more human readable,
1004 * for debugging purposes.
1005 */
1006 *tl++ = txdr_unsigned(boottime.tv_sec);
1007 *tl = txdr_unsigned(boottime.tv_nsec / 1000);
1008 } else {
1009 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1010 nfsm_srvfillattr(&va, fp);
1011 }
1012 nfsm_srvdone;
1013 }
1014
1015 /*
1016 * XXX elad: the original NFSW_SAMECRED() macro also made sure the
1017 * two nd_flag fields of the descriptors contained
1018 * ND_KERBAUTH.
1019 */
1020 static int
1021 nfsrv_samecred(kauth_cred_t cred1, kauth_cred_t cred2)
1022 {
1023 int i, do_ngroups;
1024
1025 if (kauth_cred_geteuid(cred1) != kauth_cred_geteuid(cred2))
1026 return (0);
1027 if (kauth_cred_ngroups(cred1) != kauth_cred_ngroups(cred2))
1028 return (0);
1029 do_ngroups = kauth_cred_ngroups(cred1);
1030 for (i = 0; i < do_ngroups; i++)
1031 if (kauth_cred_group(cred1, i) !=
1032 kauth_cred_group(cred2, i))
1033 return (0);
1034
1035 return (1);
1036 }
1037
1038 static struct nfsrvw_delayhash *
1039 nfsrv_nwdelayhash(struct nfssvc_sock *slp, const nfsrvfh_t *nsfh)
1040 {
1041 uint32_t hash;
1042
1043 hash = hash32_buf(NFSRVFH_DATA(nsfh), NFSRVFH_SIZE(nsfh),
1044 HASH32_BUF_INIT);
1045 return &slp->ns_wdelayhashtbl[hash % NFS_WDELAYHASHSIZ];
1046 }
1047
1048 /*
1049 * NFS write service with write gathering support. Called when
1050 * nfsrvw_procrastinate > 0.
1051 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1052 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1053 * Jan. 1994.
1054 */
1055 int
1056 nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
1057 {
1058 struct timeval now;
1059 struct iovec *ivp;
1060 struct mbuf *mp;
1061 struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1062 struct nfs_fattr *fp;
1063 int i = 0;
1064 struct iovec *iov;
1065 struct nfsrvw_delayhash *wpp;
1066 kauth_cred_t cred;
1067 struct vattr va, forat;
1068 u_int32_t *tl;
1069 int32_t t1;
1070 char *bpos, *dpos;
1071 int error = 0, rdonly, cache = 0, len = 0, forat_ret = 1;
1072 int ioflags, aftat_ret = 1, adjust, v3, zeroing;
1073 char *cp2;
1074 struct mbuf *mb, *mreq, *mrep, *md;
1075 struct vnode *vp;
1076 struct uio io, *uiop = &io;
1077 u_quad_t frev, cur_usec;
1078
1079 *mrq = NULL;
1080 if (*ndp) {
1081 nfsd = *ndp;
1082 *ndp = NULL;
1083 mrep = nfsd->nd_mrep;
1084 md = nfsd->nd_md;
1085 dpos = nfsd->nd_dpos;
1086 cred = nfsd->nd_cr;
1087 v3 = (nfsd->nd_flag & ND_NFSV3);
1088 LIST_INIT(&nfsd->nd_coalesce);
1089 nfsd->nd_mreq = NULL;
1090 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1091 getmicrotime(&now);
1092 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1093 nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
1094
1095 /*
1096 * Now, get the write header..
1097 */
1098 nfsm_srvmtofh(&nfsd->nd_fh);
1099 if (v3) {
1100 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1101 nfsd->nd_off = fxdr_hyper(tl);
1102 tl += 3;
1103 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1104 } else {
1105 nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1106 nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1107 tl += 2;
1108 }
1109 len = fxdr_unsigned(int32_t, *tl);
1110 nfsd->nd_len = len;
1111 nfsd->nd_eoff = nfsd->nd_off + len;
1112
1113 /*
1114 * Trim the header out of the mbuf list and trim off any trailing
1115 * junk so that the mbuf list has only the write data.
1116 */
1117 zeroing = 1;
1118 i = 0;
1119 mp = mrep;
1120 while (mp) {
1121 if (mp == md) {
1122 zeroing = 0;
1123 adjust = dpos - mtod(mp, char *);
1124 mp->m_len -= adjust;
1125 if (mp->m_len > 0 && adjust > 0)
1126 NFSMADV(mp, adjust);
1127 }
1128 if (zeroing)
1129 mp->m_len = 0;
1130 else {
1131 i += mp->m_len;
1132 if (i > len) {
1133 mp->m_len -= (i - len);
1134 zeroing = 1;
1135 }
1136 }
1137 mp = mp->m_next;
1138 }
1139 if (len > NFS_MAXDATA || len < 0 || i < len) {
1140 nfsmout:
1141 m_freem(mrep);
1142 error = EIO;
1143 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1144 if (v3)
1145 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1146 nfsd->nd_mreq = mreq;
1147 nfsd->nd_mrep = NULL;
1148 nfsd->nd_time = 0;
1149 }
1150
1151 /*
1152 * Add this entry to the hash and time queues.
1153 */
1154 owp = NULL;
1155 mutex_enter(&nfsd_lock);
1156 wp = LIST_FIRST(&slp->ns_tq);
1157 while (wp && wp->nd_time < nfsd->nd_time) {
1158 owp = wp;
1159 wp = LIST_NEXT(wp, nd_tq);
1160 }
1161 if (owp) {
1162 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1163 } else {
1164 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1165 }
1166 if (nfsd->nd_mrep) {
1167 wpp = nfsrv_nwdelayhash(slp, &nfsd->nd_fh);
1168 owp = NULL;
1169 wp = LIST_FIRST(wpp);
1170 while (wp && nfsrv_comparefh(&nfsd->nd_fh, &wp->nd_fh)) {
1171 owp = wp;
1172 wp = LIST_NEXT(wp, nd_hash);
1173 }
1174 while (wp && wp->nd_off < nfsd->nd_off &&
1175 !nfsrv_comparefh(&nfsd->nd_fh, &wp->nd_fh)) {
1176 owp = wp;
1177 wp = LIST_NEXT(wp, nd_hash);
1178 }
1179 if (owp) {
1180 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1181
1182 /*
1183 * Search the hash list for overlapping entries and
1184 * coalesce.
1185 */
1186 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1187 wp = LIST_NEXT(nfsd, nd_hash);
1188 if (nfsrv_samecred(owp->nd_cr, nfsd->nd_cr))
1189 nfsrvw_coalesce(owp, nfsd);
1190 }
1191 } else {
1192 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1193 }
1194 }
1195 mutex_exit(&nfsd_lock);
1196 }
1197
1198 /*
1199 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1200 * and generate the associated reply mbuf list(s).
1201 */
1202 loop1:
1203 getmicrotime(&now);
1204 cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec;
1205 mutex_enter(&nfsd_lock);
1206 for (nfsd = LIST_FIRST(&slp->ns_tq); nfsd; nfsd = owp) {
1207 owp = LIST_NEXT(nfsd, nd_tq);
1208 if (nfsd->nd_time > cur_usec)
1209 break;
1210 if (nfsd->nd_mreq)
1211 continue;
1212 LIST_REMOVE(nfsd, nd_tq);
1213 LIST_REMOVE(nfsd, nd_hash);
1214 mutex_exit(&nfsd_lock);
1215
1216 mrep = nfsd->nd_mrep;
1217 nfsd->nd_mrep = NULL;
1218 cred = nfsd->nd_cr;
1219 v3 = (nfsd->nd_flag & ND_NFSV3);
1220 forat_ret = aftat_ret = 1;
1221 error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1222 nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH),
1223 false);
1224 if (!error) {
1225 if (v3)
1226 forat_ret = VOP_GETATTR(vp, &forat, cred);
1227 if (vp->v_type != VREG) {
1228 if (v3)
1229 error = EINVAL;
1230 else
1231 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1232 }
1233 } else
1234 vp = NULL;
1235 if (!error) {
1236 nqsrv_getl(vp, ND_WRITE);
1237 error = nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 1);
1238 }
1239
1240 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1241 ioflags = IO_NODELOCKED;
1242 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1243 ioflags = (IO_SYNC | IO_NODELOCKED);
1244 else
1245 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1246 uiop->uio_rw = UIO_WRITE;
1247 uiop->uio_offset = nfsd->nd_off;
1248 uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1249 UIO_SETUP_SYSSPACE(uiop);
1250 if (uiop->uio_resid > 0) {
1251 mp = mrep;
1252 i = 0;
1253 while (mp) {
1254 if (mp->m_len > 0)
1255 i++;
1256 mp = mp->m_next;
1257 }
1258 uiop->uio_iovcnt = i;
1259 iov = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK);
1260 uiop->uio_iov = ivp = iov;
1261 mp = mrep;
1262 while (mp) {
1263 if (mp->m_len > 0) {
1264 ivp->iov_base = mtod(mp, void *);
1265 ivp->iov_len = mp->m_len;
1266 ivp++;
1267 }
1268 mp = mp->m_next;
1269 }
1270 if (!error) {
1271 error = VOP_WRITE(vp, uiop, ioflags, cred);
1272 nfsstats.srvvop_writes++;
1273 }
1274 free((void *)iov, M_TEMP);
1275 }
1276 m_freem(mrep);
1277 if (vp) {
1278 aftat_ret = VOP_GETATTR(vp, &va, cred);
1279 vput(vp);
1280 }
1281
1282 /*
1283 * Loop around generating replies for all write rpcs that have
1284 * now been completed.
1285 */
1286 swp = nfsd;
1287 do {
1288 if (error) {
1289 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1290 if (v3) {
1291 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1292 }
1293 } else {
1294 nfsm_writereply(NFSX_PREOPATTR(v3) +
1295 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1296 NFSX_WRITEVERF(v3), v3);
1297 if (v3) {
1298 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1299 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1300 *tl++ = txdr_unsigned(nfsd->nd_len);
1301 *tl++ = txdr_unsigned(swp->nd_stable);
1302 /*
1303 * Actually, there is no need to txdr these fields,
1304 * but it may make the values more human readable,
1305 * for debugging purposes.
1306 */
1307 *tl++ = txdr_unsigned(boottime.tv_sec);
1308 *tl = txdr_unsigned(boottime.tv_nsec / 1000);
1309 } else {
1310 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1311 nfsm_srvfillattr(&va, fp);
1312 }
1313 }
1314 nfsd->nd_mreq = mreq;
1315 if (nfsd->nd_mrep)
1316 panic("nfsrv_write: nd_mrep not free");
1317
1318 /*
1319 * Done. Put it at the head of the timer queue so that
1320 * the final phase can return the reply.
1321 */
1322 mutex_enter(&nfsd_lock);
1323 if (nfsd != swp) {
1324 nfsd->nd_time = 0;
1325 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1326 }
1327 nfsd = LIST_FIRST(&swp->nd_coalesce);
1328 if (nfsd) {
1329 LIST_REMOVE(nfsd, nd_tq);
1330 }
1331 mutex_exit(&nfsd_lock);
1332 } while (nfsd);
1333 swp->nd_time = 0;
1334
1335 mutex_enter(&nfsd_lock);
1336 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1337 mutex_exit(&nfsd_lock);
1338 goto loop1;
1339 }
1340 mutex_exit(&nfsd_lock);
1341 nfs_timer_start();
1342
1343 /*
1344 * Search for a reply to return.
1345 */
1346 mutex_enter(&nfsd_lock);
1347 LIST_FOREACH(nfsd, &slp->ns_tq, nd_tq) {
1348 if (nfsd->nd_mreq) {
1349 LIST_REMOVE(nfsd, nd_tq);
1350 *mrq = nfsd->nd_mreq;
1351 *ndp = nfsd;
1352 break;
1353 }
1354 }
1355 mutex_exit(&nfsd_lock);
1356 return (0);
1357 }
1358
1359 /*
1360 * Coalesce the write request nfsd into owp. To do this we must:
1361 * - remove nfsd from the queues
1362 * - merge nfsd->nd_mrep into owp->nd_mrep
1363 * - update the nd_eoff and nd_stable for owp
1364 * - put nfsd on owp's nd_coalesce list
1365 * NB: Must be called at splsoftclock().
1366 */
1367 void
1368 nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd)
1369 {
1370 int overlap;
1371 struct mbuf *mp;
1372 struct nfsrv_descript *m;
1373
1374 KASSERT(mutex_owned(&nfsd_lock));
1375
1376 LIST_REMOVE(nfsd, nd_hash);
1377 LIST_REMOVE(nfsd, nd_tq);
1378 if (owp->nd_eoff < nfsd->nd_eoff) {
1379 overlap = owp->nd_eoff - nfsd->nd_off;
1380 if (overlap < 0)
1381 panic("nfsrv_coalesce: bad off");
1382 if (overlap > 0)
1383 m_adj(nfsd->nd_mrep, overlap);
1384 mp = owp->nd_mrep;
1385 while (mp->m_next)
1386 mp = mp->m_next;
1387 mp->m_next = nfsd->nd_mrep;
1388 owp->nd_eoff = nfsd->nd_eoff;
1389 } else
1390 m_freem(nfsd->nd_mrep);
1391 nfsd->nd_mrep = NULL;
1392 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1393 owp->nd_stable = NFSV3WRITE_FILESYNC;
1394 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1395 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1396 owp->nd_stable = NFSV3WRITE_DATASYNC;
1397 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1398 /*
1399 * nfsd might hold coalesce elements! Move them to owp.
1400 * Otherwise, requests may be lost and clients will be stuck.
1401 */
1402 while ((m = LIST_FIRST(&nfsd->nd_coalesce)) != NULL) {
1403 LIST_REMOVE(m, nd_tq);
1404 LIST_INSERT_HEAD(&owp->nd_coalesce, m, nd_tq);
1405 }
1406 }
1407
1408 /*
1409 * nfs create service
1410 * now does a truncate to 0 length via. setattr if it already exists
1411 */
1412 int
1413 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
1414 {
1415 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1416 struct mbuf *nam = nfsd->nd_nam;
1417 char *dpos = nfsd->nd_dpos;
1418 kauth_cred_t cred = nfsd->nd_cr;
1419 struct nfs_fattr *fp;
1420 struct vattr va, dirfor, diraft;
1421 struct nfsv2_sattr *sp;
1422 u_int32_t *tl;
1423 struct nameidata nd;
1424 char *cp;
1425 int32_t t1;
1426 char *bpos;
1427 int error = 0, cache = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1428 int rdev = 0, abort = 0;
1429 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1430 char *cp2;
1431 struct mbuf *mb, *mreq __unused;
1432 struct vnode *vp = NULL, *dirp = NULL;
1433 nfsrvfh_t nsfh;
1434 u_quad_t frev, tempsize;
1435 u_char cverf[NFSX_V3CREATEVERF];
1436
1437 nd.ni_cnd.cn_nameiop = 0;
1438 nfsm_srvmtofh(&nsfh);
1439 nfsm_srvnamesiz(len);
1440 nd.ni_cnd.cn_cred = cred;
1441 nd.ni_cnd.cn_nameiop = CREATE;
1442 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1443 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
1444 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
1445 if (dirp && v3) {
1446 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
1447 }
1448 if (error) {
1449 nfsm_reply(NFSX_WCCDATA(v3));
1450 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1451 if (dirp)
1452 vrele(dirp);
1453 if (nd.ni_pathbuf != NULL) {
1454 pathbuf_destroy(nd.ni_pathbuf);
1455 nd.ni_pathbuf = NULL;
1456 }
1457 return (0);
1458 }
1459 abort = 1;
1460 vattr_null(&va);
1461 if (v3) {
1462 va.va_mode = 0;
1463 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1464 how = fxdr_unsigned(int, *tl);
1465 switch (how) {
1466 case NFSV3CREATE_GUARDED:
1467 if (nd.ni_vp) {
1468 error = EEXIST;
1469 break;
1470 }
1471 /* FALLTHROUGH */
1472 case NFSV3CREATE_UNCHECKED:
1473 nfsm_srvsattr(&va);
1474 break;
1475 case NFSV3CREATE_EXCLUSIVE:
1476 nfsm_dissect(cp, void *, NFSX_V3CREATEVERF);
1477 memcpy(cverf, cp, NFSX_V3CREATEVERF);
1478 exclusive_flag = 1;
1479 break;
1480 };
1481 va.va_type = VREG;
1482 } else {
1483 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1484 va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1485 if (va.va_type == VNON)
1486 va.va_type = VREG;
1487 va.va_mode = nfstov_mode(sp->sa_mode);
1488 switch (va.va_type) {
1489 case VREG:
1490 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1491 if (tsize != -1)
1492 va.va_size = (u_quad_t)tsize;
1493 break;
1494 case VCHR:
1495 case VBLK:
1496 case VFIFO:
1497 rdev = fxdr_unsigned(int32_t, sp->sa_size);
1498 break;
1499 default:
1500 break;
1501 };
1502 }
1503
1504 /*
1505 * Iff doesn't exist, create it
1506 * otherwise just truncate to 0 length
1507 * should I set the mode too ??
1508 */
1509 if (nd.ni_vp == NULL) {
1510 if (va.va_type == VREG || va.va_type == VSOCK) {
1511 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1512 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1513 if (!error) {
1514 vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY);
1515 if (exclusive_flag) {
1516 exclusive_flag = 0;
1517 vattr_null(&va);
1518 /*
1519 * XXX
1520 * assuming NFSX_V3CREATEVERF
1521 * == sizeof(nfstime3)
1522 */
1523 fxdr_nfsv3time(cverf, &va.va_atime);
1524 error = VOP_SETATTR(nd.ni_vp, &va,
1525 cred);
1526 }
1527 }
1528 } else if (va.va_type == VCHR || va.va_type == VBLK ||
1529 va.va_type == VFIFO) {
1530 if (va.va_type == VCHR && rdev == 0xffffffff)
1531 va.va_type = VFIFO;
1532 if (va.va_type != VFIFO &&
1533 (error = kauth_authorize_system(cred,
1534 KAUTH_SYSTEM_MKNOD, 0, NULL, NULL, NULL))) {
1535 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1536 vput(nd.ni_dvp);
1537 abort = 0;
1538 nfsm_reply(0);
1539 if (nd.ni_pathbuf != NULL) {
1540 pathbuf_destroy(nd.ni_pathbuf);
1541 nd.ni_pathbuf = NULL;
1542 }
1543 return (error);
1544 } else
1545 va.va_rdev = (dev_t)rdev;
1546 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1547 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1548 &va);
1549 if (!error) {
1550 vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY);
1551 } else {
1552 nfsm_reply(0);
1553 }
1554 } else {
1555 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1556 if (nd.ni_pathbuf != NULL) {
1557 pathbuf_destroy(nd.ni_pathbuf);
1558 nd.ni_pathbuf = NULL;
1559 }
1560 error = ENXIO;
1561 abort = 0;
1562 }
1563 vp = nd.ni_vp;
1564 } else {
1565 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1566 if (nd.ni_pathbuf != NULL) {
1567 pathbuf_destroy(nd.ni_pathbuf);
1568 nd.ni_pathbuf = NULL;
1569 }
1570 vp = nd.ni_vp;
1571 abort = 0;
1572 if (!error && va.va_size != -1) {
1573 error = nfsrv_access(vp, VWRITE, cred,
1574 (nd.ni_cnd.cn_flags & RDONLY), lwp, 0);
1575 if (!error) {
1576 nqsrv_getl(vp, ND_WRITE);
1577 tempsize = va.va_size;
1578 vattr_null(&va);
1579 va.va_size = tempsize;
1580 error = VOP_SETATTR(vp, &va, cred);
1581 }
1582 }
1583 if (error)
1584 vput(vp);
1585 }
1586 if (!error) {
1587 error = nfsrv_composefh(vp, &nsfh, v3);
1588 if (!error)
1589 error = VOP_GETATTR(vp, &va, cred);
1590 vput(vp);
1591 }
1592 if (nd.ni_dvp == vp)
1593 vrele(nd.ni_dvp);
1594 else
1595 vput(nd.ni_dvp);
1596 if (v3) {
1597 if (exclusive_flag && !error) {
1598 /*
1599 * XXX assuming NFSX_V3CREATEVERF == sizeof(nfstime3)
1600 */
1601 char oldverf[NFSX_V3CREATEVERF];
1602
1603 txdr_nfsv3time(&va.va_atime, oldverf);
1604 if (memcmp(cverf, oldverf, NFSX_V3CREATEVERF))
1605 error = EEXIST;
1606 }
1607 if (dirp) {
1608 vn_lock(dirp, LK_SHARED | LK_RETRY);
1609 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
1610 VOP_UNLOCK(dirp);
1611 }
1612 }
1613 if (dirp) {
1614 vrele(dirp);
1615 dirp = NULL;
1616 }
1617 if (nd.ni_pathbuf != NULL) {
1618 pathbuf_destroy(nd.ni_pathbuf);
1619 nd.ni_pathbuf = NULL;
1620 }
1621 abort = 0;
1622 nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1623 if (v3) {
1624 if (!error) {
1625 nfsm_srvpostop_fh(&nsfh);
1626 nfsm_srvpostop_attr(0, &va);
1627 }
1628 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1629 } else {
1630 nfsm_srvfhtom(&nsfh, v3);
1631 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1632 nfsm_srvfillattr(&va, fp);
1633 }
1634 return (0);
1635 nfsmout:
1636 if (dirp)
1637 vrele(dirp);
1638 if (abort) {
1639 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1640 if (nd.ni_dvp == nd.ni_vp)
1641 vrele(nd.ni_dvp);
1642 else
1643 vput(nd.ni_dvp);
1644 if (nd.ni_vp)
1645 vput(nd.ni_vp);
1646 if (nd.ni_pathbuf != NULL) {
1647 pathbuf_destroy(nd.ni_pathbuf);
1648 nd.ni_pathbuf = NULL;
1649 }
1650 }
1651 return (error);
1652 }
1653
1654 /*
1655 * nfs v3 mknod service
1656 */
1657 int
1658 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
1659 {
1660 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1661 struct mbuf *nam = nfsd->nd_nam;
1662 char *dpos = nfsd->nd_dpos;
1663 kauth_cred_t cred = nfsd->nd_cr;
1664 struct vattr va, dirfor, diraft;
1665 u_int32_t *tl;
1666 struct nameidata nd;
1667 int32_t t1;
1668 char *bpos;
1669 int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
1670 int abort = 0;
1671 u_int32_t major, minor;
1672 enum vtype vtyp;
1673 char *cp2;
1674 struct mbuf *mb, *mreq __unused;
1675 struct vnode *vp, *dirp = (struct vnode *)0;
1676 nfsrvfh_t nsfh;
1677 u_quad_t frev;
1678
1679 nd.ni_cnd.cn_nameiop = 0;
1680 nfsm_srvmtofh(&nsfh);
1681 nfsm_srvnamesiz(len);
1682 nd.ni_cnd.cn_cred = cred;
1683 nd.ni_cnd.cn_nameiop = CREATE;
1684 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1685 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
1686 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
1687 if (dirp)
1688 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
1689 if (error) {
1690 nfsm_reply(NFSX_WCCDATA(1));
1691 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1692 if (dirp)
1693 vrele(dirp);
1694 if (nd.ni_pathbuf != NULL) {
1695 pathbuf_destroy(nd.ni_pathbuf);
1696 nd.ni_pathbuf = NULL;
1697 }
1698 return (0);
1699 }
1700 abort = 1;
1701 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1702 vtyp = nfsv3tov_type(*tl);
1703 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1704 error = NFSERR_BADTYPE;
1705 goto abort;
1706 }
1707 vattr_null(&va);
1708 va.va_mode = 0;
1709 nfsm_srvsattr(&va);
1710 if (vtyp == VCHR || vtyp == VBLK) {
1711 dev_t rdev;
1712
1713 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1714 major = fxdr_unsigned(u_int32_t, *tl++);
1715 minor = fxdr_unsigned(u_int32_t, *tl);
1716 rdev = makedev(major, minor);
1717 if (major(rdev) != major || minor(rdev) != minor) {
1718 error = EINVAL;
1719 goto abort;
1720 }
1721 va.va_rdev = rdev;
1722 }
1723
1724 /*
1725 * Iff doesn't exist, create it.
1726 */
1727 if (nd.ni_vp) {
1728 error = EEXIST;
1729 abort:
1730 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1731 if (nd.ni_vp)
1732 vput(nd.ni_vp);
1733 if (nd.ni_pathbuf != NULL) {
1734 pathbuf_destroy(nd.ni_pathbuf);
1735 nd.ni_pathbuf = NULL;
1736 }
1737 goto out;
1738 }
1739 va.va_type = vtyp;
1740 if (vtyp == VSOCK) {
1741 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1742 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1743 } else {
1744 if (va.va_type != VFIFO &&
1745 (error = kauth_authorize_system(cred,
1746 KAUTH_SYSTEM_MKNOD, 0, NULL, NULL, NULL))) {
1747 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1748 vput(nd.ni_dvp);
1749 goto out;
1750 }
1751 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1752 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1753 if (error)
1754 goto out;
1755 }
1756 if (!error) {
1757 vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY);
1758 }
1759 out:
1760 vp = nd.ni_vp;
1761 if (!error) {
1762 error = nfsrv_composefh(vp, &nsfh, true);
1763 if (!error)
1764 error = VOP_GETATTR(vp, &va, cred);
1765 vput(vp);
1766 }
1767 if (nd.ni_dvp == nd.ni_vp)
1768 vrele(nd.ni_dvp);
1769 else
1770 vput(nd.ni_dvp);
1771 if (dirp) {
1772 vn_lock(dirp, LK_SHARED | LK_RETRY);
1773 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
1774 VOP_UNLOCK(dirp);
1775 vrele(dirp);
1776 dirp = NULL;
1777 }
1778 if (nd.ni_pathbuf != NULL) {
1779 pathbuf_destroy(nd.ni_pathbuf);
1780 nd.ni_pathbuf = NULL;
1781 }
1782 abort = 0;
1783 nfsm_reply(NFSX_SRVFH(&nsfh, true) + NFSX_POSTOPATTR(1) +
1784 NFSX_WCCDATA(1));
1785 if (!error) {
1786 nfsm_srvpostop_fh(&nsfh);
1787 nfsm_srvpostop_attr(0, &va);
1788 }
1789 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1790 return (0);
1791 nfsmout:
1792 if (abort) {
1793 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1794 if (nd.ni_dvp == nd.ni_vp)
1795 vrele(nd.ni_dvp);
1796 else
1797 vput(nd.ni_dvp);
1798 if (nd.ni_vp)
1799 vput(nd.ni_vp);
1800 if (nd.ni_pathbuf != NULL) {
1801 pathbuf_destroy(nd.ni_pathbuf);
1802 nd.ni_pathbuf = NULL;
1803 }
1804 }
1805 if (dirp)
1806 vrele(dirp);
1807 return (error);
1808 }
1809
1810 /*
1811 * nfs remove service
1812 */
1813 int
1814 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
1815 {
1816 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1817 struct mbuf *nam = nfsd->nd_nam;
1818 char *dpos = nfsd->nd_dpos;
1819 kauth_cred_t cred = nfsd->nd_cr;
1820 struct nameidata nd;
1821 u_int32_t *tl;
1822 int32_t t1;
1823 char *bpos;
1824 int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
1825 int v3 = (nfsd->nd_flag & ND_NFSV3);
1826 char *cp2;
1827 struct mbuf *mb, *mreq __unused;
1828 struct vnode *vp, *dirp;
1829 struct vattr dirfor, diraft;
1830 nfsrvfh_t nsfh;
1831 u_quad_t frev;
1832
1833 #ifndef nolint
1834 vp = (struct vnode *)0;
1835 #endif
1836 nfsm_srvmtofh(&nsfh);
1837 nfsm_srvnamesiz(len);
1838 nd.ni_cnd.cn_cred = cred;
1839 nd.ni_cnd.cn_nameiop = DELETE;
1840 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1841 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
1842 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
1843 if (error == 0 && dirp && v3) {
1844 if (nd.ni_dvp == nd.ni_vp)
1845 vn_lock(dirp, LK_SHARED | LK_RETRY);
1846 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
1847 if (nd.ni_dvp == nd.ni_vp)
1848 VOP_UNLOCK(dirp);
1849 }
1850 if (!error) {
1851 vp = nd.ni_vp;
1852 if (vp->v_type == VDIR) {
1853 error = EPERM;
1854 goto out;
1855 }
1856 /*
1857 * The root of a mounted filesystem cannot be deleted.
1858 */
1859 if (vp->v_vflag & VV_ROOT) {
1860 error = EBUSY;
1861 }
1862 out:
1863 if (!error) {
1864 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1865 nqsrv_getl(vp, ND_WRITE);
1866 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1867 vput(nd.ni_dvp);
1868 } else {
1869 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1870 if (nd.ni_dvp == vp)
1871 vrele(nd.ni_dvp);
1872 else
1873 vput(nd.ni_dvp);
1874 vput(vp);
1875 }
1876 }
1877 if (nd.ni_pathbuf != NULL) {
1878 pathbuf_destroy(nd.ni_pathbuf);
1879 nd.ni_pathbuf = NULL;
1880 }
1881 if (dirp) {
1882 if (v3) {
1883 vn_lock(dirp, LK_SHARED | LK_RETRY);
1884 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
1885 VOP_UNLOCK(dirp);
1886 }
1887 vrele(dirp);
1888 }
1889 nfsm_reply(NFSX_WCCDATA(v3));
1890 if (v3) {
1891 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1892 return (0);
1893 }
1894 nfsm_srvdone;
1895 }
1896
1897 /*
1898 * nfs rename service
1899 */
1900 int
1901 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
1902 {
1903 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1904 struct mbuf *nam = nfsd->nd_nam;
1905 char *dpos = nfsd->nd_dpos;
1906 kauth_cred_t cred = nfsd->nd_cr;
1907 u_int32_t *tl;
1908 int32_t t1;
1909 char *bpos;
1910 int error = 0, cache = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1911 uint32_t len, len2;
1912 int tdirfor_ret = 1, tdiraft_ret = 1;
1913 int v3 = (nfsd->nd_flag & ND_NFSV3);
1914 char *cp2;
1915 struct mbuf *mb, *mreq __unused;
1916 struct nameidata fromnd, tond;
1917 struct vnode *fvp, *tvp, *tdvp;
1918 struct vnode *fdirp = NULL, *tdirp = NULL;
1919 struct mount *localfs = NULL;
1920 struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1921 nfsrvfh_t fnsfh, tnsfh;
1922 u_quad_t frev;
1923 uid_t saved_uid;
1924
1925 #ifndef nolint
1926 fvp = (struct vnode *)0;
1927 #endif
1928 fromnd.ni_cnd.cn_nameiop = 0;
1929 tond.ni_cnd.cn_nameiop = 0;
1930 nfsm_srvmtofh(&fnsfh);
1931 nfsm_srvnamesiz(len);
1932 /*
1933 * Remember our original uid so that we can reset cr_uid before
1934 * the second nfs_namei() call, in case it is remapped.
1935 */
1936 saved_uid = kauth_cred_geteuid(cred);
1937 fromnd.ni_cnd.cn_cred = cred;
1938 fromnd.ni_cnd.cn_nameiop = DELETE;
1939 fromnd.ni_cnd.cn_flags = LOCKPARENT;
1940 error = nfs_namei(&fromnd, &fnsfh, len, slp, nam, &md,
1941 &dpos, &fdirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
1942 if (error == 0 && fdirp && v3) {
1943 if (fromnd.ni_dvp == fromnd.ni_vp)
1944 vn_lock(fdirp, LK_SHARED | LK_RETRY);
1945 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred);
1946 if (fromnd.ni_dvp == fromnd.ni_vp)
1947 VOP_UNLOCK(fdirp);
1948 }
1949 if (error) {
1950 fromnd.ni_cnd.cn_nameiop = 0;
1951 nfsm_reply(2 * NFSX_WCCDATA(v3));
1952 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1953 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1954 if (fdirp)
1955 vrele(fdirp);
1956 if (fromnd.ni_pathbuf != NULL) {
1957 pathbuf_destroy(fromnd.ni_pathbuf);
1958 }
1959 return (0);
1960 }
1961 localfs = fromnd.ni_dvp->v_mount;
1962 fstrans_start(localfs);
1963 if (fromnd.ni_dvp != fromnd.ni_vp) {
1964 VOP_UNLOCK(fromnd.ni_dvp);
1965 }
1966 fvp = fromnd.ni_vp;
1967
1968 error = VFS_RENAMELOCK_ENTER(localfs);
1969 if (error) {
1970 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1971 vrele(fromnd.ni_dvp);
1972 vrele(fvp);
1973 goto out1;
1974 }
1975
1976 /* Copied, regrettably, from vfs_syscalls.c (q.v.) */
1977 vrele(fvp);
1978 if ((fromnd.ni_cnd.cn_namelen == 1 &&
1979 fromnd.ni_cnd.cn_nameptr[0] == '.') ||
1980 (fromnd.ni_cnd.cn_namelen == 2 &&
1981 fromnd.ni_cnd.cn_nameptr[0] == '.' &&
1982 fromnd.ni_cnd.cn_nameptr[1] == '.')) {
1983 error = EINVAL;
1984 VFS_RENAMELOCK_EXIT(localfs);
1985 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1986 vrele(fromnd.ni_dvp);
1987 goto out1;
1988 }
1989 vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY);
1990 error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd, 0);
1991 if (error) {
1992 VOP_UNLOCK(fromnd.ni_dvp);
1993 VFS_RENAMELOCK_EXIT(localfs);
1994 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1995 vrele(fromnd.ni_dvp);
1996 goto out1;
1997 }
1998 VOP_UNLOCK(fromnd.ni_vp);
1999 if (fromnd.ni_dvp != fromnd.ni_vp)
2000 VOP_UNLOCK(fromnd.ni_dvp);
2001 fvp = fromnd.ni_vp;
2002
2003 nfsm_srvmtofh(&tnsfh);
2004 if (v3) {
2005 nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
2006 len2 = fxdr_unsigned(uint32_t, *tl);
2007 /* len2 will be checked by nfs_namei */
2008 }
2009 else {
2010 /* NFSv2 */
2011 nfsm_strsiz(len2, NFS_MAXNAMLEN);
2012 }
2013 kauth_cred_seteuid(cred, saved_uid);
2014 tond.ni_cnd.cn_cred = cred;
2015 tond.ni_cnd.cn_nameiop = RENAME;
2016 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE;
2017 error = nfs_namei(&tond, &tnsfh, len2, slp, nam, &md,
2018 &dpos, &tdirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2019 if (tdirp && v3) {
2020 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred);
2021 }
2022 if (error) {
2023 VFS_RENAMELOCK_EXIT(localfs);
2024 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2025 vrele(fromnd.ni_dvp);
2026 vrele(fvp);
2027 goto out1;
2028 }
2029 tdvp = tond.ni_dvp;
2030 tvp = tond.ni_vp;
2031 if (tvp != NULL) {
2032 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2033 if (v3)
2034 error = EEXIST;
2035 else
2036 error = EISDIR;
2037 goto out;
2038 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2039 if (v3)
2040 error = EEXIST;
2041 else
2042 error = ENOTDIR;
2043 goto out;
2044 }
2045 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
2046 if (v3)
2047 error = EXDEV;
2048 else
2049 error = ENOTEMPTY;
2050 goto out;
2051 }
2052 }
2053 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
2054 if (v3)
2055 error = EXDEV;
2056 else
2057 error = ENOTEMPTY;
2058 goto out;
2059 }
2060 if (fvp->v_mount != tdvp->v_mount) {
2061 if (v3)
2062 error = EXDEV;
2063 else
2064 error = ENOTEMPTY;
2065 goto out;
2066 }
2067 if (fvp == tdvp) {
2068 if (v3)
2069 error = EINVAL;
2070 else
2071 error = ENOTEMPTY;
2072 }
2073 /*
2074 * If source is the same as the destination (that is the
2075 * same vnode with the same name in the same directory),
2076 * then there is nothing to do.
2077 */
2078 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2079 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2080 !memcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2081 fromnd.ni_cnd.cn_namelen))
2082 error = -1;
2083 out:
2084 if (!error) {
2085 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
2086 nqsrv_getl(tdvp, ND_WRITE);
2087 if (tvp) {
2088 nqsrv_getl(tvp, ND_WRITE);
2089 }
2090 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2091 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2092 VFS_RENAMELOCK_EXIT(localfs);
2093 } else {
2094 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2095 if (tdvp == tvp)
2096 vrele(tdvp);
2097 else
2098 vput(tdvp);
2099 if (tvp)
2100 vput(tvp);
2101 VFS_RENAMELOCK_EXIT(localfs);
2102 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2103 vrele(fromnd.ni_dvp);
2104 vrele(fvp);
2105 if (error == -1)
2106 error = 0;
2107 }
2108 if (tond.ni_pathbuf != NULL) {
2109 pathbuf_destroy(tond.ni_pathbuf);
2110 tond.ni_pathbuf = NULL;
2111 }
2112 tond.ni_cnd.cn_nameiop = 0;
2113 out1:
2114 if (fdirp) {
2115 if (v3) {
2116 vn_lock(fdirp, LK_SHARED | LK_RETRY);
2117 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred);
2118 VOP_UNLOCK(fdirp);
2119 }
2120 vrele(fdirp);
2121 fdirp = NULL;
2122 }
2123 if (tdirp) {
2124 if (v3) {
2125 vn_lock(tdirp, LK_SHARED | LK_RETRY);
2126 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred);
2127 VOP_UNLOCK(tdirp);
2128 }
2129 vrele(tdirp);
2130 tdirp = NULL;
2131 }
2132 pathbuf_destroy(fromnd.ni_pathbuf);
2133 fromnd.ni_pathbuf = NULL;
2134 fromnd.ni_cnd.cn_nameiop = 0;
2135 fstrans_done(localfs);
2136 localfs = NULL;
2137 nfsm_reply(2 * NFSX_WCCDATA(v3));
2138 if (v3) {
2139 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2140 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2141 }
2142 return (0);
2143
2144 nfsmout:
2145 if (fdirp)
2146 vrele(fdirp);
2147 #ifdef notdef
2148 if (tdirp)
2149 vrele(tdirp);
2150 #endif
2151 if (tond.ni_cnd.cn_nameiop) {
2152 if (tond.ni_pathbuf != NULL) {
2153 pathbuf_destroy(tond.ni_pathbuf);
2154 tond.ni_pathbuf = NULL;
2155 }
2156 }
2157 if (localfs) {
2158 VFS_RENAMELOCK_EXIT(localfs);
2159 fstrans_done(localfs);
2160 }
2161 if (fromnd.ni_cnd.cn_nameiop) {
2162 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2163 if (fromnd.ni_pathbuf != NULL) {
2164 pathbuf_destroy(fromnd.ni_pathbuf);
2165 fromnd.ni_pathbuf = NULL;
2166 }
2167 vrele(fromnd.ni_dvp);
2168 vrele(fvp);
2169 }
2170 return (error);
2171 }
2172
2173 /*
2174 * nfs link service
2175 */
2176 int
2177 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2178 {
2179 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2180 struct mbuf *nam = nfsd->nd_nam;
2181 char *dpos = nfsd->nd_dpos;
2182 kauth_cred_t cred = nfsd->nd_cr;
2183 struct nameidata nd;
2184 u_int32_t *tl;
2185 int32_t t1;
2186 char *bpos;
2187 int error = 0, rdonly, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
2188 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2189 char *cp2;
2190 struct mbuf *mb, *mreq __unused;
2191 struct vnode *vp, *xp, *dirp = (struct vnode *)0;
2192 struct vattr dirfor, diraft, at;
2193 nfsrvfh_t nsfh, dnsfh;
2194 u_quad_t frev;
2195
2196 nfsm_srvmtofh(&nsfh);
2197 nfsm_srvmtofh(&dnsfh);
2198 nfsm_srvnamesiz(len);
2199 error = nfsrv_fhtovp(&nsfh, false, &vp, cred, slp, nam,
2200 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
2201 if (error) {
2202 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2203 nfsm_srvpostop_attr(getret, &at);
2204 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2205 return (0);
2206 }
2207 if (vp->v_type == VDIR) {
2208 error = EPERM;
2209 goto out1;
2210 }
2211 nd.ni_cnd.cn_cred = cred;
2212 nd.ni_cnd.cn_nameiop = CREATE;
2213 nd.ni_cnd.cn_flags = LOCKPARENT;
2214 error = nfs_namei(&nd, &dnsfh, len, slp, nam, &md, &dpos,
2215 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2216 if (dirp && v3) {
2217 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2218 }
2219 if (error)
2220 goto out1;
2221 xp = nd.ni_vp;
2222 if (xp != NULL) {
2223 error = EEXIST;
2224 goto out;
2225 }
2226 xp = nd.ni_dvp;
2227 if (vp->v_mount != xp->v_mount)
2228 error = EXDEV;
2229 out:
2230 if (!error) {
2231 nqsrv_getl(vp, ND_WRITE);
2232 nqsrv_getl(xp, ND_WRITE);
2233 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
2234 if (nd.ni_dvp != nd.ni_vp)
2235 VOP_UNLOCK(nd.ni_dvp);
2236 vrele(nd.ni_dvp);
2237 } else {
2238 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2239 if (nd.ni_dvp == nd.ni_vp)
2240 vrele(nd.ni_dvp);
2241 else
2242 vput(nd.ni_dvp);
2243 if (nd.ni_vp)
2244 vrele(nd.ni_vp);
2245 }
2246 out1:
2247 if (v3) {
2248 vn_lock(vp, LK_SHARED | LK_RETRY);
2249 getret = VOP_GETATTR(vp, &at, cred);
2250 VOP_UNLOCK(vp);
2251 }
2252 if (dirp) {
2253 if (v3) {
2254 vn_lock(dirp, LK_SHARED | LK_RETRY);
2255 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2256 VOP_UNLOCK(dirp);
2257 }
2258 vrele(dirp);
2259 }
2260 vrele(vp);
2261 if (nd.ni_pathbuf != NULL) {
2262 pathbuf_destroy(nd.ni_pathbuf);
2263 nd.ni_pathbuf = NULL;
2264 }
2265 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2266 if (v3) {
2267 nfsm_srvpostop_attr(getret, &at);
2268 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2269 return (0);
2270 }
2271 nfsm_srvdone;
2272 }
2273
2274 /*
2275 * nfs symbolic link service
2276 */
2277 int
2278 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2279 {
2280 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2281 struct mbuf *nam = nfsd->nd_nam;
2282 char *dpos = nfsd->nd_dpos;
2283 kauth_cred_t cred = nfsd->nd_cr;
2284 struct vattr va, dirfor, diraft;
2285 struct nameidata nd;
2286 u_int32_t *tl;
2287 int32_t t1;
2288 struct nfsv2_sattr *sp;
2289 char *bpos, *pathcp = NULL, *cp2;
2290 struct uio io;
2291 struct iovec iv;
2292 int error = 0, cache = 0, dirfor_ret = 1, diraft_ret = 1, abort = 0;
2293 uint32_t len, len2;
2294 int v3 = (nfsd->nd_flag & ND_NFSV3);
2295 struct mbuf *mb, *mreq __unused;
2296 struct vnode *dirp = (struct vnode *)0;
2297 nfsrvfh_t nsfh;
2298 u_quad_t frev;
2299
2300 nd.ni_cnd.cn_nameiop = 0;
2301 nfsm_srvmtofh(&nsfh);
2302 nfsm_srvnamesiz(len);
2303 nd.ni_cnd.cn_cred = cred;
2304 nd.ni_cnd.cn_nameiop = CREATE;
2305 nd.ni_cnd.cn_flags = LOCKPARENT;
2306 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
2307 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2308 if (dirp && v3) {
2309 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2310 }
2311 if (error)
2312 goto out;
2313 abort = 1;
2314 vattr_null(&va);
2315 va.va_type = VLNK;
2316 if (v3) {
2317 va.va_mode = 0;
2318 nfsm_srvsattr(&va);
2319 nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
2320 len2 = fxdr_unsigned(uint32_t, *tl);
2321 if (len2 > PATH_MAX) {
2322 /* XXX should check _PC_NO_TRUNC */
2323 error = ENAMETOOLONG;
2324 goto abortop;
2325 }
2326 }
2327 else {
2328 /* NFSv2 */
2329 nfsm_strsiz(len2, NFS_MAXPATHLEN);
2330 }
2331 pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK);
2332 iv.iov_base = pathcp;
2333 iv.iov_len = len2;
2334 io.uio_resid = len2;
2335 io.uio_offset = 0;
2336 io.uio_iov = &iv;
2337 io.uio_iovcnt = 1;
2338 io.uio_rw = UIO_READ;
2339 UIO_SETUP_SYSSPACE(&io);
2340 nfsm_mtouio(&io, len2);
2341 if (!v3) {
2342 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2343 va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
2344 }
2345 *(pathcp + len2) = '\0';
2346 if (nd.ni_vp) {
2347 error = EEXIST;
2348 abortop:
2349 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2350 if (nd.ni_dvp == nd.ni_vp)
2351 vrele(nd.ni_dvp);
2352 else
2353 vput(nd.ni_dvp);
2354 if (nd.ni_vp)
2355 vrele(nd.ni_vp);
2356 goto out;
2357 }
2358 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2359 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
2360 if (!error) {
2361 if (v3) {
2362 vn_lock(nd.ni_vp, LK_SHARED | LK_RETRY);
2363 error = nfsrv_composefh(nd.ni_vp, &nsfh, v3);
2364 if (!error)
2365 error = VOP_GETATTR(nd.ni_vp, &va, cred);
2366 vput(nd.ni_vp);
2367 } else {
2368 vrele(nd.ni_vp);
2369 }
2370 }
2371 vput(nd.ni_dvp);
2372 out:
2373 if (pathcp)
2374 free(pathcp, M_TEMP);
2375 if (dirp) {
2376 if (v3) {
2377 vn_lock(dirp, LK_SHARED | LK_RETRY);
2378 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2379 VOP_UNLOCK(dirp);
2380 }
2381 vrele(dirp);
2382 dirp = NULL;
2383 }
2384 if (nd.ni_pathbuf != NULL) {
2385 pathbuf_destroy(nd.ni_pathbuf);
2386 nd.ni_pathbuf = NULL;
2387 }
2388 abort = 0;
2389 nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPATTR(v3) +
2390 NFSX_WCCDATA(v3));
2391 if (v3) {
2392 if (!error) {
2393 nfsm_srvpostop_fh(&nsfh);
2394 nfsm_srvpostop_attr(0, &va);
2395 }
2396 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2397 }
2398 return (0);
2399 nfsmout:
2400 if (abort) {
2401 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2402 if (nd.ni_dvp == nd.ni_vp)
2403 vrele(nd.ni_dvp);
2404 else
2405 vput(nd.ni_dvp);
2406 if (nd.ni_vp)
2407 vrele(nd.ni_vp);
2408 if (nd.ni_pathbuf != NULL) {
2409 pathbuf_destroy(nd.ni_pathbuf);
2410 nd.ni_pathbuf = NULL;
2411 }
2412 }
2413 if (dirp)
2414 vrele(dirp);
2415 if (pathcp)
2416 free(pathcp, M_TEMP);
2417 return (error);
2418 }
2419
2420 /*
2421 * nfs mkdir service
2422 */
2423 int
2424 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2425 {
2426 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2427 struct mbuf *nam = nfsd->nd_nam;
2428 char *dpos = nfsd->nd_dpos;
2429 kauth_cred_t cred = nfsd->nd_cr;
2430 struct vattr va, dirfor, diraft;
2431 struct nfs_fattr *fp;
2432 struct nameidata nd;
2433 char *cp;
2434 u_int32_t *tl;
2435 int32_t t1;
2436 char *bpos;
2437 int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
2438 int abort = 0;
2439 int v3 = (nfsd->nd_flag & ND_NFSV3);
2440 char *cp2;
2441 struct mbuf *mb, *mreq __unused;
2442 struct vnode *vp, *dirp = (struct vnode *)0;
2443 nfsrvfh_t nsfh;
2444 u_quad_t frev;
2445
2446 nfsm_srvmtofh(&nsfh);
2447 nfsm_srvnamesiz(len);
2448 nd.ni_cnd.cn_cred = cred;
2449 nd.ni_cnd.cn_nameiop = CREATE;
2450 nd.ni_cnd.cn_flags = LOCKPARENT;
2451 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
2452 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2453 if (dirp && v3) {
2454 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2455 }
2456 if (error) {
2457 if (nd.ni_pathbuf != NULL) {
2458 pathbuf_destroy(nd.ni_pathbuf);
2459 nd.ni_pathbuf = NULL;
2460 }
2461 nfsm_reply(NFSX_WCCDATA(v3));
2462 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2463 if (dirp)
2464 vrele(dirp);
2465 return (0);
2466 }
2467 abort = 1;
2468 vattr_null(&va);
2469 if (v3) {
2470 va.va_mode = 0;
2471 nfsm_srvsattr(&va);
2472 } else {
2473 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
2474 va.va_mode = nfstov_mode(*tl++);
2475 }
2476 va.va_type = VDIR;
2477 vp = nd.ni_vp;
2478 if (vp != NULL) {
2479 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2480 if (nd.ni_dvp == vp)
2481 vrele(nd.ni_dvp);
2482 else
2483 vput(nd.ni_dvp);
2484 vrele(vp);
2485 error = EEXIST;
2486 goto out;
2487 }
2488 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2489 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
2490 if (!error) {
2491 vp = nd.ni_vp;
2492 vn_lock(vp, LK_SHARED | LK_RETRY);
2493 error = nfsrv_composefh(vp, &nsfh, v3);
2494 if (!error)
2495 error = VOP_GETATTR(vp, &va, cred);
2496 vput(vp);
2497 }
2498 vput(nd.ni_dvp);
2499 out:
2500 if (dirp) {
2501 if (v3) {
2502 vn_lock(dirp, LK_SHARED | LK_RETRY);
2503 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2504 VOP_UNLOCK(dirp);
2505 }
2506 vrele(dirp);
2507 dirp = NULL;
2508 }
2509 if (nd.ni_pathbuf != NULL) {
2510 pathbuf_destroy(nd.ni_pathbuf);
2511 nd.ni_pathbuf = NULL;
2512 }
2513 abort = 0;
2514 nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPATTR(v3) +
2515 NFSX_WCCDATA(v3));
2516 if (v3) {
2517 if (!error) {
2518 nfsm_srvpostop_fh(&nsfh);
2519 nfsm_srvpostop_attr(0, &va);
2520 }
2521 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2522 } else {
2523 nfsm_srvfhtom(&nsfh, v3);
2524 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2525 nfsm_srvfillattr(&va, fp);
2526 }
2527 return (0);
2528 nfsmout:
2529 if (abort) {
2530 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2531 if (nd.ni_dvp == nd.ni_vp)
2532 vrele(nd.ni_dvp);
2533 else
2534 vput(nd.ni_dvp);
2535 if (nd.ni_vp)
2536 vrele(nd.ni_vp);
2537 if (nd.ni_pathbuf != NULL) {
2538 pathbuf_destroy(nd.ni_pathbuf);
2539 nd.ni_pathbuf = NULL;
2540 }
2541 }
2542 if (dirp)
2543 vrele(dirp);
2544 return (error);
2545 }
2546
2547 /*
2548 * nfs rmdir service
2549 */
2550 int
2551 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2552 {
2553 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2554 struct mbuf *nam = nfsd->nd_nam;
2555 char *dpos = nfsd->nd_dpos;
2556 kauth_cred_t cred = nfsd->nd_cr;
2557 u_int32_t *tl;
2558 int32_t t1;
2559 char *bpos;
2560 int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
2561 int v3 = (nfsd->nd_flag & ND_NFSV3);
2562 char *cp2;
2563 struct mbuf *mb, *mreq __unused;
2564 struct vnode *vp, *dirp = (struct vnode *)0;
2565 struct vattr dirfor, diraft;
2566 nfsrvfh_t nsfh;
2567 struct nameidata nd;
2568 u_quad_t frev;
2569
2570 nfsm_srvmtofh(&nsfh);
2571 nfsm_srvnamesiz(len);
2572 nd.ni_cnd.cn_cred = cred;
2573 nd.ni_cnd.cn_nameiop = DELETE;
2574 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2575 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
2576 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2577 if (dirp && v3) {
2578 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2579 }
2580 if (error) {
2581 if (nd.ni_pathbuf != NULL) {
2582 pathbuf_destroy(nd.ni_pathbuf);
2583 nd.ni_pathbuf = NULL;
2584 }
2585 nfsm_reply(NFSX_WCCDATA(v3));
2586 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2587 if (dirp)
2588 vrele(dirp);
2589 return (0);
2590 }
2591 vp = nd.ni_vp;
2592 if (vp->v_type != VDIR) {
2593 error = ENOTDIR;
2594 goto out;
2595 }
2596 /*
2597 * No rmdir "." please.
2598 */
2599 if (nd.ni_dvp == vp) {
2600 error = EINVAL;
2601 goto out;
2602 }
2603 /*
2604 * The root of a mounted filesystem cannot be deleted.
2605 */
2606 if (vp->v_vflag & VV_ROOT)
2607 error = EBUSY;
2608 out:
2609 if (!error) {
2610 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2611 nqsrv_getl(vp, ND_WRITE);
2612 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2613 vput(nd.ni_dvp);
2614 } else {
2615 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2616 if (nd.ni_dvp == nd.ni_vp)
2617 vrele(nd.ni_dvp);
2618 else
2619 vput(nd.ni_dvp);
2620 vput(vp);
2621 }
2622 if (nd.ni_pathbuf != NULL) {
2623 pathbuf_destroy(nd.ni_pathbuf);
2624 nd.ni_pathbuf = NULL;
2625 }
2626 if (dirp) {
2627 if (v3) {
2628 vn_lock(dirp, LK_SHARED | LK_RETRY);
2629 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2630 VOP_UNLOCK(dirp);
2631 }
2632 vrele(dirp);
2633 }
2634 nfsm_reply(NFSX_WCCDATA(v3));
2635 if (v3) {
2636 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2637 return (0);
2638 }
2639 nfsm_srvdone;
2640 }
2641
2642 /*
2643 * nfs readdir service
2644 * - mallocs what it thinks is enough to read
2645 * count rounded up to a multiple of NFS_SRVDIRBLKSIZ <= NFS_MAXREADDIR
2646 * - calls VOP_READDIR()
2647 * - loops around building the reply
2648 * if the output generated exceeds count break out of loop
2649 * The nfsm_clget macro is used here so that the reply will be packed
2650 * tightly in mbuf clusters.
2651 * - it only knows that it has encountered eof when the VOP_READDIR()
2652 * reads nothing
2653 * - as such one readdir rpc will return eof false although you are there
2654 * and then the next will return eof
2655 * - it trims out records with d_fileno == 0
2656 * this doesn't matter for Unix clients, but they might confuse clients
2657 * for other os'.
2658 * - it trims out records with d_type == DT_WHT
2659 * these cannot be seen through NFS (unless we extend the protocol)
2660 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2661 * than requested, but this may not apply to all filesystems. For
2662 * example, client NFS does not { although it is never remote mounted
2663 * anyhow }
2664 * The alternate call nfsrv_readdirplus() does lookups as well.
2665 * PS: The NFS protocol spec. does not clarify what the "count" byte
2666 * argument is a count of.. just name strings and file id's or the
2667 * entire reply rpc or ...
2668 * I tried just file name and id sizes and it confused the Sun client,
2669 * so I am using the full rpc size now. The "paranoia.." comment refers
2670 * to including the status longwords that are not a part of the dir.
2671 * "entry" structures, but are in the rpc.
2672 */
2673
2674 #define NFS_SRVDIRBLKSIZ 1024
2675
2676 struct flrep {
2677 nfsuint64 fl_off;
2678 u_int32_t fl_postopok;
2679 struct nfs_fattr fl_fattr; /* XXX: must be of fattr3 size */
2680 u_int32_t fl_fhok;
2681 u_int32_t fl_fhsize;
2682 /* handle comes here, filled in dynamically */
2683 };
2684
2685 int
2686 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2687 {
2688 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2689 struct mbuf *nam = nfsd->nd_nam;
2690 char *dpos = nfsd->nd_dpos;
2691 kauth_cred_t cred = nfsd->nd_cr;
2692 char *bp, *be;
2693 struct mbuf *mp;
2694 struct dirent *dp;
2695 char *cp;
2696 u_int32_t *tl;
2697 int32_t t1;
2698 char *bpos;
2699 struct mbuf *mb, *mreq __unused, *mp2;
2700 char *cpos, *cend, *cp2, *rbuf;
2701 struct vnode *vp;
2702 struct vattr at;
2703 nfsrvfh_t nsfh;
2704 struct uio io;
2705 struct iovec iv;
2706 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2707 int siz, cnt, fullsiz, eofflag, rdonly, cache = 0, ncookies;
2708 int v3 = (nfsd->nd_flag & ND_NFSV3);
2709 u_quad_t frev, off, toff;
2710 #ifdef NFS3_STRICTVERF
2711 u_quad_t verf;
2712 #endif
2713 off_t *cookies = NULL, *cookiep;
2714 nfsuint64 jar;
2715
2716 nfsm_srvmtofh(&nsfh);
2717 if (v3) {
2718 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2719 toff = fxdr_hyper(tl);
2720 tl += 2;
2721 #ifdef NFS3_STRICTVERF
2722 verf = fxdr_hyper(tl);
2723 #endif
2724 tl += 2;
2725 } else {
2726 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2727 toff = fxdr_unsigned(u_quad_t, *tl++);
2728 }
2729 off = toff;
2730 cnt = fxdr_unsigned(int, *tl);
2731 siz = ((cnt + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1));
2732 xfer = NFS_SRVMAXDATA(nfsd);
2733 if (siz > xfer)
2734 siz = xfer;
2735 fullsiz = siz;
2736 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
2737 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
2738 if (!error && vp->v_type != VDIR) {
2739 error = ENOTDIR;
2740 vput(vp);
2741 }
2742 if (error) {
2743 nfsm_reply(NFSX_UNSIGNED);
2744 nfsm_srvpostop_attr(getret, &at);
2745 return (0);
2746 }
2747 nqsrv_getl(vp, ND_READ);
2748 if (v3) {
2749 error = getret = VOP_GETATTR(vp, &at, cred);
2750 #ifdef NFS3_STRICTVERF
2751 /*
2752 * XXX This check is too strict for Solaris 2.5 clients.
2753 */
2754 if (!error && toff && verf != at.va_filerev)
2755 error = NFSERR_BAD_COOKIE;
2756 #endif
2757 }
2758 if (!error)
2759 error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0);
2760 if (error) {
2761 vput(vp);
2762 nfsm_reply(NFSX_POSTOPATTR(v3));
2763 nfsm_srvpostop_attr(getret, &at);
2764 return (0);
2765 }
2766 VOP_UNLOCK(vp);
2767 rbuf = malloc(siz, M_TEMP, M_WAITOK);
2768 again:
2769 iv.iov_base = rbuf;
2770 iv.iov_len = fullsiz;
2771 io.uio_iov = &iv;
2772 io.uio_iovcnt = 1;
2773 io.uio_offset = (off_t)off;
2774 io.uio_resid = fullsiz;
2775 io.uio_rw = UIO_READ;
2776 UIO_SETUP_SYSSPACE(&io);
2777 eofflag = 0;
2778 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2779
2780 error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
2781
2782 off = (off_t)io.uio_offset;
2783 if (!cookies && !error)
2784 error = NFSERR_PERM;
2785 if (v3) {
2786 getret = VOP_GETATTR(vp, &at, cred);
2787 if (!error)
2788 error = getret;
2789 }
2790
2791 VOP_UNLOCK(vp);
2792 if (error) {
2793 vrele(vp);
2794 free((void *)rbuf, M_TEMP);
2795 if (cookies)
2796 free((void *)cookies, M_TEMP);
2797 nfsm_reply(NFSX_POSTOPATTR(v3));
2798 nfsm_srvpostop_attr(getret, &at);
2799 return (0);
2800 }
2801 if (io.uio_resid) {
2802 siz -= io.uio_resid;
2803
2804 /*
2805 * If nothing read, return eof
2806 * rpc reply
2807 */
2808 if (siz == 0) {
2809 vrele(vp);
2810 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2811 2 * NFSX_UNSIGNED);
2812 if (v3) {
2813 nfsm_srvpostop_attr(getret, &at);
2814 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2815 txdr_hyper(at.va_filerev, tl);
2816 tl += 2;
2817 } else
2818 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2819 *tl++ = nfs_false;
2820 *tl = nfs_true;
2821 free((void *)rbuf, M_TEMP);
2822 free((void *)cookies, M_TEMP);
2823 return (0);
2824 }
2825 }
2826
2827 /*
2828 * Check for degenerate cases of nothing useful read.
2829 * If so go try again
2830 */
2831 cpos = rbuf;
2832 cend = rbuf + siz;
2833 dp = (struct dirent *)cpos;
2834 cookiep = cookies;
2835
2836 while (cpos < cend && ncookies > 0 &&
2837 (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
2838 cpos += dp->d_reclen;
2839 dp = (struct dirent *)cpos;
2840 cookiep++;
2841 ncookies--;
2842 }
2843 if (cpos >= cend || ncookies == 0) {
2844 toff = off;
2845 siz = fullsiz;
2846 free(cookies, M_TEMP);
2847 cookies = NULL;
2848 goto again;
2849 }
2850
2851 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2852 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2853 if (v3) {
2854 nfsm_srvpostop_attr(getret, &at);
2855 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2856 txdr_hyper(at.va_filerev, tl);
2857 }
2858 mp = mp2 = mb;
2859 bp = bpos;
2860 be = bp + M_TRAILINGSPACE(mp);
2861
2862 /* Loop through the records and build reply */
2863 while (cpos < cend && ncookies > 0) {
2864 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
2865 nlen = dp->d_namlen;
2866 rem = nfsm_rndup(nlen)-nlen;
2867 len += (4 * NFSX_UNSIGNED + nlen + rem);
2868 if (v3)
2869 len += 2 * NFSX_UNSIGNED;
2870 if (len > cnt) {
2871 eofflag = 0;
2872 break;
2873 }
2874 /*
2875 * Build the directory record xdr from
2876 * the dirent entry.
2877 */
2878 nfsm_clget;
2879 *tl = nfs_true;
2880 bp += NFSX_UNSIGNED;
2881 if (v3) {
2882 nfsm_clget;
2883 *tl = txdr_unsigned(dp->d_fileno >> 32);
2884 bp += NFSX_UNSIGNED;
2885 }
2886 nfsm_clget;
2887 *tl = txdr_unsigned(dp->d_fileno);
2888 bp += NFSX_UNSIGNED;
2889 nfsm_clget;
2890 *tl = txdr_unsigned(nlen);
2891 bp += NFSX_UNSIGNED;
2892
2893 /* And loop around copying the name */
2894 xfer = nlen;
2895 cp = dp->d_name;
2896 while (xfer > 0) {
2897 nfsm_clget;
2898 if ((bp+xfer) > be)
2899 tsiz = be-bp;
2900 else
2901 tsiz = xfer;
2902 memcpy(bp, cp, tsiz);
2903 bp += tsiz;
2904 xfer -= tsiz;
2905 if (xfer > 0)
2906 cp += tsiz;
2907 }
2908 /* And null pad to an int32_t boundary */
2909 for (i = 0; i < rem; i++)
2910 *bp++ = '\0';
2911 nfsm_clget;
2912
2913 /* Finish off the record */
2914 txdr_hyper(*cookiep, &jar);
2915 if (v3) {
2916 *tl = jar.nfsuquad[0];
2917 bp += NFSX_UNSIGNED;
2918 nfsm_clget;
2919 }
2920 *tl = jar.nfsuquad[1];
2921 bp += NFSX_UNSIGNED;
2922 }
2923 cpos += dp->d_reclen;
2924 dp = (struct dirent *)cpos;
2925 cookiep++;
2926 ncookies--;
2927 }
2928 vrele(vp);
2929 nfsm_clget;
2930 *tl = nfs_false;
2931 bp += NFSX_UNSIGNED;
2932 nfsm_clget;
2933 if (eofflag)
2934 *tl = nfs_true;
2935 else
2936 *tl = nfs_false;
2937 bp += NFSX_UNSIGNED;
2938 if (mp != mb) {
2939 if (bp < be)
2940 mp->m_len = bp - mtod(mp, char *);
2941 } else
2942 mp->m_len += bp - bpos;
2943 free((void *)rbuf, M_TEMP);
2944 free((void *)cookies, M_TEMP);
2945 nfsm_srvdone;
2946 }
2947
2948 int
2949 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2950 {
2951 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2952 struct mbuf *nam = nfsd->nd_nam;
2953 char *dpos = nfsd->nd_dpos;
2954 kauth_cred_t cred = nfsd->nd_cr;
2955 char *bp, *be;
2956 struct mbuf *mp;
2957 struct dirent *dp;
2958 char *cp;
2959 u_int32_t *tl;
2960 int32_t t1;
2961 char *bpos;
2962 struct mbuf *mb, *mreq __unused, *mp2;
2963 char *cpos, *cend, *cp2, *rbuf;
2964 struct vnode *vp, *nvp;
2965 struct flrep fl;
2966 nfsrvfh_t nsfh;
2967 struct uio io;
2968 struct iovec iv;
2969 struct vattr va, at, *vap = &va;
2970 struct nfs_fattr *fp;
2971 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2972 int siz, cnt, fullsiz, eofflag, rdonly, cache = 0, dirlen, ncookies;
2973 u_quad_t frev, off, toff;
2974 #ifdef NFS3_STRICTVERF
2975 u_quad_t verf;
2976 #endif
2977 off_t *cookies = NULL, *cookiep;
2978
2979 nfsm_srvmtofh(&nsfh);
2980 nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2981 toff = fxdr_hyper(tl);
2982 tl += 2;
2983 #ifdef NFS3_STRICTVERF
2984 verf = fxdr_hyper(tl);
2985 #endif
2986 tl += 2;
2987 siz = fxdr_unsigned(int, *tl++);
2988 cnt = fxdr_unsigned(int, *tl);
2989 off = toff;
2990 siz = ((siz + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1));
2991 xfer = NFS_SRVMAXDATA(nfsd);
2992 if (siz > xfer)
2993 siz = xfer;
2994 fullsiz = siz;
2995 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
2996 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
2997 if (!error && vp->v_type != VDIR) {
2998 error = ENOTDIR;
2999 vput(vp);
3000 }
3001 if (error) {
3002 nfsm_reply(NFSX_UNSIGNED);
3003 nfsm_srvpostop_attr(getret, &at);
3004 return (0);
3005 }
3006 error = getret = VOP_GETATTR(vp, &at, cred);
3007 #ifdef NFS3_STRICTVERF
3008 /*
3009 * XXX This check is too strict for Solaris 2.5 clients.
3010 */
3011 if (!error && toff && verf != at.va_filerev)
3012 error = NFSERR_BAD_COOKIE;
3013 #endif
3014 if (!error) {
3015 nqsrv_getl(vp, ND_READ);
3016 error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0);
3017 }
3018 if (error) {
3019 vput(vp);
3020 nfsm_reply(NFSX_V3POSTOPATTR);
3021 nfsm_srvpostop_attr(getret, &at);
3022 return (0);
3023 }
3024 VOP_UNLOCK(vp);
3025
3026 rbuf = malloc(siz, M_TEMP, M_WAITOK);
3027 again:
3028 iv.iov_base = rbuf;
3029 iv.iov_len = fullsiz;
3030 io.uio_iov = &iv;
3031 io.uio_iovcnt = 1;
3032 io.uio_offset = (off_t)off;
3033 io.uio_resid = fullsiz;
3034 io.uio_rw = UIO_READ;
3035 UIO_SETUP_SYSSPACE(&io);
3036 eofflag = 0;
3037
3038 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3039
3040 error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
3041
3042 off = (u_quad_t)io.uio_offset;
3043 getret = VOP_GETATTR(vp, &at, cred);
3044
3045 VOP_UNLOCK(vp);
3046
3047 /*
3048 * If the VGET operation doesn't work for this filesystem,
3049 * we can't support readdirplus. Returning NOTSUPP should
3050 * make clients fall back to plain readdir.
3051 * There's no need to check for VPTOFH as well, we wouldn't
3052 * even be here otherwise.
3053 */
3054 if (!getret) {
3055 if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, &nvp)))
3056 getret = (getret == EOPNOTSUPP) ?
3057 NFSERR_NOTSUPP : NFSERR_IO;
3058 else
3059 vput(nvp);
3060 }
3061
3062 if (!cookies && !error)
3063 error = NFSERR_PERM;
3064 if (!error)
3065 error = getret;
3066 if (error) {
3067 vrele(vp);
3068 if (cookies)
3069 free((void *)cookies, M_TEMP);
3070 free((void *)rbuf, M_TEMP);
3071 nfsm_reply(NFSX_V3POSTOPATTR);
3072 nfsm_srvpostop_attr(getret, &at);
3073 return (0);
3074 }
3075 if (io.uio_resid) {
3076 siz -= io.uio_resid;
3077
3078 /*
3079 * If nothing read, return eof
3080 * rpc reply
3081 */
3082 if (siz == 0) {
3083 vrele(vp);
3084 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3085 2 * NFSX_UNSIGNED);
3086 nfsm_srvpostop_attr(getret, &at);
3087 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3088 txdr_hyper(at.va_filerev, tl);
3089 tl += 2;
3090 *tl++ = nfs_false;
3091 *tl = nfs_true;
3092 free((void *)cookies, M_TEMP);
3093 free((void *)rbuf, M_TEMP);
3094 return (0);
3095 }
3096 }
3097
3098 /*
3099 * Check for degenerate cases of nothing useful read.
3100 * If so go try again
3101 */
3102 cpos = rbuf;
3103 cend = rbuf + siz;
3104 dp = (struct dirent *)cpos;
3105 cookiep = cookies;
3106
3107 while (cpos < cend && ncookies > 0 &&
3108 (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
3109 cpos += dp->d_reclen;
3110 dp = (struct dirent *)cpos;
3111 cookiep++;
3112 ncookies--;
3113 }
3114 if (cpos >= cend || ncookies == 0) {
3115 toff = off;
3116 siz = fullsiz;
3117 free(cookies, M_TEMP);
3118 cookies = NULL;
3119 goto again;
3120 }
3121
3122 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3123 nfsm_reply(cnt);
3124 nfsm_srvpostop_attr(getret, &at);
3125 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3126 txdr_hyper(at.va_filerev, tl);
3127 mp = mp2 = mb;
3128 bp = bpos;
3129 be = bp + M_TRAILINGSPACE(mp);
3130
3131 /* Loop through the records and build reply */
3132 while (cpos < cend && ncookies > 0) {
3133 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
3134 nfsrvfh_t nnsfh;
3135
3136 nlen = dp->d_namlen;
3137 rem = nfsm_rndup(nlen)-nlen;
3138
3139 /*
3140 * For readdir_and_lookup get the vnode using
3141 * the file number.
3142 */
3143 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
3144 goto invalid;
3145 if (nfsrv_composefh(nvp, &nnsfh, true)) {
3146 vput(nvp);
3147 goto invalid;
3148 }
3149 if (VOP_GETATTR(nvp, vap, cred)) {
3150 vput(nvp);
3151 goto invalid;
3152 }
3153 vput(nvp);
3154
3155 /*
3156 * If either the dircount or maxcount will be
3157 * exceeded, get out now. Both of these lengths
3158 * are calculated conservatively, including all
3159 * XDR overheads.
3160 */
3161 len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
3162 NFSX_V3POSTOPATTR);
3163 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3164 if (len > cnt || dirlen > fullsiz) {
3165 eofflag = 0;
3166 break;
3167 }
3168
3169 /*
3170 * Build the directory record xdr from
3171 * the dirent entry.
3172 */
3173 fp = (struct nfs_fattr *)&fl.fl_fattr;
3174 nfsm_srvfillattr(vap, fp);
3175 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
3176 fl.fl_fhok = nfs_true;
3177 fl.fl_postopok = nfs_true;
3178 txdr_hyper(*cookiep, fl.fl_off.nfsuquad);
3179
3180 nfsm_clget;
3181 *tl = nfs_true;
3182 bp += NFSX_UNSIGNED;
3183 nfsm_clget;
3184 *tl = txdr_unsigned(dp->d_fileno >> 32);
3185 bp += NFSX_UNSIGNED;
3186 nfsm_clget;
3187 *tl = txdr_unsigned(dp->d_fileno);
3188 bp += NFSX_UNSIGNED;
3189 nfsm_clget;
3190 *tl = txdr_unsigned(nlen);
3191 bp += NFSX_UNSIGNED;
3192
3193 /* And loop around copying the name */
3194 xfer = nlen;
3195 cp = dp->d_name;
3196 while (xfer > 0) {
3197 nfsm_clget;
3198 if ((bp + xfer) > be)
3199 tsiz = be - bp;
3200 else
3201 tsiz = xfer;
3202 memcpy(bp, cp, tsiz);
3203 bp += tsiz;
3204 xfer -= tsiz;
3205 if (xfer > 0)
3206 cp += tsiz;
3207 }
3208 /* And null pad to an int32_t boundary */
3209 for (i = 0; i < rem; i++)
3210 *bp++ = '\0';
3211
3212 /*
3213 * Now copy the flrep structure out.
3214 */
3215 xfer = sizeof(struct flrep);
3216 cp = (void *)&fl;
3217 while (xfer > 0) {
3218 nfsm_clget;
3219 if ((bp + xfer) > be)
3220 tsiz = be - bp;
3221 else
3222 tsiz = xfer;
3223 memcpy(bp, cp, tsiz);
3224 bp += tsiz;
3225 xfer -= tsiz;
3226 if (xfer > 0)
3227 cp += tsiz;
3228 }
3229
3230 /*
3231 * ... and filehandle.
3232 */
3233 xfer = NFSRVFH_SIZE(&nnsfh);
3234 cp = NFSRVFH_DATA(&nnsfh);
3235 while (xfer > 0) {
3236 nfsm_clget;
3237 if ((bp + xfer) > be)
3238 tsiz = be - bp;
3239 else
3240 tsiz = xfer;
3241 memcpy(bp, cp, tsiz);
3242 bp += tsiz;
3243 xfer -= tsiz;
3244 if (xfer > 0)
3245 cp += tsiz;
3246 }
3247 }
3248 invalid:
3249 cpos += dp->d_reclen;
3250 dp = (struct dirent *)cpos;
3251 cookiep++;
3252 ncookies--;
3253 }
3254 vrele(vp);
3255 nfsm_clget;
3256 *tl = nfs_false;
3257 bp += NFSX_UNSIGNED;
3258 nfsm_clget;
3259 if (eofflag)
3260 *tl = nfs_true;
3261 else
3262 *tl = nfs_false;
3263 bp += NFSX_UNSIGNED;
3264 if (mp != mb) {
3265 if (bp < be)
3266 mp->m_len = bp - mtod(mp, char *);
3267 } else
3268 mp->m_len += bp - bpos;
3269 free((void *)cookies, M_TEMP);
3270 free((void *)rbuf, M_TEMP);
3271 nfsm_srvdone;
3272 }
3273
3274 /*
3275 * nfs commit service
3276 */
3277 int
3278 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3279 {
3280 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3281 struct mbuf *nam = nfsd->nd_nam;
3282 char *dpos = nfsd->nd_dpos;
3283 kauth_cred_t cred = nfsd->nd_cr;
3284 struct vattr bfor, aft;
3285 struct vnode *vp;
3286 nfsrvfh_t nsfh;
3287 u_int32_t *tl;
3288 int32_t t1;
3289 char *bpos;
3290 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cache = 0;
3291 uint32_t cnt;
3292 char *cp2;
3293 struct mbuf *mb, *mreq __unused;
3294 u_quad_t frev, off, end;
3295
3296 nfsm_srvmtofh(&nsfh);
3297 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3298
3299 off = fxdr_hyper(tl);
3300 tl += 2;
3301 cnt = fxdr_unsigned(uint32_t, *tl);
3302 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3303 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3304 if (error) {
3305 nfsm_reply(2 * NFSX_UNSIGNED);
3306 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3307 return (0);
3308 }
3309 for_ret = VOP_GETATTR(vp, &bfor, cred);
3310 end = (cnt > 0) ? off + cnt : vp->v_size;
3311 if (end < off || end > vp->v_size)
3312 end = vp->v_size;
3313 if (off < vp->v_size)
3314 error = VOP_FSYNC(vp, cred, FSYNC_WAIT, off, end);
3315 /* else error == 0, from nfsrv_fhtovp() */
3316 aft_ret = VOP_GETATTR(vp, &aft, cred);
3317 vput(vp);
3318 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3319 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3320 if (!error) {
3321 nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
3322 *tl++ = txdr_unsigned(boottime.tv_sec);
3323 *tl = txdr_unsigned(boottime.tv_nsec / 1000);
3324 } else {
3325 return (0);
3326 }
3327 nfsm_srvdone;
3328 }
3329
3330 /*
3331 * nfs statfs service
3332 */
3333 int
3334 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3335 {
3336 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3337 struct mbuf *nam = nfsd->nd_nam;
3338 char *dpos = nfsd->nd_dpos;
3339 kauth_cred_t cred = nfsd->nd_cr;
3340 struct statvfs *sf = NULL;
3341 struct nfs_statfs *sfp;
3342 u_int32_t *tl;
3343 int32_t t1;
3344 char *bpos;
3345 int error = 0, rdonly, cache = 0, getret = 1;
3346 int v3 = (nfsd->nd_flag & ND_NFSV3);
3347 char *cp2;
3348 struct mbuf *mb, *mreq __unused;
3349 struct vnode *vp;
3350 struct vattr at;
3351 nfsrvfh_t nsfh;
3352 u_quad_t frev, tval;
3353
3354 nfsm_srvmtofh(&nsfh);
3355 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3356 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3357 if (error) {
3358 nfsm_reply(NFSX_UNSIGNED);
3359 nfsm_srvpostop_attr(getret, &at);
3360 return (0);
3361 }
3362 sf = malloc(sizeof(*sf), M_TEMP, M_WAITOK);
3363 error = VFS_STATVFS(vp->v_mount, sf);
3364 getret = VOP_GETATTR(vp, &at, cred);
3365 vput(vp);
3366 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3367 if (v3)
3368 nfsm_srvpostop_attr(getret, &at);
3369 if (error) {
3370 free(sf, M_TEMP);
3371 return (0);
3372 }
3373 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3374 if (v3) {
3375 tval = (u_quad_t)((quad_t)sf->f_blocks * (quad_t)sf->f_frsize);
3376 txdr_hyper(tval, &sfp->sf_tbytes);
3377 tval = (u_quad_t)((quad_t)sf->f_bfree * (quad_t)sf->f_frsize);
3378 txdr_hyper(tval, &sfp->sf_fbytes);
3379 tval = (u_quad_t)((quad_t)sf->f_bavail * (quad_t)sf->f_frsize);
3380 txdr_hyper(tval, &sfp->sf_abytes);
3381 tval = (u_quad_t)sf->f_files;
3382 txdr_hyper(tval, &sfp->sf_tfiles);
3383 tval = (u_quad_t)sf->f_ffree;
3384 txdr_hyper(tval, &sfp->sf_ffiles);
3385 txdr_hyper(tval, &sfp->sf_afiles);
3386 sfp->sf_invarsec = 0;
3387 } else {
3388 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3389 sfp->sf_bsize = txdr_unsigned(sf->f_frsize);
3390 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3391 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3392 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3393 }
3394 nfsmout:
3395 if (sf)
3396 free(sf, M_TEMP);
3397 return error;
3398 }
3399
3400 /*
3401 * nfs fsinfo service
3402 */
3403 int
3404 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3405 {
3406 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3407 struct mbuf *nam = nfsd->nd_nam;
3408 char *dpos = nfsd->nd_dpos;
3409 kauth_cred_t cred = nfsd->nd_cr;
3410 u_int32_t *tl;
3411 struct nfsv3_fsinfo *sip;
3412 int32_t t1;
3413 char *bpos;
3414 int error = 0, rdonly, cache = 0, getret = 1;
3415 uint32_t maxdata;
3416 char *cp2;
3417 struct mbuf *mb, *mreq __unused;
3418 struct vnode *vp;
3419 struct vattr at;
3420 nfsrvfh_t nsfh;
3421 u_quad_t frev, maxfsize;
3422 struct statvfs *sb;
3423
3424 nfsm_srvmtofh(&nsfh);
3425 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3426 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3427 if (error) {
3428 nfsm_reply(NFSX_UNSIGNED);
3429 nfsm_srvpostop_attr(getret, &at);
3430 return (0);
3431 }
3432
3433 /* XXX Try to make a guess on the max file size. */
3434 sb = malloc(sizeof(*sb), M_TEMP, M_WAITOK);
3435 VFS_STATVFS(vp->v_mount, sb);
3436 maxfsize = (u_quad_t)0x80000000 * sb->f_frsize - 1;
3437 free(sb, M_TEMP);
3438
3439 getret = VOP_GETATTR(vp, &at, cred);
3440 vput(vp);
3441 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3442 nfsm_srvpostop_attr(getret, &at);
3443 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3444
3445 /*
3446 * XXX
3447 * There should be file system VFS OP(s) to get this information.
3448 * For now, assume ufs.
3449 */
3450 if (slp->ns_so->so_type == SOCK_DGRAM)
3451 maxdata = NFS_MAXDGRAMDATA;
3452 else
3453 maxdata = NFS_MAXDATA;
3454 sip->fs_rtmax = txdr_unsigned(maxdata);
3455 sip->fs_rtpref = txdr_unsigned(maxdata);
3456 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3457 sip->fs_wtmax = txdr_unsigned(maxdata);
3458 sip->fs_wtpref = txdr_unsigned(maxdata);
3459 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3460 sip->fs_dtpref = txdr_unsigned(maxdata);
3461 txdr_hyper(maxfsize, &sip->fs_maxfilesize);
3462 sip->fs_timedelta.nfsv3_sec = 0;
3463 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3464 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3465 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3466 NFSV3FSINFO_CANSETTIME);
3467 nfsm_srvdone;
3468 }
3469
3470 /*
3471 * nfs pathconf service
3472 */
3473 int
3474 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3475 {
3476 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3477 struct mbuf *nam = nfsd->nd_nam;
3478 char *dpos = nfsd->nd_dpos;
3479 kauth_cred_t cred = nfsd->nd_cr;
3480 u_int32_t *tl;
3481 struct nfsv3_pathconf *pc;
3482 int32_t t1;
3483 char *bpos;
3484 int error = 0, rdonly, cache = 0, getret = 1;
3485 register_t linkmax, namemax, chownres, notrunc;
3486 char *cp2;
3487 struct mbuf *mb, *mreq __unused;
3488 struct vnode *vp;
3489 struct vattr at;
3490 nfsrvfh_t nsfh;
3491 u_quad_t frev;
3492
3493 nfsm_srvmtofh(&nsfh);
3494 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3495 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3496 if (error) {
3497 nfsm_reply(NFSX_UNSIGNED);
3498 nfsm_srvpostop_attr(getret, &at);
3499 return (0);
3500 }
3501 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3502 if (!error)
3503 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3504 if (!error)
3505 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3506 if (!error)
3507 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
3508 getret = VOP_GETATTR(vp, &at, cred);
3509 vput(vp);
3510 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3511 nfsm_srvpostop_attr(getret, &at);
3512 if (error)
3513 return (0);
3514 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3515
3516 pc->pc_linkmax = txdr_unsigned(linkmax);
3517 pc->pc_namemax = txdr_unsigned(namemax);
3518 pc->pc_notrunc = txdr_unsigned(notrunc);
3519 pc->pc_chownrestricted = txdr_unsigned(chownres);
3520
3521 /*
3522 * These should probably be supported by VOP_PATHCONF(), but
3523 * until msdosfs is exportable (why would you want to?), the
3524 * Unix defaults should be ok.
3525 */
3526 pc->pc_caseinsensitive = nfs_false;
3527 pc->pc_casepreserving = nfs_true;
3528 nfsm_srvdone;
3529 }
3530
3531 /*
3532 * Null operation, used by clients to ping server
3533 */
3534 /* ARGSUSED */
3535 int
3536 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3537 struct lwp *lwp, struct mbuf **mrq)
3538 {
3539 struct mbuf *mrep = nfsd->nd_mrep;
3540 char *bpos;
3541 int error = NFSERR_RETVOID, cache = 0;
3542 struct mbuf *mb, *mreq __unused;
3543 u_quad_t frev;
3544
3545 nfsm_reply(0);
3546 nfsmout:
3547 return (0);
3548 }
3549
3550 /*
3551 * No operation, used for obsolete procedures
3552 */
3553 /* ARGSUSED */
3554 int
3555 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3556 struct lwp *lwp, struct mbuf **mrq)
3557 {
3558 struct mbuf *mrep = nfsd->nd_mrep;
3559 char *bpos;
3560 int error, cache = 0;
3561 struct mbuf *mb, *mreq __unused;
3562 u_quad_t frev;
3563
3564 if (nfsd->nd_repstat)
3565 error = nfsd->nd_repstat;
3566 else
3567 error = EPROCUNAVAIL;
3568 nfsm_reply(0);
3569 nfsmout:
3570 return (0);
3571 }
3572
3573 /*
3574 * Perform access checking for vnodes obtained from file handles that would
3575 * refer to files already opened by a Unix client. You cannot just use
3576 * vn_writechk() and VOP_ACCESS() for two reasons.
3577 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3578 * 2 - The owner is to be given access irrespective of mode bits for some
3579 * operations, so that processes that chmod after opening a file don't
3580 * break. I don't like this because it opens a security hole, but since
3581 * the nfs server opens a security hole the size of a barn door anyhow,
3582 * what the heck.
3583 *
3584 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3585 * will return EPERM instead of EACCES. EPERM is always an error.
3586 */
3587 int
3588 nfsrv_access(struct vnode *vp, int flags, kauth_cred_t cred, int rdonly, struct lwp *lwp, int override)
3589 {
3590 struct vattr vattr;
3591 int error;
3592 if (flags & VWRITE) {
3593 /* Just vn_writechk() changed to check rdonly */
3594 /*
3595 * Disallow write attempts on read-only file systems;
3596 * unless the file is a socket or a block or character
3597 * device resident on the file system.
3598 */
3599 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3600 switch (vp->v_type) {
3601 case VREG:
3602 case VDIR:
3603 case VLNK:
3604 return (EROFS);
3605 default:
3606 break;
3607 }
3608 }
3609
3610 /*
3611 * If the vnode is in use as a process's text,
3612 * we can't allow writing.
3613 */
3614 if (vp->v_iflag & VI_TEXT)
3615 return (ETXTBSY);
3616 }
3617 error = VOP_GETATTR(vp, &vattr, cred);
3618 if (error)
3619 return (error);
3620 error = VOP_ACCESS(vp, flags, cred);
3621 /*
3622 * Allow certain operations for the owner (reads and writes
3623 * on files that are already open).
3624 */
3625 if (override && error == EACCES && kauth_cred_geteuid(cred) == vattr.va_uid)
3626 error = 0;
3627 return error;
3628 }
3629