Merge branch 'wip-3301'

Reviewed-by: Sage Weil <sage@inktank.com>
This commit is contained in:
Sage Weil 2012-10-16 21:06:00 -07:00
commit ad6840ce5c
9 changed files with 224 additions and 12 deletions

View File

@ -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
View 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

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);
}