From 2365c77aad8a034c6a7fae0fae8b393805f3ca28 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Tue, 21 Feb 2012 14:39:20 -0800 Subject: [PATCH] rgw: maintain separate policies for object and bucket Signed-off-by: Yehuda Sadeh --- src/rgw/rgw_acl.cc | 22 ++++++---- src/rgw/rgw_acl.h | 3 ++ src/rgw/rgw_common.cc | 28 ++++++------- src/rgw/rgw_common.h | 8 ++-- src/rgw/rgw_log.cc | 4 +- src/rgw/rgw_op.cc | 98 +++++++++++++++++++++---------------------- 6 files changed, 86 insertions(+), 77 deletions(-) diff --git a/src/rgw/rgw_acl.cc b/src/rgw/rgw_acl.cc index 5c7575df68de4..7b0c3d70016f7 100644 --- a/src/rgw/rgw_acl.cc +++ b/src/rgw/rgw_acl.cc @@ -62,17 +62,13 @@ int RGWAccessControlList::get_group_perm(ACLGroupTypeEnum group, int perm_mask) int RGWAccessControlPolicy::get_perm(string& id, int perm_mask) { int perm = acl.get_perm(id, perm_mask); + if (id.compare(owner.get_id()) == 0) { + perm |= perm_mask & (RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP); + } + if (perm == perm_mask) return perm; - if (perm_mask & (RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP)) { - /* this is the owner, it has implicit permissions */ - if (id.compare(owner.get_id()) == 0) { - perm |= RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP; - perm &= perm_mask; - } - } - /* should we continue looking up? */ if ((perm & perm_mask) != perm_mask) { perm |= acl.get_group_perm(ACL_GROUP_ALL_USERS, perm_mask); @@ -88,6 +84,16 @@ int RGWAccessControlPolicy::get_perm(string& id, int perm_mask) { return perm; } +bool RGWAccessControlPolicy::verify_permission(string& uid, int user_perm_mask, int perm) +{ + int policy_perm = get_perm(uid, perm); + int acl_perm = policy_perm & user_perm_mask; + + dout(10) << " uid=" << uid << " requested perm (type)=" << perm << ", policy perm=" << policy_perm << ", user_perm_mask=" << user_perm_mask << ", acl perm=" << acl_perm << dendl; + + return (perm == acl_perm); +} + ACLGroupTypeEnum ACLGrant::uri_to_group() { diff --git a/src/rgw/rgw_acl.h b/src/rgw/rgw_acl.h index 96374ce10350f..d0c9fcb203008 100644 --- a/src/rgw/rgw_acl.h +++ b/src/rgw/rgw_acl.h @@ -15,6 +15,8 @@ using namespace std; #define RGW_PERM_WRITE 0x02 #define RGW_PERM_READ_ACP 0x04 #define RGW_PERM_WRITE_ACP 0x08 +#define RGW_PERM_READ_OBJS 0x10 +#define RGW_PERM_WRITE_OBJS 0x20 #define RGW_PERM_FULL_CONTROL ( RGW_PERM_READ | RGW_PERM_WRITE | \ RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP ) #define RGW_PERM_ALL RGW_PERM_FULL_CONTROL @@ -263,6 +265,7 @@ public: int get_perm(string& id, int perm_mask); int get_group_perm(ACLGroupTypeEnum group, int perm_mask); + bool verify_permission(string& uid, int user_perm_mask, int perm); void encode(bufferlist& bl) const { __u8 struct_v = 1; diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index 9fa53176c8ce4..1bc70a00e5263 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -85,12 +85,13 @@ is_err() const } -req_state::req_state(struct RGWEnv *e) : acl(NULL), os_auth_token(NULL), os_user(NULL), os_groups(NULL), env(e) +req_state::req_state(struct RGWEnv *e) : os_auth_token(NULL), os_user(NULL), os_groups(NULL), env(e) { should_log = env->conf->should_log; content_started = false; format = 0; - acl = new RGWAccessControlPolicy; + bucket_acl = NULL; + object_acl = NULL; expect_cont = false; os_auth_token = NULL; @@ -108,7 +109,8 @@ req_state::req_state(struct RGWEnv *e) : acl(NULL), os_auth_token(NULL), os_user req_state::~req_state() { delete formatter; - delete acl; + delete bucket_acl; + delete object_acl; free(os_user); free(os_groups); free((void *)object); @@ -340,22 +342,20 @@ string& XMLArgs::get(const char *name) return get(s); } -bool verify_permission(RGWAccessControlPolicy *policy, string& uid, int user_perm_mask, int perm) +bool verify_bucket_permission(struct req_state *s, int perm) { - if (!policy) - return false; - - int policy_perm = policy->get_perm(uid, perm); - int acl_perm = policy_perm & user_perm_mask; - - dout(10) << " uid=" << uid << " requested perm (type)=" << perm << ", policy perm=" << policy_perm << ", user_perm_mask=" << user_perm_mask << ", acl perm=" << acl_perm << dendl; + if (!s->bucket_acl) + return false; - return (perm == acl_perm); + return s->bucket_acl->verify_permission(s->user.user_id, s->perm_mask, perm); } -bool verify_permission(struct req_state *s, int perm) +bool verify_object_permission(struct req_state *s, int perm) { - return verify_permission(s->acl, s->user.user_id, s->perm_mask, perm); + if (!s->object_acl) + return false; + + return s->object_acl->verify_permission(s->user.user_id, s->perm_mask, perm); } static char hex_to_num(char c) diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 733d2da028d1f..8847ecfe10230 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -550,7 +550,8 @@ struct req_state { bool has_bad_meta; RGWUserInfo user; - RGWAccessControlPolicy *acl; + RGWAccessControlPolicy *bucket_acl; + RGWAccessControlPolicy *object_acl; string canned_acl; const char *copy_source; @@ -943,11 +944,10 @@ static inline const char *rgw_obj_category_name(RGWObjCategory category) extern int parse_time(const char *time_str, time_t *time); extern bool parse_rfc2616(const char *s, struct tm *t); -/** Check if a user has a permission on that ACL */ -extern bool verify_permission(RGWAccessControlPolicy *policy, string& uid, int user_perm_mask, int perm); /** Check if the req_state's user has the necessary permissions * to do the requested action */ -extern bool verify_permission(struct req_state *s, int perm); +extern bool verify_bucket_permission(struct req_state *s, int perm); +extern bool verify_object_permission(struct req_state *s, int perm); /** Convert an input URL into a sane object name * by converting %-escaped strings into characters, etc*/ extern bool url_decode(string& src_str, string& dest_str); diff --git a/src/rgw/rgw_log.cc b/src/rgw/rgw_log.cc index 9c6c7bc1f1af9..7fb4f7e832a20 100644 --- a/src/rgw/rgw_log.cc +++ b/src/rgw/rgw_log.cc @@ -120,8 +120,8 @@ int rgw_log_op(struct req_state *s) set_param_str(s, "REQUEST_METHOD", entry.op); entry.user = s->user.user_id; - if (s->acl) - entry.object_owner = s->acl->get_owner().get_id(); + if (s->object_acl) + entry.object_owner = s->object_acl->get_owner().get_id(); entry.bucket_owner = s->bucket_owner; entry.time = s->time; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 4c82057be64fe..ab65c82cdab89 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -198,7 +198,7 @@ static int get_obj_attrs(struct req_state *s, rgw_obj& obj, mapargs.get("uploadId"); @@ -226,8 +226,9 @@ static int read_acls(struct req_state *s, RGWBucketInfo& bucket_info, RGWAccessC ret = get_policy_from_attr(s->obj_ctx, &bucket_policy, no_obj); if (ret < 0) return ret; - - if (!verify_permission(&bucket_policy, s->user.user_id, s->perm_mask, RGW_PERM_READ)) + string& owner = bucket_policy.get_owner().get_id(); + if (owner.compare(s->user.user_id) != 0 && + !bucket_policy.verify_permission(s->user.user_id, s->perm_mask, RGW_PERM_READ)) ret = -EACCES; else ret = -ENOENT; @@ -244,15 +245,12 @@ static int read_acls(struct req_state *s, RGWBucketInfo& bucket_info, RGWAccessC * only_bucket: If true, reads the bucket ACL rather than the object ACL. * Returns: 0 on success, -ERR# otherwise. */ -static int read_acls(struct req_state *s, bool only_bucket, bool prefetch_data) +static int build_policies(struct req_state *s, bool only_bucket, bool prefetch_data) { int ret = 0; string obj_str; - if (!s->acl) { - s->acl = new RGWAccessControlPolicy; - if (!s->acl) - return -ENOMEM; - } + + s->bucket_acl = new RGWAccessControlPolicy; RGWBucketInfo bucket_info; if (s->bucket_name_str.size()) { @@ -263,21 +261,26 @@ static int read_acls(struct req_state *s, bool only_bucket, bool prefetch_data) } s->bucket = bucket_info.bucket; s->bucket_owner = bucket_info.owner; + + string no_obj; + RGWAccessControlPolicy bucket_acl; + ret = read_policy(s, bucket_info, s->bucket_acl, s->bucket, no_obj); } /* we're passed only_bucket = true when we specifically need the bucket's acls, that happens on write operations */ if (!only_bucket) { + s->object_acl = new RGWAccessControlPolicy; + obj_str = s->object_str; rgw_obj obj(s->bucket, obj_str); rgwstore->set_atomic(s->obj_ctx, obj); if (prefetch_data) { rgwstore->set_prefetch_data(s->obj_ctx, obj); } + ret = read_policy(s, bucket_info, s->object_acl, s->bucket, obj_str); } - ret = read_acls(s, bucket_info, s->acl, s->bucket, obj_str); - return ret; } @@ -287,7 +290,7 @@ int RGWGetObj::verify_permission() rgwstore->set_atomic(s->obj_ctx, obj); rgwstore->set_prefetch_data(s->obj_ctx, obj); - if (!::verify_permission(s, RGW_PERM_READ)) + if (!verify_object_permission(s, RGW_PERM_READ)) return -EACCES; return 0; @@ -438,7 +441,7 @@ void RGWStatAccount::execute() int RGWStatBucket::verify_permission() { - if (!::verify_permission(s, RGW_PERM_READ)) + if (!verify_bucket_permission(s, RGW_PERM_READ)) return -EACCES; return 0; @@ -468,7 +471,7 @@ void RGWStatBucket::execute() int RGWListBucket::verify_permission() { - if (!::verify_permission(s, RGW_PERM_READ)) + if (!verify_bucket_permission(s, RGW_PERM_READ)) return -EACCES; return 0; @@ -566,7 +569,7 @@ done: int RGWDeleteBucket::verify_permission() { - if (!::verify_permission(s, RGW_PERM_WRITE)) + if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; @@ -596,7 +599,7 @@ struct put_obj_aio_info { int RGWPutObj::verify_permission() { - if (!::verify_permission(s, RGW_PERM_WRITE)) + if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; @@ -990,7 +993,7 @@ done: int RGWPutObjMetadata::verify_permission() { - if (!::verify_permission(s, RGW_PERM_WRITE)) + if (!verify_object_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; @@ -1035,7 +1038,7 @@ done: int RGWDeleteObj::verify_permission() { - if (!::verify_permission(s, RGW_PERM_WRITE)) + if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; @@ -1109,21 +1112,21 @@ int RGWCopyObj::verify_permission() dest_bucket = dest_bucket_info.bucket; /* check source object permissions */ - ret = read_acls(s, src_bucket_info, &src_policy, src_bucket, src_object); + ret = read_policy(s, src_bucket_info, &src_policy, src_bucket, src_object); if (ret < 0) return ret; - if (!::verify_permission(&src_policy, s->user.user_id, s->perm_mask, RGW_PERM_READ)) + if (!src_policy.verify_permission(s->user.user_id, s->perm_mask, RGW_PERM_READ)) return -EACCES; RGWAccessControlPolicy dest_bucket_policy; /* check dest bucket permissions */ - ret = read_acls(s, dest_bucket_info, &dest_bucket_policy, dest_bucket, empty_str); + ret = read_policy(s, dest_bucket_info, &dest_bucket_policy, dest_bucket, empty_str); if (ret < 0) return ret; - if (!::verify_permission(&dest_bucket_policy, s->user.user_id, s->perm_mask, RGW_PERM_WRITE)) + if (!dest_bucket_policy.verify_permission(s->user.user_id, s->perm_mask, RGW_PERM_WRITE)) return -EACCES; ret = init_dest_policy(); @@ -1189,7 +1192,13 @@ done: int RGWGetACLs::verify_permission() { - if (!::verify_permission(s, RGW_PERM_READ_ACP)) + bool perm; + if (s->object) { + perm = verify_object_permission(s, RGW_PERM_READ_ACP); + } else { + perm = verify_bucket_permission(s, RGW_PERM_READ_ACP); + } + if (!perm) return -EACCES; return 0; @@ -1197,15 +1206,9 @@ int RGWGetACLs::verify_permission() void RGWGetACLs::execute() { - ret = read_acls(s, false, false); - - if (ret < 0) { - send_response(); - return; - } - stringstream ss; - RGWAccessControlPolicy_S3 *s3policy = static_cast(s->acl); + RGWAccessControlPolicy *acl = (s->object ? s->object_acl : s->bucket_acl); + RGWAccessControlPolicy_S3 *s3policy = static_cast(acl); s3policy->to_xml(ss); acls = ss.str(); send_response(); @@ -1215,7 +1218,13 @@ void RGWGetACLs::execute() int RGWPutACLs::verify_permission() { - if (!::verify_permission(s, RGW_PERM_WRITE_ACP)) + bool perm; + if (s->object) { + perm = verify_object_permission(s, RGW_PERM_WRITE_ACP); + } else { + perm = verify_bucket_permission(s, RGW_PERM_WRITE_ACP); + } + if (!perm) return -EACCES; return 0; @@ -1241,17 +1250,8 @@ void RGWPutACLs::execute() goto done; } - if (!s->acl) { - s->acl = new RGWAccessControlPolicy_S3; - if (!s->acl) { - ret = -ENOMEM; - goto done; - } - owner.set_id(s->user.user_id); - owner.set_name(s->user.display_name); - } else { - owner = s->acl->get_owner(); - } + owner.set_id(s->user.user_id); + owner.set_name(s->user.display_name); if (get_params() < 0) goto done; @@ -1313,7 +1313,7 @@ done: int RGWInitMultipart::verify_permission() { - if (!::verify_permission(s, RGW_PERM_WRITE)) + if (!verify_bucket_permission(s, RGW_PERM_WRITE)) return -EACCES; return 0; @@ -1409,7 +1409,7 @@ static int get_multiparts_info(struct req_state *s, string& meta_oid, mapprefetch_data()); + int ret = build_policies(s, only_bucket, op->prefetch_data()); if (ret < 0) { dout(10) << "read_permissions on " << s->bucket << ":" <object_str << " only_bucket=" << only_bucket << " ret=" << ret << dendl; -- 2.39.5