aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2001-11-11 18:20:17 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2001-11-11 18:20:17 +0000
commit0a7077f5364454de39fb1ac486d4bd233aa11798 (patch)
tree1eb1c74df8cde602e885f4817836cbd3c7567fbe
parent8cffdb9707f6d2b19a8cf639f1ec159bb5f55695 (diff)
downloadandroid_external_fuse-0a7077f5364454de39fb1ac486d4bd233aa11798.tar.gz
android_external_fuse-0a7077f5364454de39fb1ac486d4bd233aa11798.tar.bz2
android_external_fuse-0a7077f5364454de39fb1ac486d4bd233aa11798.zip
x
-rw-r--r--NEWS2
-rw-r--r--README34
-rw-r--r--TODO11
-rw-r--r--example/fusexmp.c151
-rw-r--r--include/fuse.h58
-rw-r--r--include/linux/fuse.h2
-rw-r--r--kernel/Makefile.am4
-rw-r--r--kernel/dir.c16
-rw-r--r--kernel/fuse_i.h2
-rw-r--r--lib/fuse.c108
-rw-r--r--util/fusermount.c298
11 files changed, 290 insertions, 396 deletions
diff --git a/NEWS b/NEWS
index a0258c7..74ad094 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,3 @@
-What is new in 0.9
+What is new in 0.9:
* Everything
diff --git a/README b/README
index 4c1e64b..679488e 100644
--- a/README
+++ b/README
@@ -11,11 +11,11 @@ You can download the source code releases from
http://sourceforge.net/projects/avf
or alternatively you can use CVS to get the very latest development
-version: set the cvsroot to
+version by setting the cvsroot to
:pserver:anonymous@cvs.avf.sourceforge.net:/cvsroot/avf
-and check out the 'fuse' module.
+and checking out the 'fuse' module.
Installation
============
@@ -49,13 +49,10 @@ steps:
4) ls -al /mnt/whatever
- 5) Be glad!
+ 5) Be glad
-If it doesn't work out, you can ask the me. (Oh yeah, and you need to
-do 'insmod kernel/fuse.o' before running your program, in case you
-forgot).
-
-See the file 'include/fuse.h' for documentation of the library interface.
+If it doesn't work out, please ask! Also see the file 'include/fuse.h' for
+detailed documentation of the library interface.
Security
@@ -65,9 +62,8 @@ If you run 'make install', the fusermount program is installed
set-user-id to root. This is done to allow normal users to mount
their own filesystem implementations.
-There must however be some limitations to forbid the Bad User to do
-Naughty Things with your Beautiful system. Currently those
-limitations are:
+There must however be some limitations, in order to prevent Bad User from
+doing nasty things. Currently those limitations are:
- The user can only mount on a mountpoint, for which it has write
permission
@@ -75,16 +71,15 @@ limitations are:
- The mountpoint is not a sticky directory which isn't owned by the
user (like /tmp usually is)
- - If the user doing the mount is not root, then no other user
- (including root) can access the contents of the mounted
+ - No other user (including root) can access the contents of the mounted
filesystem.
-When linux will have private namespaces (as soon as version 2.5 comes
-out) then this third condition is useless and can be gotten rid of.
+When linux will have private namespaces (as soon as version 2.5 comes out
+hopefully) then this third condition is useless and can be gotten rid of.
-Currently the first two conditions are checked by the fusermount
-program before doing the mount. This has the nice feature, that it's
-totally useless. Here's why:
+Currently the first two conditions are checked by the fusermount program
+before doing the mount. This has the nice feature, that it's totally
+useless. Here's why:
- user creates /tmp/mydir
- user starts fusermount
@@ -96,6 +91,5 @@ totally useless. Here's why:
So to make this secure, the checks must be done by the kernel. And so
there is a patch (patch/ms_permission.patch) which does exactly this.
This is against 2.4.14, but applies to some earlier kernels (not too
-much earlier though), and possibly some later (I couldn't know, could
-I?).
+much earlier though), and possibly some later.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..6dc039a
--- /dev/null
+++ b/TODO
@@ -0,0 +1,11 @@
+ - Better (but not too complex) library interface for open/read/write/close
+
+ - Permission checking for users other then the owner of the mount
+
+ - Improve efficiency of read and write operations
+
+ - Integrate (parts of) fusermount into mount(8)
+
+ - Statfs operation
+
+ - Etc, etc...
diff --git a/example/fusexmp.c b/example/fusexmp.c
index 7c17cf0..2ed35dc 100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
@@ -15,58 +15,25 @@
#include <signal.h>
#include <utime.h>
#include <fcntl.h>
-#include <grp.h>
-#include <sys/fsuid.h>
-static char *mount_point;
+static char *unmount_cmd;
-static int set_creds(struct fuse_cred *cred)
+static int xmp_getattr(const char *path, struct stat *stbuf)
{
int res;
- res = setfsuid(cred->uid);
- if(res == -1)
- return -errno;
-
- res = setfsgid(cred->gid);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static void restore_creds()
-{
- setfsuid(getuid());
- setfsgid(getgid());
-}
-
-static int xmp_getattr(struct fuse_cred *cred, const char *path,
- struct stat *stbuf)
-{
- int res;
-
- res = set_creds(cred);
- if(res)
- return res;
res = lstat(path, stbuf);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf,
- size_t size)
+static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = readlink(path, buf, size - 1);
- restore_creds();
if(res == -1)
return -errno;
@@ -75,18 +42,13 @@ static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf,
}
-static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
- fuse_dirfil_t filler)
+static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
DIR *dp;
struct dirent *de;
- int res;
+ int res = 0;
- res = set_creds(cred);
- if(res)
- return res;
dp = opendir(path);
- restore_creds();
if(dp == NULL)
return -errno;
@@ -100,169 +62,121 @@ static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
return res;
}
-static int xmp_mknod(struct fuse_cred *cred, const char *path, mode_t mode,
- dev_t rdev)
+static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = mknod(path, mode, rdev);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_mkdir(struct fuse_cred *cred, const char *path, mode_t mode)
+static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = mkdir(path, mode);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_unlink(struct fuse_cred *cred, const char *path)
+static int xmp_unlink(const char *path)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = unlink(path);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_rmdir(struct fuse_cred *cred, const char *path)
+static int xmp_rmdir(const char *path)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = rmdir(path);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_symlink(struct fuse_cred *cred, const char *from,
- const char *to)
+static int xmp_symlink(const char *from, const char *to)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = symlink(from, to);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_rename(struct fuse_cred *cred, const char *from, const char *to)
+static int xmp_rename(const char *from, const char *to)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = rename(from, to);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_link(struct fuse_cred *cred, const char *from, const char *to)
+static int xmp_link(const char *from, const char *to)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = link(from, to);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_chmod(struct fuse_cred *cred, const char *path, mode_t mode)
+static int xmp_chmod(const char *path, mode_t mode)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = chmod(path, mode);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_chown(struct fuse_cred *cred, const char *path, uid_t uid,
- gid_t gid)
+static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = lchown(path, uid, gid);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_truncate(struct fuse_cred *cred, const char *path, off_t size)
+static int xmp_truncate(const char *path, off_t size)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = truncate(path, size);
- restore_creds();
if(res == -1)
return -errno;
return 0;
}
-static int xmp_utime(struct fuse_cred *cred, const char *path,
- struct utimbuf *buf)
+static int xmp_utime(const char *path, struct utimbuf *buf)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = utime(path, buf);
- restore_creds();
if(res == -1)
return -errno;
@@ -270,15 +184,11 @@ static int xmp_utime(struct fuse_cred *cred, const char *path,
}
-static int xmp_open(struct fuse_cred *cred, const char *path, int flags)
+static int xmp_open(const char *path, int flags)
{
int res;
- res = set_creds(cred);
- if(res)
- return res;
res = open(path, flags);
- restore_creds();
if(res == -1)
return -errno;
@@ -286,17 +196,12 @@ static int xmp_open(struct fuse_cred *cred, const char *path, int flags)
return 0;
}
-static int xmp_read(struct fuse_cred *cred, const char *path, char *buf,
- size_t size, off_t offset)
+static int xmp_read(const char *path, char *buf, size_t size, off_t offset)
{
int fd;
int res;
- res = set_creds(cred);
- if(res)
- return res;
fd = open(path, O_RDONLY);
- restore_creds();
if(fd == -1)
return -errno;
@@ -308,17 +213,13 @@ static int xmp_read(struct fuse_cred *cred, const char *path, char *buf,
return res;
}
-static int xmp_write(struct fuse_cred *cred, const char *path, const char *buf,
- size_t size, off_t offset)
+static int xmp_write(const char *path, const char *buf, size_t size,
+ off_t offset)
{
int fd;
int res;
- res = set_creds(cred);
- if(res)
- return res;
fd = open(path, O_WRONLY);
- restore_creds();
if(fd == -1)
return -errno;
@@ -381,10 +282,8 @@ static struct fuse_operations xmp_oper = {
static void cleanup()
{
- char *buf = (char *) malloc(strlen(mount_point) + 128);
- sprintf(buf, "fusermount -u %s", mount_point);
- system(buf);
- free(buf);
+ close(0);
+ system(unmount_cmd);
}
int main(int argc, char *argv[])
@@ -395,7 +294,7 @@ int main(int argc, char *argv[])
if(argc < 2) {
fprintf(stderr,
- "usage: %s mount_dir [options] \n"
+ "usage: %s unmount_cmd [options] \n"
"Options:\n"
" -d enable debug output\n"
" -s disable multithreaded operation\n",
@@ -404,7 +303,7 @@ int main(int argc, char *argv[])
}
argctr = 1;
- mount_point = argv[argctr++];
+ unmount_cmd = argv[argctr++];
set_signal_handlers();
atexit(cleanup);
@@ -430,8 +329,6 @@ int main(int argc, char *argv[])
exit(1);
}
- setgroups(0, NULL);
-
fuse = fuse_new(0, flags);
fuse_set_operations(fuse, &xmp_oper);
fuse_loop(fuse);
diff --git a/include/fuse.h b/include/fuse.h
index 3ff3be6..a117211 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -21,32 +21,19 @@ typedef struct fuse_dirhandle *fuse_dirh_t;
/** Function to add an entry in a getdir() operation */
typedef int (*fuse_dirfil_t) (fuse_dirh_t, const char *, int type);
-/** Credentials for an operation, these are determined by the fsuid
- and fsgid of the calling process */
-struct fuse_cred {
- uid_t uid;
- gid_t gid;
- /* FIXME: supplementary groups should also be included */
- /* (And capabilities???) */
-};
-
/**
* The file system operations:
*
* Most of these should work very similarly to the well known UNIX
* file system operations. Exceptions are:
*
- * - All operations get a fuse_cred structure by which the filesystem
- * implementation can check, whether the operation is permitted or
- * not.
- *
* - All operations should return the negated error value (-errno) on
* error.
*
- * - readlink() should fill the buffer with a null terminated string.
- * The buffer size argument includes the space for the terminating
- * null character. If the linkname is too long to fit in the buffer,
- * it should be truncated. The return value should be 0 for success.
+ * - readlink() should fill the buffer with a null terminated string. The
+ * buffer size argument includes the space for the terminating null
+ * character. If the linkname is too long to fit in the buffer, it should
+ * be truncated. The return value should be 0 for success.
*
* - getdir() is the opendir(), readdir(), ..., closedir() sequence
* in one call. For each directory entry the filldir parameter should
@@ -62,25 +49,26 @@ struct fuse_cred {
*
* - read(), write() are not passed a filehandle, but rather a
* pathname. The offset of the read and write is passed as the last
- * argument, like the pread() and pwrite() system calls. */
+ * argument, like the pread() and pwrite() system calls.
+ */
struct fuse_operations {
- int (*getattr) (struct fuse_cred *, const char *, struct stat *);
- int (*readlink) (struct fuse_cred *, const char *, char *, size_t);
- int (*getdir) (struct fuse_cred *, const char *, fuse_dirh_t, fuse_dirfil_t);
- int (*mknod) (struct fuse_cred *, const char *, mode_t, dev_t);
- int (*mkdir) (struct fuse_cred *, const char *, mode_t);
- int (*unlink) (struct fuse_cred *, const char *);
- int (*rmdir) (struct fuse_cred *, const char *);
- int (*symlink) (struct fuse_cred *, const char *, const char *);
- int (*rename) (struct fuse_cred *, const char *, const char *);
- int (*link) (struct fuse_cred *, const char *, const char *);
- int (*chmod) (struct fuse_cred *, const char *, mode_t);
- int (*chown) (struct fuse_cred *, const char *, uid_t, gid_t);
- int (*truncate) (struct fuse_cred *, const char *, off_t);
- int (*utime) (struct fuse_cred *, const char *, struct utimbuf *);
- int (*open) (struct fuse_cred *, const char *, int);
- int (*read) (struct fuse_cred *, const char *, char *, size_t, off_t);
- int (*write) (struct fuse_cred *, const char *, const char *, size_t, off_t);
+ int (*getattr) (const char *, struct stat *);
+ int (*readlink) (const char *, char *, size_t);
+ int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
+ int (*mknod) (const char *, mode_t, dev_t);
+ int (*mkdir) (const char *, mode_t);
+ int (*unlink) (const char *);
+ int (*rmdir) (const char *);
+ int (*symlink) (const char *, const char *);
+ int (*rename) (const char *, const char *);
+ int (*link) (const char *, const char *);
+ int (*chmod) (const char *, mode_t);
+ int (*chown) (const char *, uid_t, gid_t);
+ int (*truncate) (const char *, off_t);
+ int (*utime) (const char *, struct utimbuf *);
+ int (*open) (const char *, int);
+ int (*read) (const char *, char *, size_t, off_t);
+ int (*write) (const char *, const char *, size_t, off_t);
};
/* FUSE flags: */
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 035d0be..d41a957 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -149,8 +149,6 @@ struct fuse_in_header {
int unique;
enum fuse_opcode opcode;
unsigned long ino;
- unsigned int uid;
- unsigned int gid;
};
struct fuse_out_header {
diff --git a/kernel/Makefile.am b/kernel/Makefile.am
index 4edce67..2ea0e3b 100644
--- a/kernel/Makefile.am
+++ b/kernel/Makefile.am
@@ -18,6 +18,10 @@ install-exec-local: fuse.o
$(INSTALL) -m 644 fuse.o $(DESTDIR)$(fusemoduledir)/fuse.o
/sbin/depmod -a
+uninstall-local:
+ rm -f $(DESTDIR)$(fusemoduledir)/fuse.o
+ /sbin/depmod -a
+
clean-local:
rm -f *.o *.s
diff --git a/kernel/dir.c b/kernel/dir.c
index 9a3d4ee..cd6394a 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -117,7 +117,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
return ERR_PTR(ret);
}
-/* create needs to return a positive entry, so this also does a lookup */
+/* create needs to return a positive entry, so this is actually an
+ mknod+lookup */
static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
int rdev)
{
@@ -305,14 +306,11 @@ static int fuse_permission(struct inode *inode, int mask)
{
struct fuse_conn *fc = INO_FC(inode);
- /* (too) simple protection for non-privileged mounts */
- if(fc->uid) {
- if(current->fsuid == fc->uid)
- return 0;
- else
- return -EACCES;
- }
- return 0;
+ /* (too) simple protection */
+ if(current->fsuid == fc->uid)
+ return 0;
+ else
+ return -EACCES;
}
static int fuse_revalidate(struct dentry *entry)
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 32106af..e8dde37 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -95,7 +95,7 @@ struct fuse_out {
void *arg;
};
-#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0, 0 }
+#define FUSE_IN_INIT { {0, 0, 0}, 0, 0 }
#define FUSE_OUT_INIT { {0, 0}, 0, 0, 0 }
diff --git a/lib/fuse.c b/lib/fuse.c
index e645a71..3f8a46b 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -354,33 +354,28 @@ static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
}
res = write(f->fd, outbuf, outsize);
- if(res == -1)
- perror("writing fuse device");
+ if(res == -1) {
+ /* ENOENT means the operation was interrupted */
+ if(errno != ENOENT)
+ perror("writing fuse device");
+ }
free(outbuf);
}
-static void fill_cred(struct fuse_in_header *in, struct fuse_cred *cred)
-{
- cred->uid = in->uid;
- cred->gid = in->gid;
-}
-
static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
{
int res;
char *path;
struct stat buf;
struct fuse_lookup_out arg;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path_name(f, in->ino, name);
if(path != NULL) {
res = -ENOSYS;
if(f->op.getattr)
- res = f->op.getattr(&cred, path, &buf);
+ res = f->op.getattr(path, &buf);
free(path);
}
if(res == 0) {
@@ -402,15 +397,13 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
char *path;
struct stat buf;
struct fuse_getattr_out arg;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
res = -ENOSYS;
if(f->op.getattr)
- res = f->op.getattr(&cred, path, &buf);
+ res = f->op.getattr(path, &buf);
free(path);
}
if(res == 0)
@@ -419,20 +412,19 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
send_reply(f, in, res, &arg, sizeof(arg));
}
-int do_chmod(struct fuse *f, struct fuse_cred *cred, const char *path,
- struct fuse_attr *attr)
+int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
{
int res;
res = -ENOSYS;
if(f->op.chmod)
- res = f->op.chmod(cred, path, attr->mode);
+ res = f->op.chmod(path, attr->mode);
return res;
}
-int do_chown(struct fuse *f, struct fuse_cred *cred, const char *path,
- struct fuse_attr *attr, int valid)
+int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
+ int valid)
{
int res;
uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
@@ -440,25 +432,23 @@ int do_chown(struct fuse *f, struct fuse_cred *cred, const char *path,
res = -ENOSYS;
if(f->op.chown)
- res = f->op.chown(cred, path, uid, gid);
+ res = f->op.chown(path, uid, gid);
return res;
}
-int do_truncate(struct fuse *f, struct fuse_cred *cred, const char *path,
- struct fuse_attr *attr)
+int do_truncate(struct fuse *f, const char *path, struct fuse_attr *attr)
{
int res;
res = -ENOSYS;
if(f->op.truncate)
- res = f->op.truncate(cred, path, attr->size);
+ res = f->op.truncate(path, attr->size);
return res;
}
-int do_utime(struct fuse *f, struct fuse_cred *cred, const char *path,
- struct fuse_attr *attr)
+int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
{
int res;
struct utimbuf buf;
@@ -466,7 +456,7 @@ int do_utime(struct fuse *f, struct fuse_cred *cred, const char *path,
buf.modtime = attr->mtime;
res = -ENOSYS;
if(f->op.utime)
- res = f->op.utime(cred, path, &buf);
+ res = f->op.utime(path, &buf);
return res;
}
@@ -479,9 +469,7 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
int valid = arg->valid;
struct fuse_attr *attr = &arg->attr;
struct fuse_setattr_out outarg;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
@@ -489,16 +477,16 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
if(f->op.getattr) {
res = 0;
if(!res && (valid & FATTR_MODE))
- res = do_chmod(f, &cred, path, attr);
+ res = do_chmod(f, path, attr);
if(!res && (valid & (FATTR_UID | FATTR_GID)))
- res = do_chown(f, &cred, path, attr, valid);
+ res = do_chown(f, path, attr, valid);
if(!res && (valid & FATTR_SIZE))
- res = do_truncate(f, &cred, path, attr);
+ res = do_truncate(f, path, attr);
if(!res && (valid & FATTR_UTIME))
- res = do_utime(f, &cred, path, attr);
+ res = do_utime(f, path, attr);
if(!res) {
struct stat buf;
- res = f->op.getattr(&cred, path, &buf);
+ res = f->op.getattr(path, &buf);
if(!res)
convert_stat(&buf, &outarg.attr);
}
@@ -513,15 +501,13 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in)
int res;
char link[PATH_MAX + 1];
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
res = -ENOSYS;
if(f->op.readlink)
- res = f->op.readlink(&cred, path, link, sizeof(link));
+ res = f->op.readlink(path, link, sizeof(link));
free(path);
}
link[PATH_MAX] = '\0';
@@ -534,9 +520,7 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
struct fuse_getdir_out arg;
struct fuse_dirhandle dh;
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
dh.fuse = f;
dh.fp = tmpfile();
dh.dir = in->ino;
@@ -545,7 +529,7 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
if(path != NULL) {
res = -ENOSYS;
if(f->op.getdir)
- res = f->op.getdir(&cred, path, &dh, (fuse_dirfil_t) fill_dir);
+ res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
free(path);
}
fflush(dh.fp);
@@ -561,17 +545,15 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in,
char *path;
struct fuse_mknod_out outarg;
struct stat buf;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path_name(f, in->ino, inarg->name);
if(path != NULL) {
res = -ENOSYS;
if(f->op.mknod && f->op.getattr) {
- res = f->op.mknod(&cred, path, inarg->mode, inarg->rdev);
+ res = f->op.mknod(path, inarg->mode, inarg->rdev);
if(res == 0)
- res = f->op.getattr(&cred, path, &buf);
+ res = f->op.getattr(path, &buf);
}
free(path);
}
@@ -589,15 +571,13 @@ static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
{
int res;
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path_name(f, in->ino, inarg->name);
if(path != NULL) {
res = -ENOSYS;
if(f->op.mkdir)
- res = f->op.mkdir(&cred, path, inarg->mode);
+ res = f->op.mkdir(path, inarg->mode);
free(path);
}
send_reply(f, in, res, NULL, 0);
@@ -607,20 +587,18 @@ static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
{
int res;
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path_name(f, in->ino, name);
if(path != NULL) {
res = -ENOSYS;
if(in->opcode == FUSE_UNLINK) {
if(f->op.unlink)
- res = f->op.unlink(&cred, path);
+ res = f->op.unlink(path);
}
else {
if(f->op.rmdir)
- res = f->op.rmdir(&cred, path);
+ res = f->op.rmdir(path);
}
free(path);
}
@@ -634,15 +612,13 @@ static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
{
int res;
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path_name(f, in->ino, name);
if(path != NULL) {
res = -ENOSYS;
if(f->op.symlink)
- res = f->op.symlink(&cred, link, path);
+ res = f->op.symlink(link, path);
free(path);
}
send_reply(f, in, res, NULL, 0);
@@ -658,9 +634,7 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
char *newname = inarg->names + strlen(oldname) + 1;
char *oldpath;
char *newpath;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
oldpath = get_path_name(f, olddir, oldname);
if(oldpath != NULL) {
@@ -668,7 +642,7 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
if(newpath != NULL) {
res = -ENOSYS;
if(f->op.rename)
- res = f->op.rename(&cred, oldpath, newpath);
+ res = f->op.rename(oldpath, newpath);
if(res == 0)
rename_node(f, olddir, oldname, newdir, newname);
free(newpath);
@@ -684,9 +658,7 @@ static void do_link(struct fuse *f, struct fuse_in_header *in,
int res;
char *oldpath;
char *newpath;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
oldpath = get_path(f, in->ino);
if(oldpath != NULL) {
@@ -694,7 +666,7 @@ static void do_link(struct fuse *f, struct fuse_in_header *in,
if(newpath != NULL) {
res = -ENOSYS;
if(f->op.link)
- res = f->op.link(&cred, oldpath, newpath);
+ res = f->op.link(oldpath, newpath);
free(newpath);
}
free(oldpath);
@@ -707,15 +679,13 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
{
int res;
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
res = -ENOSYS;
if(f->op.open)
- res = f->op.open(&cred, path, arg->flags);
+ res = f->op.open(path, arg->flags);
free(path);
}
send_reply(f, in, res, NULL, 0);
@@ -728,15 +698,13 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
char *path;
char *buf = (char *) malloc(arg->size);
size_t size;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
res = -ENOSYS;
if(f->op.read)
- res = f->op.read(&cred, path, buf, arg->size, arg->offset);
+ res = f->op.read(path, buf, arg->size, arg->offset);
free(path);
}
@@ -755,15 +723,13 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
{
int res;
char *path;
- struct fuse_cred cred;
- fill_cred(in, &cred);
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
res = -ENOSYS;
if(f->op.write)
- res = f->op.write(&cred, path, arg->buf, arg->size, arg->offset);
+ res = f->op.write(path, arg->buf, arg->size, arg->offset);
free(path);
}
@@ -905,11 +871,13 @@ void fuse_loop(struct fuse *f)
res = read(f->fd, inbuf, sizeof(inbuf));
if(res == -1) {
perror("reading fuse device");
- continue;
+ /* BAD... This will happen again */
+ exit(1);
}
if((size_t) res < sizeof(struct fuse_in_header)) {
fprintf(stderr, "short read on fuse device\n");
- continue;
+ /* Cannot happen */
+ exit(1);
}
cmd = (struct cmd *) malloc(sizeof(struct cmd));
diff --git a/util/fusermount.c b/util/fusermount.c
index 72fa673..ac30c65 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -5,6 +5,17 @@
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
+/* This program does the mounting and unmounting of FUSE filesystems */
+
+/*
+ * NOTE: This program should be part of (or be called from) /bin/mount
+ *
+ * Unless that is done, operations on /etc/mtab are not under lock, and so
+ * data in it may be lost. (I will _not_ reimplement that locking, and
+ * anyway that should be done in libc, if possible. But probably it is
+ * not).
+ *
+ */
#include <stdio.h>
#include <stdlib.h>
@@ -13,6 +24,8 @@
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
+#include <mntent.h>
+#include <limits.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mount.h>
@@ -28,12 +41,6 @@
#define FUSE_DEV "/proc/fs/fuse/dev"
const char *progname;
-const char *fusermnt = "/etc/fusermnt";
-const char *fusermnt_temp = "/etc/fusermnt~";
-
-#define FUSE_USERNAME_MAX 256
-#define FUSE_PATH_MAX 4096
-#define FUSEMNT_LINE_MAX (FUSE_USERNAME_MAX + 1 + FUSE_PATH_MAX + 1)
static const char *get_user_name()
{
@@ -46,152 +53,136 @@ static const char *get_user_name()
}
}
-static int fusermnt_lock()
+static int add_mount(const char *dev, const char *mnt, const char *type)
{
int res;
- const char *lockfile = fusermnt;
- int fd = open(lockfile, O_WRONLY | O_CREAT, 0644);
- if(fd == -1) {
- fprintf(stderr, "%s: failed to open lockfile %s: %s\n", progname,
- lockfile, strerror(errno));
- return -1;
- }
- res = lockf(fd, F_LOCK, 0);
- if(res == -1) {
- fprintf(stderr, "%s: failed to lock file %s: %s\n", progname,
- lockfile, strerror(errno));
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-static void fusermnt_unlock(int fd)
-{
- lockf(fd, F_UNLCK, 0);
- close(fd);
-}
-
-
-static int add_mount(const char *mnt)
-{
+ const char *mtab = _PATH_MOUNTED;
+ struct mntent ent;
FILE *fp;
- int lockfd;
- const char *user = get_user_name();
- if(user == NULL)
- return -1;
-
- lockfd = fusermnt_lock();
- if(lockfd == -1)
- return -1;
+ char *opts;
- fp = fopen(fusermnt, "a");
+ fp = setmntent(mtab, "a");
if(fp == NULL) {
- fprintf(stderr, "%s: could not open %s for writing: %s\n", progname,
- fusermnt, strerror(errno));
+ fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab,
+ strerror(errno));
+ return -1;
+ }
+
+ if(getuid() != 0) {
+ const char *user = get_user_name();
+ if(user == NULL)
+ return -1;
+
+ opts = malloc(strlen(user) + 128);
+ if(opts != NULL)
+ sprintf(opts, "rw,nosuid,nodev,user=%s", user);
+ }
+ else
+ opts = strdup("rw,nosuid,nodev");
+
+ if(opts == NULL)
+ return -1;
+
+ ent.mnt_fsname = (char *) dev;
+ ent.mnt_dir = (char *) mnt;
+ ent.mnt_type = (char *) type;
+ ent.mnt_opts = opts;
+ ent.mnt_freq = 0;
+ ent.mnt_passno = 0;
+ res = addmntent(fp, &ent);
+ if(res != 0) {
+ fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
+ mtab, strerror(errno));
return -1;
}
- fprintf(fp, "%s %s\n", user, mnt);
- fclose(fp);
-
- fusermnt_unlock(lockfd);
+
+ endmntent(fp);
return 0;
}
static int remove_mount(const char *mnt)
{
+ int res;
+ const char *mtab = _PATH_MOUNTED;
+ const char *mtab_new = _PATH_MOUNTED "~";
+ struct mntent *entp;
FILE *fp;
FILE *newfp;
- int lockfd;
+ const char *user = NULL;
int found;
- char buf[FUSEMNT_LINE_MAX + 1];
- const char *user = get_user_name();
- if(user == NULL)
- return -1;
-
- lockfd = fusermnt_lock();
- if(lockfd == -1)
- return -1;
- fp = fopen(fusermnt, "r");
+ fp = setmntent(mtab, "r");
if(fp == NULL) {
- fprintf(stderr, "%s: could not open %s for reading: %s\n", progname,
- fusermnt, strerror(errno));
- fusermnt_unlock(lockfd);
- return -1;
+ fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab,
+ strerror(errno));
+ return -1;
}
-
- newfp = fopen(fusermnt_temp, "w");
+
+ newfp = setmntent(mtab_new, "w");
if(newfp == NULL) {
- fprintf(stderr, "%s: could not open %s for writing: %s\n", progname,
- fusermnt_temp, strerror(errno));
- fclose(fp);
- fusermnt_unlock(lockfd);
- return -1;
+ fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab_new,
+ strerror(errno));
+ return -1;
}
+ if(getuid() != 0) {
+ user = get_user_name();
+ if(user == NULL)
+ return -1;
+ }
+
found = 0;
- while(fgets(buf, sizeof(buf), fp) != NULL) {
- char *end = buf + strlen(buf) - 1;
- char *p;
- if(*end != '\n') {
- fprintf(stderr, "%s: line too long in file %s\n", progname,
- fusermnt);
- while(fgets(buf, sizeof(buf), fp) != NULL) {
- char *end = buf + strlen(buf) - 1;
- if(*end == '\n')
- break;
+ while((entp = getmntent(fp)) != NULL) {
+ int remove = 0;
+ if(!found && strcmp(entp->mnt_dir, mnt) == 0 &&
+ strcmp(entp->mnt_type, "fuse") == 0) {
+ if(user == NULL)
+ remove = 1;
+ else {
+ char *p = strstr(entp->mnt_opts, "user=");
+ if(p != NULL && strcmp(p + 5, user) == 0)
+ remove = 1;
}
- continue;
- }
- *end = '\0';
-
- for(p = buf; *p != '\0' && *p != ' '; p++);
- if(*p == '\0') {
- fprintf(stderr, "%s: malformed line in file %s\n", progname,
- fusermnt);
- continue;
}
- *p = '\0';
- p++;
- if(!found && strcmp(user, buf) == 0 && strcmp(mnt, p) == 0) {
- int res = umount(mnt);
+ if(remove) {
+ res = umount(mnt);
if(res == -1) {
- found = -1;
- fprintf(stderr, "%s: umount of %s failed: %s\n", progname,
+ fprintf(stderr, "%s: failed to unmount %s: %s\n", progname,
mnt, strerror(errno));
+ found = -1;
break;
}
found = 1;
}
- else
- fprintf(newfp, "%s %s\n", buf, p);
+ else {
+ res = addmntent(newfp, entp);
+ if(res != 0) {
+ fprintf(stderr, "%s: failed to add entry to %s: %s", progname,
+ mtab_new, strerror(errno));
+
+ }
+ }
}
-
- fclose(fp);
- fclose(newfp);
+
+ endmntent(fp);
+ endmntent(newfp);
if(found == 1) {
- int res;
- res = rename(fusermnt_temp, fusermnt);
+ res = rename(mtab_new, mtab);
if(res == -1) {
- fprintf(stderr, "%s: failed to rename %s to %s: %s\n",
- progname, fusermnt_temp, fusermnt, strerror(errno));
- fusermnt_unlock(lockfd);
+ fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
+ mtab_new, mtab, strerror(errno));
return -1;
}
}
else {
if(!found)
fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
- mnt, fusermnt);
- unlink(fusermnt_temp);
- fusermnt_unlock(lockfd);
+ mnt, mtab);
+ unlink(mtab_new);
return -1;
}
- fusermnt_unlock(lockfd);
return 0;
}
@@ -348,6 +339,19 @@ static int mount_fuse(const char *mnt)
fd = open(dev, O_RDWR);
if(fd == -1) {
+ int status;
+ pid_t pid = fork();
+ if(pid == 0) {
+ setuid(0);
+ execl("/sbin/modprobe", "modprobe", "fuse", NULL);
+ exit(1);
+ }
+ if(pid != -1)
+ waitpid(pid, &status, 0);
+
+ 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;
@@ -357,7 +361,7 @@ static int mount_fuse(const char *mnt)
if(res == -1)
return -1;
- res = add_mount(mnt);
+ res = add_mount(dev, mnt, type);
if(res == -1) {
umount(mnt);
return -1;
@@ -366,16 +370,22 @@ static int mount_fuse(const char *mnt)
return fd;
}
-static int do_umount(const char *mnt)
+static char *resolve_path(const char *orig, int unmount)
{
- int res;
+ char buf[PATH_MAX];
- res = remove_mount(mnt);
- if(res == -1)
- return -1;
+ /* Resolving at unmount can only be done very carefully, not touching
+ the mountpoint... So for the moment it's not done. */
+ if(unmount)
+ return strdup(orig);
- umount(mnt);
- return 0;
+ if(realpath(orig, buf) == NULL) {
+ fprintf(stderr, "%s: Bad mount point %s: %s\n", progname, orig,
+ strerror(errno));
+ return NULL;
+ }
+
+ return strdup(buf);
}
static void usage()
@@ -384,7 +394,7 @@ static void usage()
"%s: [options] mountpoint [program [args ...]]\n"
"Options:\n"
" -h print help\n"
- " -u umount\n",
+ " -u unmount\n",
progname);
exit(1);
}
@@ -394,11 +404,14 @@ int main(int argc, char *argv[])
int a;
int fd;
int res;
- char *mnt = NULL;
- int umount = 0;
+ char *origmnt;
+ char *mnt;
+ int unmount = 0;
char **userprog;
int numargs;
char **newargv;
+ char mypath[PATH_MAX];
+ char *unmount_cmd;
progname = argv[0];
@@ -412,7 +425,7 @@ int main(int argc, char *argv[])
break;
case 'u':
- umount = 1;
+ unmount = 1;
break;
default:
@@ -426,10 +439,20 @@ int main(int argc, char *argv[])
exit(1);
}
- mnt = argv[a++];
+ origmnt = argv[a++];
+
+ if(getpid() != 0)
+ drop_privs();
+
+ mnt = resolve_path(origmnt, unmount);
+ if(mnt == NULL)
+ exit(1);
+
+ if(getpid() != 0)
+ restore_privs();
- if(umount) {
- res = do_umount(mnt);
+ if(unmount) {
+ res = remove_mount(mnt);
if(res == -1)
exit(1);
@@ -454,23 +477,36 @@ int main(int argc, char *argv[])
close(fd);
}
+ /* Strangely this doesn't work after dropping permissions... */
+ res = readlink("/proc/self/exe", mypath, sizeof(mypath) - 1);
+ if(res == -1) {
+ fprintf(stderr, "%s: failed to determine self path: %s\n",
+ progname, strerror(errno));
+ strcpy(mypath, "fusermount");
+ fprintf(stderr, "using %s as the default\n", mypath);
+ }
+ else
+ mypath[res] = '\0';
+
/* Drop setuid/setgid permissions */
setuid(getuid());
setgid(getgid());
-
+
+ unmount_cmd = (char *) malloc(strlen(mypath) + strlen(mnt) + 64);
+ sprintf(unmount_cmd, "%s -u %s", mypath, mnt);
+
newargv = (char **) malloc(sizeof(char *) * (numargs + 2));
newargv[0] = userprog[0];
- newargv[1] = mnt;
+ newargv[1] = unmount_cmd;
for(a = 1; a < numargs; a++)
newargv[a+1] = userprog[a];
newargv[numargs+1] = NULL;
- execv(userprog[0], newargv);
+ execvp(userprog[0], newargv);
fprintf(stderr, "%s: failed to exec %s: %s\n", progname, userprog[0],
strerror(errno));
- execl("/proc/self/exe", progname, "-u", mnt, NULL);
- fprintf(stderr, "%s: failed to exec self: %s\n", progname,
- strerror(errno));
- exit(1);
+ close(0);
+ system(unmount_cmd);
+ return 1;
}