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