1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)portal_vnops.c	8.7 (Berkeley) 01/14/94
12  *
13  * $Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp jsp $
14  */
15 
16 /*
17  * Portal Filesystem
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/types.h>
24 #include <sys/time.h>
25 #include <sys/proc.h>
26 #include <sys/filedesc.h>
27 #include <sys/vnode.h>
28 #include <sys/file.h>
29 #include <sys/stat.h>
30 #include <sys/mount.h>
31 #include <sys/malloc.h>
32 #include <sys/namei.h>
33 #include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #include <sys/socketvar.h>
36 #include <sys/un.h>
37 #include <sys/unpcb.h>
38 #include <miscfs/portal/portal.h>
39 
40 static int portal_fileid = PORTAL_ROOTFILEID+1;
41 
42 static void
43 portal_closefd(p, fd)
44 	struct proc *p;
45 	int fd;
46 {
47 	int error;
48 	struct {
49 		int fd;
50 	} ua;
51 	int rc;
52 
53 	ua.fd = fd;
54 	error = close(p, &ua, &rc);
55 	/*
56 	 * We should never get an error, and there isn't anything
57 	 * we could do if we got one, so just print a message.
58 	 */
59 	if (error)
60 		printf("portal_closefd: error = %d\n", error);
61 }
62 
63 /*
64  * vp is the current namei directory
65  * cnp is the name to locate in that directory...
66  */
67 int
68 portal_lookup(ap)
69 	struct vop_lookup_args /* {
70 		struct vnode * a_dvp;
71 		struct vnode ** a_vpp;
72 		struct componentname * a_cnp;
73 	} */ *ap;
74 {
75 	char *pname = ap->a_cnp->cn_nameptr;
76 	struct portalnode *pt;
77 	int error;
78 	struct vnode *fvp = 0;
79 	char *path;
80 	int size;
81 
82 	if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {
83 		*ap->a_vpp = ap->a_dvp;
84 		VREF(ap->a_dvp);
85 		/*VOP_LOCK(ap->a_dvp);*/
86 		return (0);
87 	}
88 
89 
90 	error = getnewvnode(VT_PORTAL, ap->a_dvp->v_mount, portal_vnodeop_p, &fvp);
91 	if (error)
92 		goto bad;
93 	fvp->v_type = VREG;
94 	MALLOC(fvp->v_data, void *, sizeof(struct portalnode),
95 		M_TEMP, M_WAITOK);
96 
97 	pt = VTOPORTAL(fvp);
98 	/*
99 	 * Save all of the remaining pathname and
100 	 * advance the namei next pointer to the end
101 	 * of the string.
102 	 */
103 	for (size = 0, path = pname; *path; path++)
104 		size++;
105 	ap->a_cnp->cn_consume = size - ap->a_cnp->cn_namelen;
106 
107 	pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
108 	pt->pt_size = size+1;
109 	bcopy(pname, pt->pt_arg, pt->pt_size);
110 	pt->pt_fileid = portal_fileid++;
111 
112 	*ap->a_vpp = fvp;
113 	/*VOP_LOCK(fvp);*/
114 	return (0);
115 
116 bad:;
117 	if (fvp) {
118 		vrele(fvp);
119 	}
120 	*ap->a_vpp = NULL;
121 	return (error);
122 }
123 
124 static int
125 portal_connect(so, so2)
126 	struct socket *so;
127 	struct socket *so2;
128 {
129 	/* from unp_connect, bypassing the namei stuff... */
130 	struct socket *so3;
131 	struct unpcb *unp2;
132 	struct unpcb *unp3;
133 
134 	if (so2 == 0)
135 		return (ECONNREFUSED);
136 
137 	if (so->so_type != so2->so_type)
138 		return (EPROTOTYPE);
139 
140 	if ((so2->so_options & SO_ACCEPTCONN) == 0)
141 		return (ECONNREFUSED);
142 
143 	if ((so3 = sonewconn(so2, 0)) == 0)
144 		return (ECONNREFUSED);
145 
146 	unp2 = sotounpcb(so2);
147 	unp3 = sotounpcb(so3);
148 	if (unp2->unp_addr)
149 		unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
150 
151 	so2 = so3;
152 
153 
154 	return (unp_connect2(so, so2));
155 }
156 
157 int
158 portal_open(ap)
159 	struct vop_open_args /* {
160 		struct vnode *a_vp;
161 		int  a_mode;
162 		struct ucred *a_cred;
163 		struct proc *a_p;
164 	} */ *ap;
165 {
166 	struct socket *so = 0;
167 	struct portalnode *pt;
168 	struct proc *p = ap->a_p;
169 	struct vnode *vp = ap->a_vp;
170 	int s;
171 	struct uio auio;
172 	struct iovec aiov[2];
173 	int res;
174 	struct mbuf *cm = 0;
175 	struct cmsghdr *cmsg;
176 	int newfds;
177 	int *ip;
178 	int fd;
179 	int error;
180 	int len;
181 	struct portalmount *fmp;
182 	struct file *fp;
183 	struct portal_cred pcred;
184 
185 	/*
186 	 * Nothing to do when opening the root node.
187 	 */
188 	if (vp->v_flag & VROOT)
189 		return (0);
190 
191 	/*
192 	 * Can't be opened unless the caller is set up
193 	 * to deal with the side effects.  Check for this
194 	 * by testing whether the p_dupfd has been set.
195 	 */
196 	if (p->p_dupfd >= 0)
197 		return (ENODEV);
198 
199 	pt = VTOPORTAL(vp);
200 	fmp = VFSTOPORTAL(vp->v_mount);
201 
202 	/*
203 	 * Create a new socket.
204 	 */
205 	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);
206 	if (error)
207 		goto bad;
208 
209 	/*
210 	 * Reserve some buffer space
211 	 */
212 	res = pt->pt_size + sizeof(pcred) + 512;	/* XXX */
213 	error = soreserve(so, res, res);
214 	if (error)
215 		goto bad;
216 
217 	/*
218 	 * Kick off connection
219 	 */
220 	error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
221 	if (error)
222 		goto bad;
223 
224 	/*
225 	 * Wait for connection to complete
226 	 */
227 	/*
228 	 * XXX: Since the mount point is holding a reference on the
229 	 * underlying server socket, it is not easy to find out whether
230 	 * the server process is still running.  To handle this problem
231 	 * we loop waiting for the new socket to be connected (something
232 	 * which will only happen if the server is still running) or for
233 	 * the reference count on the server socket to drop to 1, which
234 	 * will happen if the server dies.  Sleep for 5 second intervals
235 	 * and keep polling the reference count.   XXX.
236 	 */
237 	s = splnet();
238 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
239 		if (fmp->pm_server->f_count == 1) {
240 			error = ECONNREFUSED;
241 			splx(s);
242 			goto bad;
243 		}
244 		(void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz);
245 	}
246 	splx(s);
247 
248 	if (so->so_error) {
249 		error = so->so_error;
250 		goto bad;
251 	}
252 
253 	/*
254 	 * Set miscellaneous flags
255 	 */
256 	so->so_rcv.sb_timeo = 0;
257 	so->so_snd.sb_timeo = 0;
258 	so->so_rcv.sb_flags |= SB_NOINTR;
259 	so->so_snd.sb_flags |= SB_NOINTR;
260 
261 
262 	pcred.pcr_flag = ap->a_mode;
263 	pcred.pcr_uid = ap->a_cred->cr_uid;
264 	pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
265 	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
266 	aiov[0].iov_base = (caddr_t) &pcred;
267 	aiov[0].iov_len = sizeof(pcred);
268 	aiov[1].iov_base = pt->pt_arg;
269 	aiov[1].iov_len = pt->pt_size;
270 	auio.uio_iov = aiov;
271 	auio.uio_iovcnt = 2;
272 	auio.uio_rw = UIO_WRITE;
273 	auio.uio_segflg = UIO_SYSSPACE;
274 	auio.uio_procp = p;
275 	auio.uio_offset = 0;
276 	auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
277 
278 	error = sosend(so, (struct mbuf *) 0, &auio,
279 			(struct mbuf *) 0, (struct mbuf *) 0, 0);
280 	if (error)
281 		goto bad;
282 
283 	len = auio.uio_resid = sizeof(int);
284 	do {
285 		struct mbuf *m = 0;
286 		int flags = MSG_WAITALL;
287 		error = soreceive(so, (struct mbuf **) 0, &auio,
288 					&m, &cm, &flags);
289 		if (error)
290 			goto bad;
291 
292 		/*
293 		 * Grab an error code from the mbuf.
294 		 */
295 		if (m) {
296 			m = m_pullup(m, sizeof(int));	/* Needed? */
297 			if (m) {
298 				error = *(mtod(m, int *));
299 				m_freem(m);
300 			} else {
301 				error = EINVAL;
302 			}
303 		} else {
304 			if (cm == 0) {
305 				error = ECONNRESET;	 /* XXX */
306 #ifdef notdef
307 				break;
308 #endif
309 			}
310 		}
311 	} while (cm == 0 && auio.uio_resid == len && !error);
312 
313 	if (cm == 0)
314 		goto bad;
315 
316 	if (auio.uio_resid) {
317 		error = 0;
318 #ifdef notdef
319 		error = EMSGSIZE;
320 		goto bad;
321 #endif
322 	}
323 
324 	/*
325 	 * XXX: Break apart the control message, and retrieve the
326 	 * received file descriptor.  Note that more than one descriptor
327 	 * may have been received, or that the rights chain may have more
328 	 * than a single mbuf in it.  What to do?
329 	 */
330 	cmsg = mtod(cm, struct cmsghdr *);
331 	newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
332 	if (newfds == 0) {
333 		error = ECONNREFUSED;
334 		goto bad;
335 	}
336 	/*
337 	 * At this point the rights message consists of a control message
338 	 * header, followed by a data region containing a vector of
339 	 * integer file descriptors.  The fds were allocated by the action
340 	 * of receiving the control message.
341 	 */
342 	ip = (int *) (cmsg + 1);
343 	fd = *ip++;
344 	if (newfds > 1) {
345 		/*
346 		 * Close extra fds.
347 		 */
348 		int i;
349 		printf("portal_open: %d extra fds\n", newfds - 1);
350 		for (i = 1; i < newfds; i++) {
351 			portal_closefd(p, *ip);
352 			ip++;
353 		}
354 	}
355 
356 	/*
357 	 * Check that the mode the file is being opened for is a subset
358 	 * of the mode of the existing descriptor.
359 	 */
360  	fp = p->p_fd->fd_ofiles[fd];
361 	if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
362 		portal_closefd(p, fd);
363 		error = EACCES;
364 		goto bad;
365 	}
366 
367 	/*
368 	 * Save the dup fd in the proc structure then return the
369 	 * special error code (ENXIO) which causes magic things to
370 	 * happen in vn_open.  The whole concept is, well, hmmm.
371 	 */
372 	p->p_dupfd = fd;
373 	error = ENXIO;
374 
375 bad:;
376 	/*
377 	 * And discard the control message.
378 	 */
379 	if (cm) {
380 		m_freem(cm);
381 	}
382 
383 	if (so) {
384 		soshutdown(so, 2);
385 		soclose(so);
386 	}
387 	return (error);
388 }
389 
390 int
391 portal_getattr(ap)
392 	struct vop_getattr_args /* {
393 		struct vnode *a_vp;
394 		struct vattr *a_vap;
395 		struct ucred *a_cred;
396 		struct proc *a_p;
397 	} */ *ap;
398 {
399 	struct vnode *vp = ap->a_vp;
400 	struct vattr *vap = ap->a_vap;
401 
402 	bzero(vap, sizeof(*vap));
403 	vattr_null(vap);
404 	vap->va_uid = 0;
405 	vap->va_gid = 0;
406 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
407 	vap->va_size = DEV_BSIZE;
408 	vap->va_blocksize = DEV_BSIZE;
409 	microtime(&vap->va_atime);
410 	vap->va_mtime = vap->va_atime;
411 	vap->va_ctime = vap->va_ctime;
412 	vap->va_gen = 0;
413 	vap->va_flags = 0;
414 	vap->va_rdev = 0;
415 	/* vap->va_qbytes = 0; */
416 	vap->va_bytes = 0;
417 	/* vap->va_qsize = 0; */
418 	if (vp->v_flag & VROOT) {
419 		vap->va_type = VDIR;
420 		vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
421 				S_IRGRP|S_IWGRP|S_IXGRP|
422 				S_IROTH|S_IWOTH|S_IXOTH;
423 		vap->va_nlink = 2;
424 		vap->va_fileid = 2;
425 	} else {
426 		vap->va_type = VREG;
427 		vap->va_mode = S_IRUSR|S_IWUSR|
428 				S_IRGRP|S_IWGRP|
429 				S_IROTH|S_IWOTH;
430 		vap->va_nlink = 1;
431 		vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
432 	}
433 	return (0);
434 }
435 
436 int
437 portal_setattr(ap)
438 	struct vop_setattr_args /* {
439 		struct vnode *a_vp;
440 		struct vattr *a_vap;
441 		struct ucred *a_cred;
442 		struct proc *a_p;
443 	} */ *ap;
444 {
445 
446 	/*
447 	 * Can't mess with the root vnode
448 	 */
449 	if (ap->a_vp->v_flag & VROOT)
450 		return (EACCES);
451 
452 	return (0);
453 }
454 
455 /*
456  * Fake readdir, just return empty directory.
457  * It is hard to deal with '.' and '..' so don't bother.
458  */
459 int
460 portal_readdir(ap)
461 	struct vop_readdir_args /* {
462 		struct vnode *a_vp;
463 		struct uio *a_uio;
464 		struct ucred *a_cred;
465 	} */ *ap;
466 {
467 
468 	return (0);
469 }
470 
471 int
472 portal_inactive(ap)
473 	struct vop_inactive_args /* {
474 		struct vnode *a_vp;
475 	} */ *ap;
476 {
477 
478 	return (0);
479 }
480 
481 int
482 portal_reclaim(ap)
483 	struct vop_reclaim_args /* {
484 		struct vnode *a_vp;
485 	} */ *ap;
486 {
487 	struct portalnode *pt = VTOPORTAL(ap->a_vp);
488 
489 	if (pt->pt_arg) {
490 		free((caddr_t) pt->pt_arg, M_TEMP);
491 		pt->pt_arg = 0;
492 	}
493 	FREE(ap->a_vp->v_data, M_TEMP);
494 	ap->a_vp->v_data = 0;
495 
496 	return (0);
497 }
498 
499 /*
500  * Return POSIX pathconf information applicable to special devices.
501  */
502 portal_pathconf(ap)
503 	struct vop_pathconf_args /* {
504 		struct vnode *a_vp;
505 		int a_name;
506 		int *a_retval;
507 	} */ *ap;
508 {
509 
510 	switch (ap->a_name) {
511 	case _PC_LINK_MAX:
512 		*ap->a_retval = LINK_MAX;
513 		return (0);
514 	case _PC_MAX_CANON:
515 		*ap->a_retval = MAX_CANON;
516 		return (0);
517 	case _PC_MAX_INPUT:
518 		*ap->a_retval = MAX_INPUT;
519 		return (0);
520 	case _PC_PIPE_BUF:
521 		*ap->a_retval = PIPE_BUF;
522 		return (0);
523 	case _PC_CHOWN_RESTRICTED:
524 		*ap->a_retval = 1;
525 		return (0);
526 	case _PC_VDISABLE:
527 		*ap->a_retval = _POSIX_VDISABLE;
528 		return (0);
529 	default:
530 		return (EINVAL);
531 	}
532 	/* NOTREACHED */
533 }
534 
535 /*
536  * Print out the contents of a Portal vnode.
537  */
538 /* ARGSUSED */
539 int
540 portal_print(ap)
541 	struct vop_print_args /* {
542 		struct vnode *a_vp;
543 	} */ *ap;
544 {
545 
546 	printf("tag VT_PORTAL, portal vnode\n");
547 	return (0);
548 }
549 
550 /*void*/
551 int
552 portal_vfree(ap)
553 	struct vop_vfree_args /* {
554 		struct vnode *a_pvp;
555 		ino_t a_ino;
556 		int a_mode;
557 	} */ *ap;
558 {
559 
560 	return (0);
561 }
562 
563 
564 /*
565  * Portal vnode unsupported operation
566  */
567 int
568 portal_enotsupp()
569 {
570 
571 	return (EOPNOTSUPP);
572 }
573 
574 /*
575  * Portal "should never get here" operation
576  */
577 int
578 portal_badop()
579 {
580 
581 	panic("portal: bad op");
582 	/* NOTREACHED */
583 }
584 
585 /*
586  * Portal vnode null operation
587  */
588 int
589 portal_nullop()
590 {
591 
592 	return (0);
593 }
594 
595 #define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp)
596 #define portal_mknod ((int (*) __P((struct  vop_mknod_args *)))portal_enotsupp)
597 #define portal_close ((int (*) __P((struct  vop_close_args *)))nullop)
598 #define portal_access ((int (*) __P((struct  vop_access_args *)))nullop)
599 #define portal_read ((int (*) __P((struct  vop_read_args *)))portal_enotsupp)
600 #define portal_write ((int (*) __P((struct  vop_write_args *)))portal_enotsupp)
601 #define portal_ioctl ((int (*) __P((struct  vop_ioctl_args *)))portal_enotsupp)
602 #define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp)
603 #define portal_mmap ((int (*) __P((struct  vop_mmap_args *)))portal_enotsupp)
604 #define portal_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
605 #define portal_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
606 #define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp)
607 #define portal_link ((int (*) __P((struct  vop_link_args *)))portal_enotsupp)
608 #define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp)
609 #define portal_mkdir ((int (*) __P((struct  vop_mkdir_args *)))portal_enotsupp)
610 #define portal_rmdir ((int (*) __P((struct  vop_rmdir_args *)))portal_enotsupp)
611 #define portal_symlink \
612 	((int (*) __P((struct  vop_symlink_args *)))portal_enotsupp)
613 #define portal_readlink \
614 	((int (*) __P((struct  vop_readlink_args *)))portal_enotsupp)
615 #define portal_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
616 #define portal_lock ((int (*) __P((struct  vop_lock_args *)))nullop)
617 #define portal_unlock ((int (*) __P((struct  vop_unlock_args *)))nullop)
618 #define portal_bmap ((int (*) __P((struct  vop_bmap_args *)))portal_badop)
619 #define portal_strategy \
620 	((int (*) __P((struct  vop_strategy_args *)))portal_badop)
621 #define portal_islocked ((int (*) __P((struct  vop_islocked_args *)))nullop)
622 #define portal_advlock \
623 	((int (*) __P((struct  vop_advlock_args *)))portal_enotsupp)
624 #define portal_blkatoff \
625 	((int (*) __P((struct  vop_blkatoff_args *)))portal_enotsupp)
626 #define portal_valloc ((int(*) __P(( \
627 		struct vnode *pvp, \
628 		int mode, \
629 		struct ucred *cred, \
630 		struct vnode **vpp))) portal_enotsupp)
631 #define portal_truncate \
632 	((int (*) __P((struct  vop_truncate_args *)))portal_enotsupp)
633 #define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp)
634 #define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp)
635 
636 int (**portal_vnodeop_p)();
637 struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
638 	{ &vop_default_desc, vn_default_error },
639 	{ &vop_lookup_desc, portal_lookup },		/* lookup */
640 	{ &vop_create_desc, portal_create },		/* create */
641 	{ &vop_mknod_desc, portal_mknod },		/* mknod */
642 	{ &vop_open_desc, portal_open },		/* open */
643 	{ &vop_close_desc, portal_close },		/* close */
644 	{ &vop_access_desc, portal_access },		/* access */
645 	{ &vop_getattr_desc, portal_getattr },		/* getattr */
646 	{ &vop_setattr_desc, portal_setattr },		/* setattr */
647 	{ &vop_read_desc, portal_read },		/* read */
648 	{ &vop_write_desc, portal_write },		/* write */
649 	{ &vop_ioctl_desc, portal_ioctl },		/* ioctl */
650 	{ &vop_select_desc, portal_select },		/* select */
651 	{ &vop_mmap_desc, portal_mmap },		/* mmap */
652 	{ &vop_fsync_desc, portal_fsync },		/* fsync */
653 	{ &vop_seek_desc, portal_seek },		/* seek */
654 	{ &vop_remove_desc, portal_remove },		/* remove */
655 	{ &vop_link_desc, portal_link },		/* link */
656 	{ &vop_rename_desc, portal_rename },		/* rename */
657 	{ &vop_mkdir_desc, portal_mkdir },		/* mkdir */
658 	{ &vop_rmdir_desc, portal_rmdir },		/* rmdir */
659 	{ &vop_symlink_desc, portal_symlink },		/* symlink */
660 	{ &vop_readdir_desc, portal_readdir },		/* readdir */
661 	{ &vop_readlink_desc, portal_readlink },	/* readlink */
662 	{ &vop_abortop_desc, portal_abortop },		/* abortop */
663 	{ &vop_inactive_desc, portal_inactive },	/* inactive */
664 	{ &vop_reclaim_desc, portal_reclaim },		/* reclaim */
665 	{ &vop_lock_desc, portal_lock },		/* lock */
666 	{ &vop_unlock_desc, portal_unlock },		/* unlock */
667 	{ &vop_bmap_desc, portal_bmap },		/* bmap */
668 	{ &vop_strategy_desc, portal_strategy },	/* strategy */
669 	{ &vop_print_desc, portal_print },		/* print */
670 	{ &vop_islocked_desc, portal_islocked },	/* islocked */
671 	{ &vop_pathconf_desc, portal_pathconf },	/* pathconf */
672 	{ &vop_advlock_desc, portal_advlock },		/* advlock */
673 	{ &vop_blkatoff_desc, portal_blkatoff },	/* blkatoff */
674 	{ &vop_valloc_desc, portal_valloc },		/* valloc */
675 	{ &vop_vfree_desc, portal_vfree },		/* vfree */
676 	{ &vop_truncate_desc, portal_truncate },	/* truncate */
677 	{ &vop_update_desc, portal_update },		/* update */
678 	{ &vop_bwrite_desc, portal_bwrite },		/* bwrite */
679 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
680 };
681 struct vnodeopv_desc portal_vnodeop_opv_desc =
682 	{ &portal_vnodeop_p, portal_vnodeop_entries };
683