mirror of
https://github.com/ceph/ceph
synced 2025-02-20 17:37:29 +00:00
Merge branch 'wip-3301'
Reviewed-by: Sage Weil <sage@inktank.com>
This commit is contained in:
commit
ad6840ce5c
@ -309,6 +309,9 @@ AS_IF([test "x$with_system_leveldb" = xcheck],
|
||||
[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])],
|
||||
|
58
qa/workunits/misc/chmod.sh
Executable file
58
qa/workunits/misc/chmod.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
set -e
|
||||
|
||||
check_perms() {
|
||||
|
||||
file=$1
|
||||
r=$(ls -la ${file})
|
||||
if test $? != 0; then
|
||||
echo "ERROR: File listing/stat failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
perms=$2
|
||||
if test "${perms}" != $(echo ${r} | awk '{print $1}'); then
|
||||
echo "ERROR: Permissions should be ${perms}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "foo" > foo
|
||||
if test $? != 0; then
|
||||
echo "ERROR: Failed to create file foo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_perms foo "-rw-r--r--"
|
||||
|
||||
chmod 400 foo
|
||||
if test $? != 0; then
|
||||
echo "ERROR: Failed to change mode of foo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_perms foo "-r--------"
|
||||
|
||||
set +e
|
||||
echo "bar" >> foo
|
||||
if test $? = 0; then
|
||||
echo "ERROR: Write to read-only file should Fail"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
chmod 600 foo
|
||||
echo "bar" >> foo
|
||||
if test $? != 0; then
|
||||
echo "ERROR: Write to writeable file failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_perms foo "-rw-------"
|
||||
|
||||
echo "foo" >> foo
|
||||
if test $? != 0; then
|
||||
echo "ERROR: Failed to write to file"
|
||||
exit 1
|
||||
fi
|
@ -113,6 +113,8 @@ Client::Client(Messenger *m, MonClient *mc)
|
||||
: 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()),
|
||||
@ -2034,10 +2036,7 @@ void Client::send_cap(Inode *in, int mds, Cap *cap, int used, int want, int reta
|
||||
<< dendl;
|
||||
|
||||
cap->issued &= retain;
|
||||
|
||||
if (revoking && (revoking & used) == 0) {
|
||||
cap->implemented = cap->issued;
|
||||
}
|
||||
cap->implemented &= cap->issued | used;
|
||||
|
||||
uint64_t flush_tid = 0;
|
||||
snapid_t follows = 0;
|
||||
@ -3285,6 +3284,24 @@ void Client::handle_cap_grant(Inode *in, int mds, Cap *cap, MClientCaps *m)
|
||||
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
|
||||
@ -4830,11 +4847,6 @@ int Client::getdir(const char *relpath, list<string>& contents)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****** file i/o **********/
|
||||
int Client::open(const char *relpath, int flags, mode_t mode)
|
||||
{
|
||||
@ -4963,8 +4975,17 @@ int Client::_release_fh(Fh *f)
|
||||
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;
|
||||
@ -5381,7 +5402,7 @@ int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf)
|
||||
|
||||
// was Fh opened as writeable?
|
||||
if ((f->mode & CEPH_FILE_MODE_WR) == 0)
|
||||
return -EINVAL;
|
||||
return -EBADF;
|
||||
|
||||
// use/adjust fd pos?
|
||||
if (offset < 0) {
|
||||
@ -5693,6 +5714,13 @@ void Client::ll_register_ino_invalidate_cb(client_ino_callback_t cb, void *handl
|
||||
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;
|
||||
|
@ -119,6 +119,7 @@ class MetaRequest;
|
||||
|
||||
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
|
||||
@ -200,6 +201,9 @@ class Client : public Dispatcher {
|
||||
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;
|
||||
@ -515,6 +519,8 @@ private:
|
||||
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();
|
||||
@ -666,6 +672,8 @@ public:
|
||||
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
|
||||
|
@ -264,3 +264,34 @@ Dir *Inode::open_dir()
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -212,6 +212,8 @@ class Inode {
|
||||
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);
|
||||
|
@ -464,6 +464,31 @@ static void ceph_ll_statfs(fuse_req_t req, fuse_ino_t ino)
|
||||
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)
|
||||
{
|
||||
@ -607,6 +632,8 @@ int ceph_fuse_ll_main(Client *c, int argc, const char *argv[], int fd)
|
||||
|
||||
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);
|
||||
|
||||
|
@ -166,7 +166,7 @@ public:
|
||||
out << " " << ccap_string(head.args.getattr.mask);
|
||||
if (head.op == CEPH_MDS_OP_SETATTR) {
|
||||
if (head.args.setattr.mask & CEPH_SETATTR_MODE)
|
||||
out << " mode=0" << ios::oct << head.args.setattr.mode << ios::dec;
|
||||
out << " mode=0" << std::oct << head.args.setattr.mode << std::dec;
|
||||
if (head.args.setattr.mask & CEPH_SETATTR_UID)
|
||||
out << " uid=" << head.args.setattr.uid;
|
||||
if (head.args.setattr.mask & CEPH_SETATTR_GID)
|
||||
|
@ -352,3 +352,58 @@ TEST(LibCephFS, Lstat_slashdot) {
|
||||
|
||||
ceph_shutdown(cmount);
|
||||
}
|
||||
|
||||
TEST(LibCephFS, Double_chmod) {
|
||||
|
||||
struct ceph_mount_info *cmount;
|
||||
ASSERT_EQ(ceph_create(&cmount, NULL), 0);
|
||||
ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
|
||||
ASSERT_EQ(ceph_mount(cmount, NULL), 0);
|
||||
|
||||
char test_file[256];
|
||||
sprintf(test_file, "test_perms_%d", getpid());
|
||||
|
||||
int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
|
||||
ASSERT_GT(fd, 0);
|
||||
|
||||
// write some stuff
|
||||
const char *bytes = "foobarbaz";
|
||||
ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
|
||||
|
||||
ceph_close(cmount, fd);
|
||||
|
||||
// set perms to read but can't write
|
||||
ASSERT_EQ(ceph_chmod(cmount, test_file, 0400), 0);
|
||||
|
||||
fd = ceph_open(cmount, test_file, O_RDWR, 0);
|
||||
ASSERT_EQ(fd, -EACCES);
|
||||
|
||||
fd = ceph_open(cmount, test_file, O_RDONLY, 0);
|
||||
ASSERT_GT(fd, -1);
|
||||
|
||||
char buf[100];
|
||||
int ret = ceph_read(cmount, fd, buf, 100, 0);
|
||||
ASSERT_EQ(ret, (int)strlen(bytes));
|
||||
buf[ret] = '\0';
|
||||
ASSERT_STREQ(buf, bytes);
|
||||
|
||||
ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), -EBADF);
|
||||
|
||||
ceph_close(cmount, fd);
|
||||
|
||||
// reset back to writeable
|
||||
ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
|
||||
|
||||
// ensure perms are correct
|
||||
struct stat stbuf;
|
||||
ASSERT_EQ(ceph_lstat(cmount, test_file, &stbuf), 0);
|
||||
ASSERT_EQ(stbuf.st_mode, 0100600U);
|
||||
|
||||
fd = ceph_open(cmount, test_file, O_RDWR, 0);
|
||||
ASSERT_GT(fd, 0);
|
||||
|
||||
ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
|
||||
ceph_close(cmount, fd);
|
||||
|
||||
ceph_shutdown(cmount);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user