Skip to content

Commit

Permalink
client: POSIX ACL support
Browse files Browse the repository at this point in the history
Signed-off-by: Yan, Zheng <[email protected]>
  • Loading branch information
ukernel committed Jan 12, 2016
1 parent 9865dfd commit 5064671
Show file tree
Hide file tree
Showing 9 changed files with 580 additions and 47 deletions.
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@ if(WITH_LIBCEPHFS)
client/MetaRequest.cc
client/ClientSnapRealm.cc
client/MetaSession.cc
client/Trace.cc)
client/Trace.cc
client/posix_acl.cc)
add_library(client ${libclient_srcs})
target_link_libraries(client osdc mds ${LIBEDIT_LIBS})
set(libcephfs_srcs libcephfs.cc)
Expand Down
251 changes: 222 additions & 29 deletions src/client/Client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ using namespace std;
#include "MetaSession.h"
#include "MetaRequest.h"
#include "ObjecterWriteback.h"
#include "posix_acl.h"

#include "include/assert.h"
#include "include/stat.h"
Expand Down Expand Up @@ -270,6 +271,10 @@ Client::Client(Messenger *m, MonClient *mc)
user_id = cct->_conf->client_mount_uid;
group_id = cct->_conf->client_mount_gid;

acl_type = NO_ACL;
if (cct->_conf->client_acl_type == "posix_acl")
acl_type = POSIX_ACL;

lru.lru_set_max(cct->_conf->client_cache_size);
lru.lru_set_midpoint(cct->_conf->client_cache_mid);

Expand Down Expand Up @@ -4818,12 +4823,24 @@ int Client::check_permissions(Inode *in, int flags, int uid, int gid)
}
}
#endif
unsigned want = 0;
if ((flags & O_ACCMODE) == O_WRONLY)
want = MAY_WRITE;
else if ((flags & O_ACCMODE) == O_RDWR)
want = MAY_READ | MAY_WRITE;
else if ((flags & O_ACCMODE) == O_RDONLY)
want = MAY_READ;

int ret = _posix_acl_permission(in, uid, gid, sgids, sgid_count, want);
if (ret != -EAGAIN)
return ret;

// check permissions before doing anything else
int ret = 0;
if (uid != 0 && !in->check_mode(uid, gid, sgids, sgid_count, flags)) {
if (uid == 0 || in->check_mode(uid, gid, sgids, sgid_count, want))
ret = 0;
else
ret = -EACCES;
}

if (sgids)
free(sgids);
return ret;
Expand Down Expand Up @@ -5826,8 +5843,8 @@ int Client::_getattr(Inode *in, int mask, int uid, int gid, bool force)
return res;
}

int Client::_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid,
InodeRef *inp)
int Client::_do_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid,
InodeRef *inp)
{
int issued = in->caps_issued();

Expand Down Expand Up @@ -5986,6 +6003,17 @@ int Client::_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid,
return res;
}

int Client::_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid,
InodeRef *inp)
{
int ret = _do_setattr(in, attr, mask, uid, gid, inp);
if (ret < 0)
return ret;
if (mask & CEPH_SETATTR_MODE)
ret = _posix_acl_chmod(in, attr->st_mode, uid, gid);
return ret;
}

int Client::setattr(const char *relpath, struct stat *attr, int mask)
{
Mutex::Locker lock(client_lock);
Expand Down Expand Up @@ -9162,6 +9190,11 @@ int Client::_getxattr(Inode *in, const char *name, void *value, size_t size,
goto out;
}

if (acl_type == NO_ACL && !strncmp(name, "system.", 7)) {
r = -EOPNOTSUPP;
goto out;
}

r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid, in->xattr_version == 0);
if (r == 0) {
string n(name);
Expand Down Expand Up @@ -9255,23 +9288,9 @@ int Client::ll_listxattr(Inode *in, char *names, size_t size, int uid,
return _listxattr(in, names, size, uid, gid);
}

int Client::_setxattr(Inode *in, const char *name, const void *value,
size_t size, int flags, int uid, int gid)
int Client::_do_setxattr(Inode *in, const char *name, const void *value,
size_t size, int flags, int uid, int gid)
{
if (in->snapid != CEPH_NOSNAP) {
return -EROFS;
}

// same xattrs supported by kernel client
if (strncmp(name, "user.", 5) &&
strncmp(name, "security.", 9) &&
strncmp(name, "trusted.", 8) &&
strncmp(name, "ceph.", 5))
return -EOPNOTSUPP;

const VXattr *vxattr = _match_vxattr(in, name);
if (vxattr && vxattr->readonly)
return -EOPNOTSUPP;

int xattr_flags = 0;
if (!value)
Expand Down Expand Up @@ -9301,6 +9320,62 @@ int Client::_setxattr(Inode *in, const char *name, const void *value,
return res;
}

int Client::_setxattr(Inode *in, const char *name, const void *value,
size_t size, int flags, int uid, int gid)
{
if (in->snapid != CEPH_NOSNAP) {
return -EROFS;
}

bool posix_acl_xattr = false;
if (acl_type == POSIX_ACL)
posix_acl_xattr = !strncmp(name, "system.", 7);

if (strncmp(name, "user.", 5) &&
strncmp(name, "security.", 9) &&
strncmp(name, "trusted.", 8) &&
strncmp(name, "ceph.", 5) &&
!posix_acl_xattr)
return -EOPNOTSUPP;

if (posix_acl_xattr) {
if (!strcmp(name, ACL_EA_ACCESS)) {
mode_t new_mode = in->mode;
if (value) {
int ret = posix_acl_equiv_mode(value, size, &new_mode);
if (ret < 0)
return ret;
if (ret == 0) {
value = NULL;
size = 0;
}
if (new_mode != in->mode) {
struct stat attr;
attr.st_mode = new_mode;
ret = _do_setattr(in, &attr, CEPH_SETATTR_MODE, uid, gid, NULL);
if (ret < 0)
return ret;
}
}
} else if (!strcmp(name, ACL_EA_DEFAULT)) {
if (value) {
if (!S_ISDIR(in->mode))
return -EACCES;
if (!posix_acl_check(value, size))
return -EINVAL;
}
} else {
return -EOPNOTSUPP;
}
} else {
const VXattr *vxattr = _match_vxattr(in, name);
if (vxattr && vxattr->readonly)
return -EOPNOTSUPP;
}

return _do_setxattr(in, name, value, size, flags, uid, gid);
}

int Client::check_data_pool_exist(string name, string value, const OSDMap *osdmap)
{
string tmp;
Expand Down Expand Up @@ -9382,6 +9457,7 @@ int Client::_removexattr(Inode *in, const char *name, int uid, int gid)

// same xattrs supported by kernel client
if (strncmp(name, "user.", 5) &&
strncmp(name, "system.", 7) &&
strncmp(name, "security.", 9) &&
strncmp(name, "trusted.", 8) &&
strncmp(name, "ceph.", 5))
Expand Down Expand Up @@ -9677,13 +9753,20 @@ int Client::_mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev,
path.push_dentry(name);
req->set_filepath(path);
req->set_inode(dir);
req->head.args.mknod.mode = mode;
req->head.args.mknod.rdev = rdev;
req->dentry_drop = CEPH_CAP_FILE_SHARED;
req->dentry_unless = CEPH_CAP_FILE_EXCL;

bufferlist xattrs_bl;
int res = _posix_acl_create(dir, &mode, xattrs_bl, uid, gid);
if (res < 0)
goto fail;
req->head.args.mknod.mode = mode;
if (xattrs_bl.length() > 0)
req->set_data(xattrs_bl);

Dentry *de;
int res = get_or_create(dir, name, &de);
res = get_or_create(dir, name, &de);
if (res < 0)
goto fail;
req->set_dentry(de);
Expand Down Expand Up @@ -9768,7 +9851,6 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode,
req->set_filepath(path);
req->set_inode(dir);
req->head.args.open.flags = flags | O_CREAT;
req->head.args.open.mode = mode;

req->head.args.open.stripe_unit = stripe_unit;
req->head.args.open.stripe_count = stripe_count;
Expand All @@ -9777,11 +9859,17 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode,
req->dentry_drop = CEPH_CAP_FILE_SHARED;
req->dentry_unless = CEPH_CAP_FILE_EXCL;

bufferlist extra_bl;
inodeno_t created_ino;
mode |= S_IFREG;
bufferlist xattrs_bl;
int res = _posix_acl_create(dir, &mode, xattrs_bl, uid, gid);
if (res < 0)
goto fail;
req->head.args.open.mode = mode;
if (xattrs_bl.length() > 0)
req->set_data(xattrs_bl);

Dentry *de;
int res = get_or_create(dir, name, &de);
res = get_or_create(dir, name, &de);
if (res < 0)
goto fail;
req->set_dentry(de);
Expand Down Expand Up @@ -9837,12 +9925,20 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, int uid, int gid,
path.push_dentry(name);
req->set_filepath(path);
req->set_inode(dir);
req->head.args.mkdir.mode = mode;
req->dentry_drop = CEPH_CAP_FILE_SHARED;
req->dentry_unless = CEPH_CAP_FILE_EXCL;

mode |= S_IFDIR;
bufferlist xattrs_bl;
int res = _posix_acl_create(dir, &mode, xattrs_bl, uid, gid);
if (res < 0)
goto fail;
req->head.args.mkdir.mode = mode;
if (xattrs_bl.length() > 0)
req->set_data(xattrs_bl);

Dentry *de;
int res = get_or_create(dir, name, &de);
res = get_or_create(dir, name, &de);
if (res < 0)
goto fail;
req->set_dentry(de);
Expand Down Expand Up @@ -11481,6 +11577,97 @@ int Client::check_pool_perm(Inode *in, int need)
return 0;
}

int Client::_posix_acl_permission(Inode *in, int uid, int gid,
gid_t *sgids, int sgid_count, unsigned want)
{
if (acl_type == POSIX_ACL) {
int r = _getattr(in, CEPH_STAT_CAP_XATTR | CEPH_STAT_CAP_MODE,
uid, gid, in->xattr_version == 0);
if (r < 0)
return r;

if (in->xattrs.count(ACL_EA_ACCESS)) {
const bufferptr& access_acl = in->xattrs[ACL_EA_ACCESS];
if (in->mode & S_IRWXG)
return posix_acl_permits(access_acl, in->uid, in->gid,
uid, gid, sgids, sgid_count, want);
}
}
return -EAGAIN;
}

int Client::_posix_acl_chmod(Inode *in, mode_t mode, int uid, int gid)
{
if (acl_type == NO_ACL)
return 0;

int r = _getattr(in, CEPH_STAT_CAP_XATTR, uid, gid, in->xattr_version == 0);
if (r < 0)
goto out;

if (acl_type == POSIX_ACL) {
if (in->xattrs.count(ACL_EA_ACCESS)) {
const bufferptr& access_acl = in->xattrs[ACL_EA_ACCESS];
bufferptr acl(access_acl.c_str(), access_acl.length());
r = posix_acl_access_chmod(acl, mode);
if (r < 0)
goto out;
r = _do_setxattr(in, ACL_EA_ACCESS, acl.c_str(), acl.length(), 0, uid, gid);
} else {
r = 0;
}
}
out:
ldout(cct, 10) << __func__ << " ino " << in->ino << " result=" << r << dendl;
return r;
}

int Client::_posix_acl_create(Inode *dir, mode_t *mode, bufferlist& xattrs_bl,
int uid, int gid)
{
if (acl_type == NO_ACL)
return 0;

if (S_ISLNK(*mode))
return 0;

int r = _getattr(dir, CEPH_STAT_CAP_XATTR, uid, gid, dir->xattr_version == 0);
if (r < 0)
goto out;

if (acl_type == POSIX_ACL) {
if (dir->xattrs.count(ACL_EA_DEFAULT)) {
map<string, bufferptr> xattrs;

const bufferptr& default_acl = dir->xattrs[ACL_EA_DEFAULT];
bufferptr acl(default_acl.c_str(), default_acl.length());
r = posix_acl_inherit_mode(acl, mode);
if (r < 0)
goto out;

if (r > 0) {
r = posix_acl_equiv_mode(acl.c_str(), acl.length(), mode);
if (r < 0)
goto out;
if (r > 0)
xattrs[ACL_EA_ACCESS] = acl;
}

if (S_ISDIR(*mode))
xattrs[ACL_EA_DEFAULT] = dir->xattrs[ACL_EA_DEFAULT];

r = xattrs.size();
if (r > 0)
::encode(xattrs, xattrs_bl);
} else {
r = 0;
}
}
out:
ldout(cct, 10) << __func__ << " dir ino " << dir->ino << " result=" << r << dendl;
return r;
}

void Client::set_filer_flags(int flags)
{
Mutex::Locker l(client_lock);
Expand Down Expand Up @@ -11514,6 +11701,7 @@ const char** Client::get_tracked_conf_keys() const
static const char* keys[] = {
"client_cache_size",
"client_cache_mid",
"client_acl_type",
NULL
};
return keys;
Expand All @@ -11527,6 +11715,11 @@ void Client::handle_conf_change(const struct md_config_t *conf,
lru.lru_set_max(cct->_conf->client_cache_size);
lru.lru_set_midpoint(cct->_conf->client_cache_mid);
}
if (changed.count("client_acl_type")) {
acl_type = NO_ACL;
if (cct->_conf->client_acl_type == "posix_acl")
acl_type = POSIX_ACL;
}
}

void intrusive_ptr_add_ref(Inode *in)
Expand Down
Loading

0 comments on commit 5064671

Please sign in to comment.