diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 9bb48b0..721af55 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -8,7 +8,6 @@ #include -#include #include #include #include diff --git a/util/fusermount.c b/util/fusermount.c new file mode 100644 index 0000000..784fd47 --- /dev/null +++ b/util/fusermount.c @@ -0,0 +1,199 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu) + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUSE_DEV "/proc/fs/fuse/dev" + +const char *progname; + +static int do_mount(const char *dev, const char *mnt, const char *type, + mode_t rootmode, int fd) +{ + int res; + struct fuse_mount_data data; + + data.version = FUSE_KERNEL_VERSION; + data.fd = fd; + data.rootmode = rootmode; + + res = mount(dev, mnt, type, MS_MGC_VAL | MS_NOSUID | MS_NODEV, &data); + if(res == -1) { + fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno)); + return -1; + } + + return 0; +} + +static int check_perm(const char *mnt, struct stat *stbuf) +{ + int res; + + res = lstat(mnt, stbuf); + if(res == -1) { + fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + + if(!S_ISDIR(stbuf->st_mode) && !S_ISREG(stbuf->st_mode)) { + fprintf(stderr, "%s: mountpoint %s is a special file\n", + progname, mnt); + return -1; + } + + if(getuid() != 0) { + if(stbuf->st_uid != getuid()) { + fprintf(stderr, "%s: mountpoint %s not owned by user\n", + progname, mnt); + return -1; + } + + res = access(mnt, R_OK | W_OK | (S_ISDIR(stbuf->st_mode) ? X_OK : 0)); + if(res == -1) { + fprintf(stderr, "%s: user has no full access to mountpoint %s\n", + progname, mnt); + return -1; + } + } + + return 0; +} + +static int mount_fuse(const char *mnt) +{ + int res; + int fd; + const char *dev = FUSE_DEV; + const char *type = "fuse"; + struct stat stbuf; + + res = check_perm(mnt, &stbuf); + if(res == -1) + return -1; + + fd = open(dev, O_RDWR); + if(fd == -1) { + fprintf(stderr, "%s: unable to open fuse device %s: %s\n", progname, + dev, strerror(errno)); + return -1; + } + + res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd); + if(res == -1) + return -1; + + return fd; +} + +static void usage() +{ + fprintf(stderr, + "%s: [options] mountpoint program [args ...]\n" + "Options:\n" + " -h print help\n", + progname); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int a; + const char *mnt = NULL; + char **userprog; + pid_t pid; + int fd; + int status; + int res; + + progname = argv[0]; + + for(a = 1; a < argc; a++) { + if(argv[a][0] != '-') + break; + + switch(argv[a][1]) { + case 'h': + usage(); + break; + + default: + fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]); + exit(1); + } + } + + if(a == argc) { + fprintf(stderr, "%s: Missing mountpoint argument\n", progname); + exit(1); + } + + mnt = argv[a++]; + + if(a == argc) { + fprintf(stderr, "%s: Missing program argument\n", progname); + exit(1); + } + + userprog = argv + a; + + fd = mount_fuse(mnt); + if(fd == -1) + exit(1); + + /* Dup the file descriptor to stdin */ + if(fd != 0) { + dup2(fd, 0); + close(fd); + } + + pid = fork(); + if(pid == -1) { + fprintf(stderr, "%s: Unable to fork: %s\n", progname, strerror(errno)); + umount(mnt); + exit(1); + } + + if(pid == 0) { + /* Drop setuid/setgid permissions */ + setuid(getuid()); + setgid(getgid()); + + execv(userprog[0], userprog); + fprintf(stderr, "%s: failed to exec %s: %s\n", progname, userprog[0], + strerror(errno)); + exit(1); + } + + close(0); + res = waitpid(pid, &status, 0); + if(res == -1) { + fprintf(stderr, "%s: failed to wait for child: %s\n", progname, + strerror(errno)); + exit(1); + } + res = umount(mnt); + if(res == -1) { + fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, + strerror(errno)); + exit(1); + } + + return 0; +}