#include <linux/init.h>
#include <linux/module.h>
#ifdef KERNEL_2_6
-#include <linux/moduleparam.h>
#include <linux/parser.h>
#include <linux/statfs.h>
#else
-#include <linux/proc_fs.h>
#include "compat/parser.h"
#endif
spinlock_t fuse_lock;
static kmem_cache_t *fuse_inode_cachep;
-static int mount_count;
-
-static int user_allow_other;
-#ifdef KERNEL_2_6
-module_param(user_allow_other, int, 0644);
-#else
-MODULE_PARM(user_allow_other, "i");
-#endif
-MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
-
-static int mount_max = 1000;
-#ifdef KERNEL_2_6
-module_param(mount_max, int, 0644);
-#else
-MODULE_PARM(mount_max, "i");
-#endif
-MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)");
#define FUSE_SUPER_MAGIC 0x65735546
struct fuse_conn *fc = get_fuse_conn_super(sb);
spin_lock(&fuse_lock);
- mount_count --;
fc->sb = NULL;
fc->user_id = 0;
fc->flags = 0;
.show_options = fuse_show_options,
};
-static int inc_mount_count(void)
-{
- int success = 0;
- spin_lock(&fuse_lock);
- mount_count ++;
- if (mount_max == -1 || mount_count <= mount_max)
- success = 1;
- spin_unlock(&fuse_lock);
- return success;
-}
-
static int fuse_fill_super(struct super_block *sb, void *data, int silent)
{
struct fuse_conn *fc;
if (!parse_fuse_opt((char *) data, &d))
return -EINVAL;
- if (!user_allow_other &&
- (d.flags & (FUSE_ALLOW_OTHER | FUSE_ALLOW_ROOT)) &&
- current->uid != 0)
- return -EPERM;
-
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = FUSE_SUPER_MAGIC;
*get_fuse_conn_super_p(sb) = fc;
- err = -ENFILE;
- if (!inc_mount_count() && current->uid != 0)
- goto err;
-
err = -ENOMEM;
root = get_root_inode(sb, d.rootmode);
if (root == NULL)
err:
spin_lock(&fuse_lock);
- mount_count --;
fc->sb = NULL;
fuse_release_conn(fc);
spin_unlock(&fuse_lock);
#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
#define FUSE_DEV_NEW "/dev/fuse"
#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
+#define FUSE_CONF "/etc/fuse.conf"
#define FUSE_MAJOR 10
#define FUSE_MINOR 229
-const char *progname;
+static const char *progname;
+
+static int user_allow_other = 0;
+static int mount_max = 1000;
static const char *get_user_name()
{
if (mtablock >= 0) {
res = lockf(mtablock, F_LOCK, 0);
if (res < 0)
- perror("error getting lock");
+ fprintf(stderr, "%s: error getting lock", progname);
} else
- fprintf(stderr, "unable to open fuse lock file, continuing anyway\n");
+ fprintf(stderr, "%s: unable to open fuse lock file\n", progname);
return mtablock;
}
fp = setmntent(mtab, "r");
if (fp == NULL) {
- fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab,
+ fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
strerror(errno));
return -1;
}
newfp = setmntent(mtab_new, "w");
if (newfp == NULL) {
- fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab_new,
+ fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new,
strerror(errno));
return -1;
}
return 0;
}
+static int count_fuse_fs()
+{
+ struct mntent *entp;
+ int count = 0;
+ const char *mtab = _PATH_MOUNTED;
+ FILE *fp = setmntent(mtab, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "%s: faild to open %s: %s\n", progname, mtab,
+ strerror(errno));
+ return -1;
+ }
+ while ((entp = getmntent(fp)) != NULL) {
+ if (strcmp(entp->mnt_type, "fuse") == 0)
+ count ++;
+ }
+ endmntent(fp);
+ return count;
+}
static int do_unmount(const char *mnt, int quiet, int lazy, const char *mtab,
const char *mtab_new)
}
#endif /* USE_UCLIBC */
+static void read_conf(void)
+{
+ FILE *fp = fopen(FUSE_CONF, "r");
+ if (fp != NULL) {
+ char line[256];
+ int isnewline = 1;
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (isnewline) {
+ int tmp;
+ if (strcmp(line, "user_allow_other\n") == 0)
+ user_allow_other = 1;
+ else if (sscanf(line, "mount_max = %i\n", &tmp) == 1)
+ mount_max = tmp;
+ }
+ if(line[strlen(line)-1] == '\n')
+ isnewline = 1;
+ else
+ isnewline = 0;
+ }
+ fclose(fp);
+ } else if (errno != ENOENT) {
+ fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
+ strerror(errno));
+ }
+}
+
static int begins_with(const char *s, const char *beg)
{
if (strncmp(s, beg, strlen(beg)) == 0)
return 0;
}
+static int opt_eq(const char *s, unsigned len, const char *opt)
+{
+ if(strlen(opt) == len && strncmp(s, opt, len) == 0)
+ return 1;
+ else
+ return 0;
+}
+
static int do_mount(const char *mnt, const char *type, mode_t rootmode,
int fd, const char *opts, const char *dev, char **fsnamep,
char **mnt_optsp)
int on;
int flag;
int skip_option = 0;
- const char *large_read_opt = "large_read";
- if (len == strlen(large_read_opt) &&
- strncmp(large_read_opt, s, len) == 0) {
+ if (opt_eq(s, len, "large_read")) {
struct utsname utsname;
unsigned kmaj, kmin;
res = uname(&utsname);
skip_option = 1;
}
}
+ if (getuid() != 0 && !user_allow_other &&
+ (opt_eq(s, len, "allow_other") ||
+ opt_eq(s, len, "allow_root"))) {
+ fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
+ free(optbuf);
+ return -1;
+ }
if (!skip_option) {
if (find_mount_flag(s, len, &on, &flag)) {
if (on)
if (fd >= 0)
return fd;
- fprintf(stderr, "fuse device not found, try 'modprobe fuse' first\n");
+ fprintf(stderr, "%s: fuse device not found, try 'modprobe fuse' first\n",
+ progname);
return -1;
}
char *mnt_opts;
const char *real_mnt = mnt;
int currdir_fd = -1;
+ int mtablock = -1;
fd = open_fuse_device(&dev);
if (fd == -1)
return -1;
-
+
+#ifndef USE_UCLIBC
+ if (geteuid() == 0) {
+ mtablock = lock_mtab();
+ if (mtablock < 0) {
+ close(fd);
+ return -1;
+ }
+ }
+#endif
+
if (getuid() != 0) {
res = drop_privs();
- if (res == -1)
+ if (res == -1) {
+ close(fd);
+#ifndef USE_UCLIBC
+ unlock_mtab(mtablock);
+#endif
return -1;
+ }
+ }
+
+ read_conf();
+
+ if (getuid != 0 && mount_max != -1) {
+ int mount_count = count_fuse_fs();
+ if (mount_count >= mount_max) {
+ fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
+ close(fd);
+#ifndef USE_UCLIBC
+ unlock_mtab(mtablock);
+#endif
+ return -1;
+ }
}
res = check_version(dev);
if (getuid() != 0)
restore_privs();
- if (res == -1)
+ if (res == -1) {
+ close(fd);
+#ifndef USE_UCLIBC
+ unlock_mtab(mtablock);
+#endif
return -1;
+ }
if (currdir_fd != -1) {
fchdir(currdir_fd);
#ifndef USE_UCLIBC
if (geteuid() == 0) {
- int mtablock = lock_mtab();
res = add_mount(fsname, mnt, type, mnt_opts);
unlock_mtab(mtablock);
if (res == -1) {
umount2(mnt, 2); /* lazy umount */
+ close(fd);
return -1;
}
}