[AC_CHECK_LIB([leveldb], [leveldb_open], [with_system_leveldb=yes], [], [-lsnappy -lpthread])])
AM_CONDITIONAL(WITH_SYSTEM_LEVELDB, [ test "$with_system_leveldb" = "yes" ])
+# look for fuse_getgroups and define FUSE_GETGROUPS if found
+AC_CHECK_FUNCS([fuse_getgroups])
+
# use system libs3?
AC_ARG_WITH([system-libs3],
[AS_HELP_STRING([--with-system-libs3], [use system libs3])],
: Dispatcher(m->cct), cct(m->cct), logger(NULL), timer(m->cct, client_lock),
ino_invalidate_cb(NULL),
ino_invalidate_cb_handle(NULL),
+ getgroups_cb(NULL),
+ getgroups_cb_handle(NULL),
async_ino_invalidator(m->cct),
tick_event(NULL),
monclient(mc), messenger(m), whoami(m->get_myname().num()),
m->put();
}
+int Client::check_permissions(Inode *in, int flags, int uid, int gid)
+{
+ gid_t *sgids = NULL;
+ int sgid_count = 0;
+ if (getgroups_cb) {
+ sgid_count = getgroups_cb(getgroups_cb_handle, uid, &sgids);
+ if (sgid_count < 0) {
+ ldout(cct, 3) << "getgroups failed!" << dendl;
+ return sgid_count;
+ }
+ }
+ // check permissions before doing anything else
+ if (!in->check_mode(uid, gid, sgids, sgid_count, flags)) {
+ return -EACCES;
+ }
+ return 0;
+}
+
// -------------------
// MOUNT
}
-
-
-
-
-
/****** file i/o **********/
int Client::open(const char *relpath, int flags, mode_t mode)
{
return 0;
}
-int Client::_open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid)
+int Client::_open(Inode *in, int flags, mode_t mode, Fh **fhp, int uid, int gid)
{
+ int ret;
+ if (uid < 0) {
+ uid = geteuid();
+ gid = getegid();
+ }
+ ret = check_permissions(in, flags, uid, gid);
+ if (ret < 0)
+ return ret;
+
int cmode = ceph_flags_to_mode(flags);
if (cmode < 0)
return -EINVAL;
// was Fh opened as writeable?
if ((f->mode & CEPH_FILE_MODE_WR) == 0)
- return -EINVAL;
+ return -EBADF;
// use/adjust fd pos?
if (offset < 0) {
async_ino_invalidator.start();
}
+void Client::ll_register_getgroups_cb(client_getgroups_callback_t cb, void *handle)
+{
+ Mutex::Locker l(client_lock);
+ getgroups_cb = cb;
+ getgroups_cb_handle = handle;
+}
+
int Client::_sync_fs()
{
ldout(cct, 10) << "_sync_fs" << dendl;
typedef void (*client_ino_callback_t)(void *handle, vinodeno_t ino, int64_t off, int64_t len);
+typedef int (*client_getgroups_callback_t)(void *handle, uid_t uid, gid_t **sgids);
// ========================================================
// client interface
client_ino_callback_t ino_invalidate_cb;
void *ino_invalidate_cb_handle;
+ client_getgroups_callback_t getgroups_cb;
+ void *getgroups_cb_handle;
+
Finisher async_ino_invalidator;
Context *tick_event;
int get_or_create(Inode *dir, const char* name,
Dentry **pdn, bool expect_null=false);
+ int check_permissions(Inode *in, int flags, int uid, int gid);
+
public:
int mount(const std::string &mount_root);
void unmount();
int ll_statfs(vinodeno_t vino, struct statvfs *stbuf);
void ll_register_ino_invalidate_cb(client_ino_callback_t cb, void *handle);
+
+ void ll_register_getgroups_cb(client_getgroups_callback_t cb, void *handle);
};
#endif
}
return dir;
}
+
+bool Inode::check_mode(uid_t ruid, gid_t rgid, gid_t *sgids, int sgids_count, uint32_t rflags)
+{
+ int mflags = rflags & O_ACCMODE;
+ int fmode = 0;
+
+ if ((mflags & O_WRONLY) == O_WRONLY)
+ fmode |= 2;
+ if ((mflags & O_RDONLY) == O_RDONLY)
+ fmode |= 4;
+ if ((mflags & O_RDWR) == O_RDWR)
+ fmode |= 6;
+
+ // if uid is owner, owner entry determines access
+ if (uid == ruid) {
+ fmode = fmode << 6;
+ } else if (gid == rgid) {
+ // if a gid or sgid matches the owning group, group entry determines access
+ fmode = fmode << 3;
+ } else {
+ int i = 0;
+ for (; i < sgids_count; ++i) {
+ if (sgids[i] == gid) {
+ fmode = fmode << 3;
+ break;
+ }
+ }
+ }
+
+ return (mode & fmode) == fmode;
+}
vinodeno_t vino() { return vinodeno_t(ino, snapid); }
+ bool check_mode(uid_t uid, gid_t gid, gid_t *sgids, int sgid_count, uint32_t flags);
+
// CAPS --------
void get_open_ref(int mode);
bool put_open_ref(int mode);
fuse_reply_err(req, -r);
}
+static int getgroups_cb(void *handle, uid_t uid, gid_t **sgids)
+{
+#ifdef HAVE_FUSE_GETGROUPS
+ assert(sgids);
+ int c = fuse_getgroups(0, NULL);
+ if (c < 0) {
+ return c;
+ }
+ if (c == 0) {
+ return 0;
+ }
+
+ *sgids = malloc(c*sizeof(**sgids));
+ if (!*sgids) {
+ return -ENOMEM;
+ }
+ c = fuse_getgroups(c, *sgids);
+ if (c < 0) {
+ free(*sgids);
+ return c;
+ }
+ return c;
+#endif
+ return 0;
+}
static void invalidate_cb(void *handle, vinodeno_t vino, int64_t off, int64_t len)
{
fuse_session_add_chan(se, ch);
+ client->ll_register_getgroups_cb(getgroups_cb, ch);
+
if (g_conf->fuse_use_invalidate_cb)
client->ll_register_ino_invalidate_cb(invalidate_cb, ch);