]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: maintain separate policies for object and bucket
authorYehuda Sadeh <yehuda@hq.newdream.net>
Tue, 21 Feb 2012 22:39:20 +0000 (14:39 -0800)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Tue, 21 Feb 2012 22:39:20 +0000 (14:39 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net>
src/rgw/rgw_acl.cc
src/rgw/rgw_acl.h
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_log.cc
src/rgw/rgw_op.cc

index 5c7575df68de46e34791357cce835af66fa1c780..7b0c3d70016f72c3577ffb2a5fb2152bc2f5328a 100644 (file)
@@ -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()
 {
index 96374ce10350fe0d6dbadb024b267975bbd49bcc..d0c9fcb20300824fefeccb8ce745d74594546948 100644 (file)
@@ -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;
index 9fa53176c8ce42e14a1d577fda62e0a7fa1e43d4..1bc70a00e5263a7d7dfa2f8a65d3ef75fd95f635 100644 (file)
@@ -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)
index 733d2da028d1f7b4b0ae0b288e60fb6cbd8db089..8847ecfe1023070031dae46f3c134a7285a2f120 100644 (file)
@@ -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);
index 9c6c7bc1f1af90a7b23f6ea891f6c9635eace5f8..7fb4f7e832a20596f101c943042a0353adc81a7d 100644 (file)
@@ -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;
index 4c82057be64fe3081b2a28ebd01461adc8da0fbd..ab65c82cdab898e266d76f3a0c0c8cea12219b22 100644 (file)
@@ -198,7 +198,7 @@ static int get_obj_attrs(struct req_state *s, rgw_obj& obj, map<string, bufferli
   return ret;
 }
 
-static int read_acls(struct req_state *s, RGWBucketInfo& bucket_info, RGWAccessControlPolicy *policy, rgw_bucket& bucket, string& object)
+static int read_policy(struct req_state *s, RGWBucketInfo& bucket_info, RGWAccessControlPolicy *policy, rgw_bucket& bucket, string& object)
 {
   string upload_id;
   upload_id = s->args.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<RGWAccessControlPolicy_S3 *>(s->acl);
+  RGWAccessControlPolicy *acl = (s->object ? s->object_acl : s->bucket_acl);
+  RGWAccessControlPolicy_S3 *s3policy = static_cast<RGWAccessControlPolicy_S3 *>(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, map<uint32
 
 int RGWCompleteMultipart::verify_permission()
 {
-  if (!::verify_permission(s, RGW_PERM_WRITE))
+  if (!verify_bucket_permission(s, RGW_PERM_WRITE))
     return -EACCES;
 
   return 0;
@@ -1540,7 +1540,7 @@ done:
 
 int RGWAbortMultipart::verify_permission()
 {
-  if (!::verify_permission(s, RGW_PERM_WRITE))
+  if (!verify_bucket_permission(s, RGW_PERM_WRITE))
     return -EACCES;
 
   return 0;
@@ -1590,7 +1590,7 @@ done:
 
 int RGWListMultipart::verify_permission()
 {
-  if (!::verify_permission(s, RGW_PERM_READ))
+  if (!verify_object_permission(s, RGW_PERM_READ))
     return -EACCES;
 
   return 0;
@@ -1617,7 +1617,7 @@ done:
 
 int RGWListBucketMultiparts::verify_permission()
 {
-  if (!::verify_permission(s, RGW_PERM_READ))
+  if (!verify_bucket_permission(s, RGW_PERM_READ))
     return -EACCES;
 
   return 0;
@@ -1678,7 +1678,7 @@ int RGWHandler::init(struct req_state *_s, FCGX_Request *fcgx)
 
 int RGWHandler::do_read_permissions(RGWOp *op, bool only_bucket)
 {
-  int ret = read_acls(s, only_bucket, op->prefetch_data());
+  int ret = build_policies(s, only_bucket, op->prefetch_data());
 
   if (ret < 0) {
     dout(10) << "read_permissions on " << s->bucket << ":" <<s->object_str << " only_bucket=" << only_bucket << " ret=" << ret << dendl;