permission checking implemented
diff --git a/BUGS b/BUGS
index 3706264..5fdce02 100644
--- a/BUGS
+++ b/BUGS
@@ -1,8 +1,5 @@
- It is allowed to mount a directory on a non-directory.
-- When a non-directory is mounted the root inode is not filled in, only at
- the first getattr
-
- I want really low priority for my cached pages. Can they start out
'old' so they will be thrown out on the first oportunity?
diff --git a/ChangeLog b/ChangeLog
index cfa7aef..cf7aaa8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,36 @@
-2001-11-09 Miklos Szeredi <mszeredi@inf.bme.hu>
+2001-12-20 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Added function fuse_get_context() to library API (inspired by
+ patch from Matt Ryan)
+
+ * Added flags to fusermount and to kernel interface to control
+ permission checking
- * Started ChangeLog
+ * Integrated fuse_set_operations() into fuse_new()
+
+2001-12-08 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Applied header protection + extern "C" patch by Roland
+ Bauerschmidt
+
+2001-12-02 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Added perl bindings by Mark Glines
+
+2001-11-21 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Cleaned up way of mounting simple filesystems.
+
+ * fuse_main() helper function added
+
+2001-11-18 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Optimized read/write operations, so that minimal copying of data
+ is done
+
+2001-11-14 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Python bindings by Jeff Epler added
2001-11-13 Miklos Szeredi <mszeredi@inf.bme.hu>
@@ -9,7 +39,6 @@
* FS blocksize is set to PAGE_CACHE_SIZE, blksize attribute from
userspace is ignored
-2001-11-14 Miklos Szeredi <mszeredi@inf.bme.hu>
+2001-11-09 Miklos Szeredi <mszeredi@inf.bme.hu>
- * Python bindings by Jeff Epler added
-
+ * Started ChangeLog
diff --git a/TODO b/TODO
index 2942e4e..fbf6d70 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,5 @@
- Better (but not too complex) library interface for open/read/write/close
- - Permission checking for users other then the owner of the mount
-
- Integrate (parts of) fusermount into mount(8)
- Statfs operation
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index fd5ef9c..53cb3f0 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -9,7 +9,7 @@
/* This file defines the kernel interface of FUSE */
/** Version number of this interface */
-#define FUSE_KERNEL_VERSION 1
+#define FUSE_KERNEL_VERSION 2
/** The inode number of the root indode */
#define FUSE_ROOT_INO 1
@@ -35,6 +35,17 @@
unsigned int flags;
};
+/* FUSE mount flags: */
+
+/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
+module will check permissions based on the file mode. Otherwise no
+permission checking is done in the kernel */
+#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
+
+/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
+ doing the mount will be allowed to access the filesystem */
+#define FUSE_ALLOW_OTHER (1 << 1)
+
struct fuse_attr {
unsigned int mode;
unsigned int nlink;
@@ -149,6 +160,8 @@
int unique;
enum fuse_opcode opcode;
unsigned long ino;
+ unsigned int uid;
+ unsigned int gid;
};
struct fuse_out_header {
diff --git a/kernel/dir.c b/kernel/dir.c
index a3f1485..7068d37 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -315,29 +315,14 @@
return out.h.error;
}
-static int fuse_permission(struct inode *inode, int mask)
-{
- struct fuse_conn *fc = INO_FC(inode);
- /* (too) simple protection */
- if(current->fsuid == fc->uid)
- return 0;
- else
- return -EACCES;
-}
-
-static int fuse_revalidate(struct dentry *entry)
+int fuse_getattr(struct inode *inode)
{
- struct inode *inode = entry->d_inode;
struct fuse_conn *fc = INO_FC(inode);
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_getattr_out arg;
- if(inode->i_ino != FUSE_ROOT_INO &&
- time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
- return 0;
-
in.h.opcode = FUSE_GETATTR;
in.h.ino = inode->i_ino;
out.numargs = 1;
@@ -351,6 +336,57 @@
return out.h.error;
}
+static int fuse_revalidate(struct dentry *entry)
+{
+ struct inode *inode = entry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+
+ if(inode->i_ino == FUSE_ROOT_INO) {
+ if(!(fc->flags & FUSE_ALLOW_OTHER)
+ && current->fsuid != fc->uid)
+ return -EACCES;
+ }
+ else if(time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
+ return 0;
+
+ return fuse_getattr(inode);
+}
+
+static int fuse_permission(struct inode *inode, int mask)
+{
+ struct fuse_conn *fc = INO_FC(inode);
+
+ if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
+ return -EACCES;
+ else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) {
+ int err = vfs_permission(inode, mask);
+
+ /* If permission is denied, try to refresh file
+ attributes. This is also needed, because the root
+ node will at first have no permissions */
+
+ if(err == -EACCES) {
+ err = fuse_getattr(inode);
+ if(!err)
+ err = vfs_permission(inode, mask);
+ }
+
+ /* FIXME: Need some mechanism to revoke permissions:
+ currently if the filesystem suddenly changes the
+ file mode, we will not be informed abot that, and
+ continue to allow access to the file/directory.
+
+ This is actually not so grave, since the user can
+ simply keep access to the file/directory anyway by
+ keeping it open... */
+
+ return err;
+ }
+ else
+ return 0;
+}
+
+
static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
void *dstbuf, filldir_t filldir)
{
diff --git a/kernel/file.c b/kernel/file.c
index b7cb2f4..0622e51 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -17,6 +17,14 @@
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_open_in inarg;
+ /* If opening the root node, no lookup has been performed on
+ it, so the attributes must be refreshed */
+ if(inode->i_ino == FUSE_ROOT_INO) {
+ int err = fuse_getattr(inode);
+ if(err)
+ return err;
+ }
+
memset(&inarg, 0, sizeof(inarg));
inarg.flags = file->f_flags & ~O_EXCL;
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 27d8eb3..262e05d 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -77,7 +77,7 @@
struct fuse_out_arg args[3];
};
-#define FUSE_IN_INIT { {0, 0, 0}, 0}
+#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0}
#define FUSE_OUT_INIT { {0, 0}, 0, 0}
/**
@@ -178,6 +178,11 @@
*/
int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in);
+/**
+ * Get the attributes of a file
+ */
+int fuse_getattr(struct inode *inode);
+
/*
* Local Variables:
* indent-tabs-mode: t
diff --git a/kernel/inode.c b/kernel/inode.c
index 7d211cb..7fc5cfe 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -32,6 +32,7 @@
in = kmalloc(sizeof(struct fuse_in), GFP_NOFS);
if(!in)
return;
+ memset(in, 0, sizeof(struct fuse_in));
inarg = kmalloc(sizeof(struct fuse_forget_in), GFP_NOFS);
if(!inarg)
diff --git a/lib/fuse.c b/lib/fuse.c
index 0a0b40a..541014f 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -781,6 +781,7 @@
struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
void *inarg = cmd->buf + sizeof(struct fuse_in_header);
size_t argsize;
+ struct fuse_context *ctx = fuse_get_context(f);
dec_avail(f);
@@ -789,6 +790,9 @@
in->opcode, in->ino, cmd->buflen);
fflush(stdout);
}
+
+ ctx->uid = in->uid;
+ ctx->gid = in->gid;
argsize = cmd->buflen - sizeof(struct fuse_in_header);
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 604c297..d587af1 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -37,6 +37,7 @@
int numavail;
struct fuse_context *(*getcontext)(struct fuse *);
struct fuse_context context;
+ pthread_key_t context_key;
};
struct fuse_dirhandle {
diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c
index 4534d0f..b8756ac 100644
--- a/lib/fuse_mt.c
+++ b/lib/fuse_mt.c
@@ -69,9 +69,28 @@
pthread_detach(thrid);
}
+static struct fuse_context *mt_getcontext(struct fuse *f)
+{
+ struct fuse_context *ctx;
+
+ ctx = (struct fuse_context *) pthread_getspecific(f->context_key);
+ if(ctx == NULL) {
+ ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
+ pthread_setspecific(f->context_key, ctx);
+ }
+
+ return ctx;
+}
+
+static void mt_freecontext(void *data)
+{
+ free(data);
+}
+
void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
{
struct fuse_worker *w;
+ int res;
w = malloc(sizeof(struct fuse_worker));
w->f = f;
@@ -79,6 +98,12 @@
w->proc = proc;
f->numworker = 1;
+ res = pthread_key_create(&f->context_key, mt_freecontext);
+ if(res != 0) {
+ fprintf(stderr, "Failed to create thread specific key\n");
+ exit(1);
+ }
+ f->getcontext = mt_getcontext;
do_work(w);
}
diff --git a/util/fusermount.c b/util/fusermount.c
index ee51269..94f435f 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -264,7 +264,7 @@
}
static int do_mount(const char *dev, const char *mnt, const char *type,
- mode_t rootmode, int fd)
+ mode_t rootmode, int fd, int fuseflags)
{
int res;
struct fuse_mount_data data;
@@ -282,7 +282,7 @@
data.fd = fd;
data.rootmode = rootmode;
data.uid = getuid();
- data.flags = 0;
+ data.flags = fuseflags;
res = mount(dev, mnt, type, flags, &data);
if(res == -1)
@@ -332,7 +332,7 @@
return 0;
}
-static int mount_fuse(const char *mnt)
+static int mount_fuse(const char *mnt, int flags)
{
int res;
int fd;
@@ -364,7 +364,7 @@
return -1;
}
- res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd);
+ res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd, flags);
if(res == -1)
return -1;
@@ -401,7 +401,9 @@
"%s: [options] mountpoint [program [args ...]]\n"
"Options:\n"
" -h print help\n"
- " -u unmount\n",
+ " -u unmount\n"
+ " -p check default permissions on files\n"
+ " -x allow other users to access the files (only for root)\n",
progname);
exit(1);
}
@@ -419,6 +421,7 @@
char mypath[PATH_MAX];
char *unmount_cmd;
char verstr[128];
+ int flags = 0;
progname = argv[0];
@@ -435,6 +438,19 @@
unmount = 1;
break;
+ case 'p':
+ flags |= FUSE_DEFAULT_PERMISSIONS;
+ break;
+
+ case 'x':
+ if(getuid() != 0) {
+ fprintf(stderr, "%s: option %s is allowed only for root\n",
+ progname, argv[a]);
+ exit(1);
+ }
+ flags |= FUSE_ALLOW_OTHER;
+ break;
+
default:
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]);
exit(1);
@@ -474,7 +490,7 @@
userprog = argv + a;
numargs = argc - a;
- fd = mount_fuse(mnt);
+ fd = mount_fuse(mnt, flags);
if(fd == -1)
exit(1);