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