Beispiel #1
0
static int
fuse_vfsop_mount(struct mount *mp)
{
	int err;

	uint64_t mntopts, __mntopts;
	int max_read_set;
	uint32_t max_read;
	int daemon_timeout;
	int fd;

	size_t len;

	struct cdev *fdev;
	struct fuse_data *data;
	struct thread *td;
	struct file *fp, *fptmp;
	char *fspec, *subtype;
	struct vfsoptlist *opts;

	subtype = NULL;
	max_read_set = 0;
	max_read = ~0;
	err = 0;
	mntopts = 0;
	__mntopts = 0;
	td = curthread;

	fuse_trace_printf_vfsop();

	if (mp->mnt_flag & MNT_UPDATE)
		return EOPNOTSUPP;

	mp->mnt_flag |= MNT_SYNCHRONOUS;
	mp->mnt_data = NULL;
	/* Get the new options passed to mount */
	opts = mp->mnt_optnew;

	if (!opts)
		return EINVAL;

	/* `fspath' contains the mount point (eg. /mnt/fuse/sshfs); REQUIRED */
	if (!vfs_getopts(opts, "fspath", &err))
		return err;

	/* `from' contains the device name (eg. /dev/fuse0); REQUIRED */
	fspec = vfs_getopts(opts, "from", &err);
	if (!fspec)
		return err;

	/* `fd' contains the filedescriptor for this session; REQUIRED */
	if (vfs_scanopt(opts, "fd", "%d", &fd) != 1)
		return EINVAL;

	err = fuse_getdevice(fspec, td, &fdev);
	if (err != 0)
		return err;

	/*
         * With the help of underscored options the mount program
         * can inform us from the flags it sets by default
         */
	FUSE_FLAGOPT(allow_other, FSESS_DAEMON_CAN_SPY);
	FUSE_FLAGOPT(push_symlinks_in, FSESS_PUSH_SYMLINKS_IN);
	FUSE_FLAGOPT(default_permissions, FSESS_DEFAULT_PERMISSIONS);
	FUSE_FLAGOPT(no_attrcache, FSESS_NO_ATTRCACHE);
	FUSE_FLAGOPT(no_readahed, FSESS_NO_READAHEAD);
	FUSE_FLAGOPT(no_datacache, FSESS_NO_DATACACHE);
	FUSE_FLAGOPT(no_namecache, FSESS_NO_NAMECACHE);
	FUSE_FLAGOPT(no_mmap, FSESS_NO_MMAP);
	FUSE_FLAGOPT(brokenio, FSESS_BROKENIO);

	if (vfs_scanopt(opts, "max_read=", "%u", &max_read) == 1)
		max_read_set = 1;
	if (vfs_scanopt(opts, "timeout=", "%u", &daemon_timeout) == 1) {
		if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT)
			daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT;
		else if (daemon_timeout > FUSE_MAX_DAEMON_TIMEOUT)
			daemon_timeout = FUSE_MAX_DAEMON_TIMEOUT;
	} else {
		daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
	}
	subtype = vfs_getopts(opts, "subtype=", &err);

	FS_DEBUG2G("mntopts 0x%jx\n", (uintmax_t)mntopts);

	err = fget(td, fd, CAP_READ, &fp);
	if (err != 0) {
		FS_DEBUG("invalid or not opened device: data=%p\n", data);
		goto out;
	}
	fptmp = td->td_fpop;
	td->td_fpop = fp;
        err = devfs_get_cdevpriv((void **)&data);
	td->td_fpop = fptmp;
	fdrop(fp, td);
	FUSE_LOCK();
	if (err != 0 || data == NULL || data->mp != NULL) {
		FS_DEBUG("invalid or not opened device: data=%p data.mp=%p\n",
		    data, data != NULL ? data->mp : NULL);
		err = ENXIO;
		FUSE_UNLOCK();
		goto out;
	}
	if (fdata_get_dead(data)) {
		FS_DEBUG("device is dead during mount: data=%p\n", data);
		err = ENOTCONN;
		FUSE_UNLOCK();
		goto out;
	}
	/* Sanity + permission checks */
	if (!data->daemoncred)
		panic("fuse daemon found, but identity unknown");
	if (mntopts & FSESS_DAEMON_CAN_SPY)
		err = priv_check(td, PRIV_VFS_FUSE_ALLOWOTHER);
	if (err == 0 && td->td_ucred->cr_uid != data->daemoncred->cr_uid)
		/* are we allowed to do the first mount? */
		err = priv_check(td, PRIV_VFS_FUSE_MOUNT_NONUSER);
	if (err) {
		FUSE_UNLOCK();
		goto out;
	}
	/* We need this here as this slot is used by getnewvnode() */
	mp->mnt_stat.f_iosize = PAGE_SIZE;
	mp->mnt_data = data;
	data->ref++;
	data->mp = mp;
	data->dataflags |= mntopts;
	data->max_read = max_read;
	data->daemon_timeout = daemon_timeout;
#ifdef XXXIP
	if (!priv_check(td, PRIV_VFS_FUSE_SYNC_UNMOUNT))
		data->dataflags |= FSESS_CAN_SYNC_UNMOUNT;
#endif
	FUSE_UNLOCK();

	vfs_getnewfsid(mp);
	mp->mnt_flag |= MNT_LOCAL;
	mp->mnt_kern_flag |= MNTK_MPSAFE;
	if (subtype) {
		strlcat(mp->mnt_stat.f_fstypename, ".", MFSNAMELEN);
		strlcat(mp->mnt_stat.f_fstypename, subtype, MFSNAMELEN);
	}
	copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len);
	bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
	FS_DEBUG2G("mp %p: %s\n", mp, mp->mnt_stat.f_mntfromname);

	/* Now handshaking with daemon */
	fuse_internal_send_init(data, td);

out:
	if (err) {
		FUSE_LOCK();
		if (data->mp == mp) {
			/*
			 * Destroy device only if we acquired reference to
			 * it
			 */
			FS_DEBUG("mount failed, destroy device: data=%p mp=%p"
			      " err=%d\n",
			    data, mp, err);
			data->mp = NULL;
			fdata_trydestroy(data);
		}
		FUSE_UNLOCK();
		dev_rel(fdev);
	}
	return err;
}
/*
 * Mount the per-process file descriptors (/dev/fd)
 */
static int
portal_mount(struct mount *mp)
{
	struct file *fp;
	struct portalmount *fmp;
	struct socket *so;
	struct vnode *rvp;
	struct thread *td;
	struct portalnode *pn;
	int error, v;
	char *p;

	td = curthread;
	if (vfs_filteropt(mp->mnt_optnew, portal_opts))
		return (EINVAL);

	error = vfs_scanopt(mp->mnt_optnew, "socket", "%d", &v);
	if (error != 1)
		return (EINVAL);
	error = vfs_getopt(mp->mnt_optnew, "config", (void **)&p, NULL);
	if (error)
		return (error);

	/*
	 * Capsicum is not incompatible with portalfs, but we don't really
	 * know what rights are required. In the spirit of "better safe than
	 * sorry", pretend that all rights are required for now.
	 */
	if ((error = fget(td, v, CAP_MASK_VALID, &fp)) != 0)
		return (error);
        if (fp->f_type != DTYPE_SOCKET) {
		fdrop(fp, td);
                return(ENOTSOCK);
	}
	so = fp->f_data;	/* XXX race against userland */
	if (so->so_proto->pr_domain->dom_family != AF_UNIX) {
		fdrop(fp, td);
		return (ESOCKTNOSUPPORT);
	}

	pn = malloc(sizeof(struct portalnode),
		M_TEMP, M_WAITOK);

	fmp = malloc(sizeof(struct portalmount),
		M_PORTALFSMNT, M_WAITOK);	/* XXX */

	error = getnewvnode("portal", mp, &portal_vnodeops, &rvp); /* XXX */
	if (error) {
		free(fmp, M_PORTALFSMNT);
		free(pn, M_TEMP);
		fdrop(fp, td);
		return (error);
	}

	error = insmntque(rvp, mp);	/* XXX: Too early for mpsafe fs */
	if (error != 0) {
		free(fmp, M_PORTALFSMNT);
		free(pn, M_TEMP);
		fdrop(fp, td);
		return (error);
	}
	rvp->v_data = pn;
	rvp->v_type = VDIR;
	rvp->v_vflag |= VV_ROOT;
	VTOPORTAL(rvp)->pt_arg = 0;
	VTOPORTAL(rvp)->pt_size = 0;
	VTOPORTAL(rvp)->pt_fileid = PORTAL_ROOTFILEID;
	fmp->pm_root = rvp;
	fhold(fp);
	fmp->pm_server = fp;

	MNT_ILOCK(mp);
	mp->mnt_flag |= MNT_LOCAL;
	MNT_IUNLOCK(mp);
	mp->mnt_data =  fmp;
	vfs_getnewfsid(mp);

	vfs_mountedfrom(mp, p);
	fdrop(fp, td);
	return (0);
}
Beispiel #3
0
static int
smbfs_mount(struct mount *mp)
{
	struct smbmount *smp = NULL;
	struct smb_vc *vcp;
	struct smb_share *ssp = NULL;
	struct vnode *vp;
	struct thread *td;
	struct smb_dev *dev;
	struct smb_cred *scred;
	int error, v;
	char *pc, *pe;

	dev = NULL;
	td = curthread;
	if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS))
		return EOPNOTSUPP;

	if (vfs_filteropt(mp->mnt_optnew, smbfs_opts)) {
		vfs_mount_error(mp, "%s", "Invalid option");
		return (EINVAL);
	}

	scred = smbfs_malloc_scred();
	smb_makescred(scred, td, td->td_ucred);
	
	/* Ask userspace of `fd`, the file descriptor of this session */
	if (1 != vfs_scanopt(mp->mnt_optnew, "fd", "%d", &v)) {
		vfs_mount_error(mp, "No fd option");
		smbfs_free_scred(scred);
		return (EINVAL);
	}
	error = smb_dev2share(v, SMBM_EXEC, scred, &ssp, &dev);
	smp = malloc(sizeof(*smp), M_SMBFSDATA, M_WAITOK | M_ZERO);
	if (error) {
		printf("invalid device handle %d (%d)\n", v, error);
		vfs_mount_error(mp, "invalid device handle %d %d\n", v, error);
		smbfs_free_scred(scred);
		free(smp, M_SMBFSDATA);
		return error;
	}
	vcp = SSTOVC(ssp);
	smb_share_unlock(ssp);
	mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax;
	mp->mnt_data = smp;
	smp->sm_share = ssp;
	smp->sm_root = NULL;
	smp->sm_dev = dev;
	if (1 != vfs_scanopt(mp->mnt_optnew,
	    "caseopt", "%d", &smp->sm_caseopt)) {
		vfs_mount_error(mp, "Invalid caseopt");
		error = EINVAL;
		goto bad;
	}
	if (1 != vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v)) {
		vfs_mount_error(mp, "Invalid uid");
		error = EINVAL;
		goto bad;
	}
	smp->sm_uid = v;

	if (1 != vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v)) {
		vfs_mount_error(mp, "Invalid gid");
		error = EINVAL;
		goto bad;
	}
	smp->sm_gid = v;

	if (1 != vfs_scanopt(mp->mnt_optnew, "file_mode", "%d", &v)) {
		vfs_mount_error(mp, "Invalid file_mode");
		error = EINVAL;
		goto bad;
	}
	smp->sm_file_mode = (v & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;

	if (1 != vfs_scanopt(mp->mnt_optnew, "dir_mode", "%d", &v)) {
		vfs_mount_error(mp, "Invalid dir_mode");
		error = EINVAL;
		goto bad;
	}
	smp->sm_dir_mode  = (v & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;

	vfs_flagopt(mp->mnt_optnew,
	    "nolong", &smp->sm_flags, SMBFS_MOUNT_NO_LONG);

	pc = mp->mnt_stat.f_mntfromname;
	pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
	bzero(pc, MNAMELEN);
	*pc++ = '/';
	*pc++ = '/';
	pc = strchr(strncpy(pc, vcp->vc_username, pe - pc - 2), 0);
	if (pc < pe-1) {
		*(pc++) = '@';
		pc = strchr(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0);
		if (pc < pe - 1) {
			*(pc++) = '/';
			strncpy(pc, ssp->ss_name, pe - pc - 2);
		}
	}
	vfs_getnewfsid(mp);
	error = smbfs_root(mp, LK_EXCLUSIVE, &vp);
	if (error) {
		vfs_mount_error(mp, "smbfs_root error: %d", error);
		goto bad;
	}
	VOP_UNLOCK(vp, 0);
	SMBVDEBUG("root.v_usecount = %d\n", vrefcnt(vp));

#ifdef DIAGNOSTIC
	SMBERROR("mp=%p\n", mp);
#endif
	smbfs_free_scred(scred);
	return error;
bad:
	if (ssp)
		smb_share_put(ssp, scred);
	smbfs_free_scred(scred);	
	SMB_LOCK();
	if (error && smp->sm_dev == dev) {
		smp->sm_dev = NULL;
		sdp_trydestroy(dev);
	}
	SMB_UNLOCK();
	free(smp, M_SMBFSDATA);
	return error;
}
Beispiel #4
0
static int
update_mp(struct mount *mp, struct thread *td)
{
	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
	void *dos, *win, *local;
	int error, v;

	if (!vfs_getopt(mp->mnt_optnew, "kiconv", NULL, NULL)) {
		if (msdosfs_iconv != NULL) {
			error = vfs_getopt(mp->mnt_optnew,
			    "cs_win", &win, NULL);
			if (!error)
				error = vfs_getopt(mp->mnt_optnew,
				    "cs_local", &local, NULL);
			if (!error)
				error = vfs_getopt(mp->mnt_optnew,
				    "cs_dos", &dos, NULL);
			if (!error) {
				msdosfs_iconv->open(win, local, &pmp->pm_u2w);
				msdosfs_iconv->open(local, win, &pmp->pm_w2u);
				msdosfs_iconv->open(dos, local, &pmp->pm_u2d);
				msdosfs_iconv->open(local, dos, &pmp->pm_d2u);
			}
			if (error != 0)
				return (error);
		} else {
			pmp->pm_w2u = NULL;
			pmp->pm_u2w = NULL;
			pmp->pm_d2u = NULL;
			pmp->pm_u2d = NULL;
		}
	}

	if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1)
		pmp->pm_gid = v;
	if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1)
		pmp->pm_uid = v;
	if (vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v) == 1)
		pmp->pm_mask = v & ALLPERMS;
	if (vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v) == 1)
		pmp->pm_dirmask = v & ALLPERMS;
	vfs_flagopt(mp->mnt_optnew, "shortname",
	    &pmp->pm_flags, MSDOSFSMNT_SHORTNAME);
	vfs_flagopt(mp->mnt_optnew, "shortnames",
	    &pmp->pm_flags, MSDOSFSMNT_SHORTNAME);
	vfs_flagopt(mp->mnt_optnew, "longname",
	    &pmp->pm_flags, MSDOSFSMNT_LONGNAME);
	vfs_flagopt(mp->mnt_optnew, "longnames",
	    &pmp->pm_flags, MSDOSFSMNT_LONGNAME);
	vfs_flagopt(mp->mnt_optnew, "kiconv",
	    &pmp->pm_flags, MSDOSFSMNT_KICONV);

	if (vfs_getopt(mp->mnt_optnew, "nowin95", NULL, NULL) == 0)
		pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
	else
		pmp->pm_flags &= ~MSDOSFSMNT_NOWIN95;

	if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
		pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
	else if (!(pmp->pm_flags &
	    (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
		struct vnode *rootvp;

		/*
		 * Try to divine whether to support Win'95 long filenames
		 */
		if (FAT32(pmp))
			pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
		else {
			if ((error =
			    msdosfs_root(mp, LK_EXCLUSIVE, &rootvp)) != 0)
				return error;
			pmp->pm_flags |= findwin95(VTODE(rootvp)) ?
			    MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME;
			vput(rootvp);
		}
	}
	return 0;
}