permission checking implemented
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 20 Dec 2001 15:38:05 +0000 (15:38 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 20 Dec 2001 15:38:05 +0000 (15:38 +0000)
12 files changed:
BUGS
ChangeLog
TODO
include/linux/fuse.h
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/inode.c
lib/fuse.c
lib/fuse_i.h
lib/fuse_mt.c
util/fusermount.c

diff --git a/BUGS b/BUGS
index 3706264b7e36d51f90ff5a8c019316518d7adcf1..5fdce028e472525490fc4d1ff718587d14ba4ac9 100644 (file)
--- 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?
 
index cfa7aef5cb31c241d97ba3964ed62224f111c293..cf7aaa8b0a1f0776794937813c26c60f24e1b6b2 100644 (file)
--- 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>
-
-       * Python bindings by Jeff Epler added
+2001-11-09  Miklos Szeredi <mszeredi@inf.bme.hu>
 
+       * Started ChangeLog
diff --git a/TODO b/TODO
index 2942e4e094c1f4a18977de3f3083117cea828f8d..fbf6d70971bf019bed11811f802068f8dda47822 100644 (file)
--- 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
index fd5ef9c419ed3feb78d35d33aadcb03656ad9759..53cb3f005a20f02d7c9335de32908e07730f5339 100644 (file)
@@ -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 @@ struct fuse_mount_data {
        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 @@ struct fuse_in_header {
        int unique;
        enum fuse_opcode opcode;
        unsigned long ino;
+       unsigned int uid;
+       unsigned int gid;
 };
 
 struct fuse_out_header {
index a3f148512a742935e15494aeb40b448ed86c0d4f..7068d37ad42fefa7510d31f145ec4b54aa1b2fed 100644 (file)
@@ -315,29 +315,14 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
        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 @@ static int fuse_revalidate(struct dentry *entry)
        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)
 {
index b7cb2f4fe28e86e4c04ea353b972ce07c8fb65bf..0622e5108453be7c4548acbf3ebf42bef6ec06a6 100644 (file)
@@ -17,6 +17,14 @@ static int fuse_open(struct inode *inode, struct file *file)
        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;
 
index 27d8eb36f9c57aad13b07c98897d9864887c1abd..262e05debb0347ec40db1b747ae6661024de715e 100644 (file)
@@ -77,7 +77,7 @@ struct fuse_out {
        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 @@ void request_send(struct fuse_conn *fc, struct fuse_in *in,
  */
 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
index 7d211cbd426bc7685129927a4b1134728b198388..7fc5cfef20ab8f463369fd89de5d27836779bd9a 100644 (file)
@@ -32,6 +32,7 @@ static void fuse_clear_inode(struct inode *inode)
        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) 
index 0a0b40a521860c513c431610d039d934f70558e2..541014f4ccb4706684bd760b93e1d96f2c74f384 100644 (file)
@@ -781,6 +781,7 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
     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 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
                in->opcode, in->ino, cmd->buflen);
         fflush(stdout);
     }
+
+    ctx->uid = in->uid;
+    ctx->gid = in->gid;
     
     argsize = cmd->buflen - sizeof(struct fuse_in_header);
         
index 604c297c999b9ae9a24d5df9175cca3c24ee19ae..d587af1364c8addb02904187d4e26f6d3a4890c8 100644 (file)
@@ -37,6 +37,7 @@ struct fuse {
     int numavail;
     struct fuse_context *(*getcontext)(struct fuse *);
     struct fuse_context context;
+    pthread_key_t context_key;
 };
 
 struct fuse_dirhandle {
index 4534d0f721efd92e98c5d153ea55d9ac32d5b4ad..b8756ac9bcef4c347a050adb63b881bd57d50175 100644 (file)
@@ -69,9 +69,28 @@ static void start_thread(struct fuse_worker *w)
     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 @@ void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
     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);
 }
 
index ee51269e51bbb46c33b59e730df0126b24f177e8..94f435fc33a81cd1f4641b341100a0a490e716f8 100644 (file)
@@ -264,7 +264,7 @@ static void restore_privs()
 }
 
 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 @@ static int do_mount(const char *dev, const char *mnt, const char *type,
     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 @@ static int check_perm(const char *mnt, struct stat *stbuf)
     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 @@ static int mount_fuse(const char *mnt)
         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 @@ static void usage()
             "%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 @@ int main(int argc, char *argv[])
     char mypath[PATH_MAX];
     char *unmount_cmd;
     char verstr[128];
+    int flags = 0;
 
     progname = argv[0];
     
@@ -435,6 +438,19 @@ int main(int argc, char *argv[])
             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 @@ int main(int argc, char *argv[])
     userprog = argv + a;
     numargs = argc - a;
     
-    fd = mount_fuse(mnt);
+    fd = mount_fuse(mnt, flags);
     if(fd == -1)
         exit(1);