]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/rgw/rgw_op.cc
import ceph 15.2.14
[ceph.git] / ceph / src / rgw / rgw_op.cc
index 20f7b62e54b262b49ddfc67d02c2e177924f9d1f..6914cc1ab6a534e057b47d96eb6ce8cf663931bc 100644 (file)
@@ -534,8 +534,15 @@ static int read_obj_policy(rgw::sal::RGWRadosStore *store,
     const rgw_user& bucket_owner = bucket_policy.get_owner().get_id();
     if (bucket_owner.compare(s->user->get_id()) != 0 &&
         ! s->auth.identity->is_admin_of(bucket_owner)) {
+      auto r = eval_user_policies(s->iam_user_policies, s->env,
+                                  *s->auth.identity, rgw::IAM::s3ListBucket,
+                                  ARN(bucket));
+      if (r == Effect::Allow)
+        return -ENOENT;
+      if (r == Effect::Deny)
+        return -EACCES;
       if (policy) {
-        auto r =  policy->eval(s->env, *s->auth.identity, rgw::IAM::s3ListBucket, ARN(bucket));
+        r = policy->eval(s->env, *s->auth.identity, rgw::IAM::s3ListBucket, ARN(bucket));
         if (r == Effect::Allow)
           return -ENOENT;
         if (r == Effect::Deny)
@@ -955,7 +962,6 @@ int retry_raced_bucket_write(RGWRados* g, req_state* s, const F& f) {
 }
 }
 
-
 int RGWGetObj::verify_permission()
 {
   obj = rgw_obj(s->bucket, s->object);
@@ -1589,7 +1595,7 @@ bool RGWOp::generate_cors_headers(string& origin, string& method, string& header
   return true;
 }
 
-int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket,
+int RGWGetObj::read_user_manifest_part(RGWBucketInfo& bucket_info,
                                        const rgw_bucket_dir_entry& ent,
                                        RGWAccessControlPolicy * const bucket_acl,
                                        const boost::optional<Policy>& bucket_policy,
@@ -1606,6 +1612,8 @@ int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket,
   int64_t cur_ofs = start_ofs;
   int64_t cur_end = end_ofs;
 
+  rgw_bucket& bucket = bucket_info.bucket;
+
   rgw_obj part(bucket, ent.key);
 
   map<string, bufferlist> attrs;
@@ -1620,7 +1628,7 @@ int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket,
   obj_ctx.set_atomic(part);
   store->getRados()->set_prefetch_data(&obj_ctx, part);
 
-  RGWRados::Object op_target(store->getRados(), s->bucket_info, obj_ctx, part);
+  RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, part);
   RGWRados::Object::Read read_op(&op_target);
 
   if (!swift_slo) {
@@ -1701,7 +1709,7 @@ static int iterate_user_manifest_parts(CephContext * const cct,
                                        uint64_t * const ptotal_len,
                                        uint64_t * const pobj_size,
                                        string * const pobj_sum,
-                                       int (*cb)(rgw_bucket& bucket,
+                                       int (*cb)(RGWBucketInfo& bucket_info,
                                                  const rgw_bucket_dir_entry& ent,
                                                  RGWAccessControlPolicy * const bucket_acl,
                                                  const boost::optional<Policy>& bucket_policy,
@@ -1762,7 +1770,7 @@ static int iterate_user_manifest_parts(CephContext * const cct,
         len_count += end_ofs - start_ofs;
 
         if (cb) {
-          r = cb(bucket, ent, bucket_acl, bucket_policy, start_ofs, end_ofs,
+          r = cb(*pbucket_info, ent, bucket_acl, bucket_policy, start_ofs, end_ofs,
                 cb_param, false /* swift_slo */);
           if (r < 0) {
             return r;
@@ -1791,7 +1799,7 @@ static int iterate_user_manifest_parts(CephContext * const cct,
 struct rgw_slo_part {
   RGWAccessControlPolicy *bucket_acl = nullptr;
   Policy* bucket_policy = nullptr;
-  rgw_bucket bucket;
+  RGWBucketInfo *pbucket_info = nullptr;
   string obj_name;
   uint64_t size = 0;
   string etag;
@@ -1802,7 +1810,7 @@ static int iterate_slo_parts(CephContext *cct,
                              off_t ofs,
                              off_t end,
                              map<uint64_t, rgw_slo_part>& slo_parts,
-                             int (*cb)(rgw_bucket& bucket,
+                             int (*cb)(RGWBucketInfo& bucket_info,
                                        const rgw_bucket_dir_entry& ent,
                                        RGWAccessControlPolicy *bucket_acl,
                                        const boost::optional<Policy>& bucket_policy,
@@ -1862,7 +1870,7 @@ static int iterate_slo_parts(CephContext *cct,
                           << dendl;
 
        // SLO is a Swift thing, and Swift has no knowledge of S3 Policies.
-        int r = cb(part.bucket, ent, part.bucket_acl,
+        int r = cb(*(part.pbucket_info), ent, part.bucket_acl,
                   (part.bucket_policy ?
                    boost::optional<Policy>(*part.bucket_policy) : none),
                   start_ofs, end_ofs, cb_param, true /* swift_slo */);
@@ -1877,7 +1885,7 @@ static int iterate_slo_parts(CephContext *cct,
   return 0;
 }
 
-static int get_obj_user_manifest_iterate_cb(rgw_bucket& bucket,
+static int get_obj_user_manifest_iterate_cb(RGWBucketInfo& bucket_info,
                                             const rgw_bucket_dir_entry& ent,
                                             RGWAccessControlPolicy * const bucket_acl,
                                             const boost::optional<Policy>& bucket_policy,
@@ -1888,7 +1896,7 @@ static int get_obj_user_manifest_iterate_cb(rgw_bucket& bucket,
 {
   RGWGetObj *op = static_cast<RGWGetObj *>(param);
   return op->read_user_manifest_part(
-    bucket, ent, bucket_acl, bucket_policy, start_ofs, end_ofs, swift_slo);
+    bucket_info, ent, bucket_acl, bucket_policy, start_ofs, end_ofs, swift_slo);
 }
 
 int RGWGetObj::handle_user_manifest(const char *prefix)
@@ -2004,7 +2012,7 @@ int RGWGetObj::handle_slo_manifest(bufferlist& bl)
 
   vector<RGWAccessControlPolicy> allocated_acls;
   map<string, pair<RGWAccessControlPolicy *, boost::optional<Policy>>> policies;
-  map<string, rgw_bucket> buckets;
+  map<string, RGWBucketInfo> bucket_infos;
 
   map<uint64_t, rgw_slo_part> slo_parts;
 
@@ -2035,6 +2043,7 @@ int RGWGetObj::handle_slo_manifest(bufferlist& bl)
     string obj_name = path.substr(pos_sep + 1);
 
     rgw_bucket bucket;
+    RGWBucketInfo *pbucket_info;
     RGWAccessControlPolicy *bucket_acl;
     Policy* bucket_policy;
 
@@ -2043,7 +2052,7 @@ int RGWGetObj::handle_slo_manifest(bufferlist& bl)
       if (piter != policies.end()) {
         bucket_acl = piter->second.first;
         bucket_policy = piter->second.second.get_ptr();
-       bucket = buckets[bucket_name];
+        pbucket_info = &bucket_infos[bucket_name];
       } else {
        allocated_acls.push_back(RGWAccessControlPolicy(s->cct));
        RGWAccessControlPolicy& _bucket_acl = allocated_acls.back();
@@ -2071,11 +2080,12 @@ int RGWGetObj::handle_slo_manifest(bufferlist& bl)
        auto _bucket_policy = get_iam_policy_from_attr(
          s->cct, store, bucket_attrs, bucket_info.bucket.tenant);
         bucket_policy = _bucket_policy.get_ptr();
-       buckets[bucket_name] = bucket;
+        bucket_infos.emplace(bucket_name, std::move(bucket_info));
+        pbucket_info = &bucket_infos[bucket_name];
         policies[bucket_name] = make_pair(bucket_acl, _bucket_policy);
       }
     } else {
-      bucket = s->bucket;
+      pbucket_info = &s->bucket_info;
       bucket_acl = s->bucket_acl.get();
       bucket_policy = s->iam_policy.get_ptr();
     }
@@ -2083,11 +2093,11 @@ int RGWGetObj::handle_slo_manifest(bufferlist& bl)
     rgw_slo_part part;
     part.bucket_acl = bucket_acl;
     part.bucket_policy = bucket_policy;
-    part.bucket = bucket;
+    part.pbucket_info = pbucket_info;
     part.obj_name = obj_name;
     part.size = entry.size_bytes;
     part.etag = entry.etag;
-    ldpp_dout(this, 20) << "slo_part: bucket=" << part.bucket
+    ldpp_dout(this, 20) << "slo_part: bucket=" << part.pbucket_info->bucket
                       << " obj=" << part.obj_name
                       << " size=" << part.size
                       << " etag=" << part.etag
@@ -2534,11 +2544,10 @@ void RGWGetUsage::execute()
   bool is_truncated = true;
 
   RGWUsageIter usage_iter;
-  
+
   while (is_truncated) {
     op_ret = store->getRados()->read_usage(s->user->get_id(), s->bucket_name, start_epoch, end_epoch, max_entries,
                                 &is_truncated, usage_iter, usage);
-
     if (op_ret == -ENOENT) {
       op_ret = 0;
       is_truncated = false;
@@ -2669,6 +2678,8 @@ void RGWSetBucketVersioning::execute()
     return;
 
   if (s->bucket_info.obj_lock_enabled() && versioning_status != VersioningEnabled) {
+    s->err.message = "bucket versioning cannot be disabled on buckets with object lock enabled";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_BUCKET_STATE;
     return;
   }
@@ -3779,7 +3790,7 @@ int RGWPutObj::get_data(const off_t fst, const off_t lst, bufferlist& bl)
     filter = decrypt.get();
   }
   if (op_ret < 0) {
-    return ret;
+    return op_ret;
   }
 
   ret = read_op.range_to_ofs(obj_size, new_ofs, new_end);
@@ -4863,37 +4874,10 @@ void RGWDeleteObj::execute()
     op_ret = 0;
 
     if (check_obj_lock) {
-      auto aiter = attrs.find(RGW_ATTR_OBJECT_RETENTION);
-      if (aiter != attrs.end()) {
-        RGWObjectRetention obj_retention;
-        try {
-          decode(obj_retention, aiter->second);
-        } catch (buffer::error& err) {
-          ldpp_dout(this, 0) << "ERROR: failed to decode RGWObjectRetention" << dendl;
-          op_ret = -EIO;
-          return;
-        }
-        if (ceph::real_clock::to_time_t(obj_retention.get_retain_until_date()) > ceph_clock_now()) {
-          if (obj_retention.get_mode().compare("GOVERNANCE") != 0 || !bypass_perm || !bypass_governance_mode) {
-            op_ret = -EACCES;
-            return;
-          }
-        }
-      }
-      aiter = attrs.find(RGW_ATTR_OBJECT_LEGAL_HOLD);
-      if (aiter != attrs.end()) {
-        RGWObjectLegalHold obj_legal_hold;
-        try {
-          decode(obj_legal_hold, aiter->second);
-        } catch (buffer::error& err) {
-          ldpp_dout(this, 0) << "ERROR: failed to decode RGWObjectLegalHold" << dendl;
-          op_ret = -EIO;
-          return;
-        }
-        if (obj_legal_hold.is_enabled()) {
-          op_ret = -EACCES;
-          return;
-        }
+      int object_lock_response = verify_object_lock(this, attrs, bypass_perm, bypass_governance_mode);
+      if (object_lock_response != 0) {
+        op_ret = object_lock_response;
+        return;
       }
     }
 
@@ -6495,10 +6479,31 @@ void RGWGetHealthCheck::execute()
 
 int RGWDeleteMultiObj::verify_permission()
 {
+  int op_ret = get_params();
+  if (op_ret) {
+    return op_ret;
+  }
+
   if (s->iam_policy || ! s->iam_user_policies.empty()) {
+    if (s->bucket_info.obj_lock_enabled() && bypass_governance_mode) {
+      auto r = eval_user_policies(s->iam_user_policies, s->env, boost::none,
+                                               rgw::IAM::s3BypassGovernanceRetention, ARN(s->bucket_info.bucket));
+      if (r == Effect::Deny) {
+        bypass_perm = false;
+      } else if (r == Effect::Pass && s->iam_policy) {
+        r = s->iam_policy->eval(s->env, *s->auth.identity, rgw::IAM::s3BypassGovernanceRetention,
+                                     ARN(s->bucket_info.bucket));
+        if (r == Effect::Deny) {
+          bypass_perm = false;
+        }
+      }
+    }
+
+    bool not_versioned = s->object.empty() || s->object.instance.empty();
+
     auto usr_policy_res = eval_user_policies(s->iam_user_policies, s->env,
                                               boost::none,
-                                              s->object.instance.empty() ?
+                                              not_versioned ?
                                               rgw::IAM::s3DeleteObject :
                                               rgw::IAM::s3DeleteObjectVersion,
                                               ARN(s->bucket));
@@ -6509,7 +6514,7 @@ int RGWDeleteMultiObj::verify_permission()
     rgw::IAM::Effect r = Effect::Pass;
     if (s->iam_policy) {
       r = s->iam_policy->eval(s->env, *s->auth.identity,
-                                s->object.instance.empty() ?
+                                not_versioned ?
                                 rgw::IAM::s3DeleteObject :
                                 rgw::IAM::s3DeleteObjectVersion,
                                 ARN(s->bucket));
@@ -6542,11 +6547,6 @@ void RGWDeleteMultiObj::execute()
   RGWObjectCtx *obj_ctx = static_cast<RGWObjectCtx *>(s->obj_ctx);
   char* buf;
 
-  op_ret = get_params();
-  if (op_ret < 0) {
-    goto error;
-  }
-
   buf = data.c_str();
   if (!buf) {
     op_ret = -EINVAL;
@@ -6635,6 +6635,31 @@ void RGWDeleteMultiObj::execute()
       }
     }
 
+    // verify_object_lock
+    bool check_obj_lock = obj.key.have_instance() && s->bucket_info.obj_lock_enabled();
+    map<string,bufferlist> attrs;
+    if (check_obj_lock) {
+      int get_attrs_response = get_obj_attrs(store, s, obj, attrs);
+      if (get_attrs_response < 0) {
+        if (get_attrs_response == -ENOENT) {
+          // object maybe delete_marker, skip check_obj_lock
+          check_obj_lock = false;
+        } else {
+          // Something went wrong.
+          send_partial_response(*iter, false, "", get_attrs_response);
+          continue;
+        }
+      }
+    }
+
+    if (check_obj_lock) {
+      int object_lock_response = verify_object_lock(this, attrs, bypass_perm, bypass_governance_mode);
+      if (object_lock_response != 0) {
+        send_partial_response(*iter, false, "", object_lock_response);
+        continue;
+      }
+    }
+
     obj_ctx->set_atomic(obj);
 
     RGWRados::Object del_target(store->getRados(), s->bucket_info, *obj_ctx, obj);
@@ -7670,6 +7695,10 @@ void RGWDefaultResponseOp::send_response() {
 
 void RGWPutBucketPolicy::send_response()
 {
+  if (!op_ret) {
+    /* A successful Put Bucket Policy should return a 204 on success */
+    op_ret = STATUS_NO_CONTENT;
+  }
   if (op_ret) {
     set_req_state_err(s, op_ret);
   }
@@ -7821,7 +7850,8 @@ int RGWPutBucketObjectLock::verify_permission()
 void RGWPutBucketObjectLock::execute()
 {
   if (!s->bucket_info.obj_lock_enabled()) {
-    ldpp_dout(this, 0) << "ERROR: object Lock configuration cannot be enabled on existing buckets" << dendl;
+    s->err.message = "object lock configuration can't be set if bucket object lock not enabled";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_BUCKET_STATE;
     return;
   }
@@ -7849,7 +7879,8 @@ void RGWPutBucketObjectLock::execute()
     return;
   }
   if (obj_lock.has_rule() && !obj_lock.retention_period_valid()) {
-    ldpp_dout(this, 0) << "ERROR: retention period must be a positive integer value" << dendl;
+    s->err.message = "retention period must be a positive integer value";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_RETENTION_PERIOD;
     return;
   }
@@ -7912,7 +7943,8 @@ void RGWPutObjRetention::pre_exec()
 void RGWPutObjRetention::execute()
 {
   if (!s->bucket_info.obj_lock_enabled()) {
-    ldpp_dout(this, 0) << "ERROR: object retention can't be set if bucket object lock not configured" << dendl;
+    s->err.message = "object retention can't be set if bucket object lock not configured";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_REQUEST;
     return;
   }
@@ -7938,7 +7970,8 @@ void RGWPutObjRetention::execute()
   }
 
   if (ceph::real_clock::to_time_t(obj_retention.get_retain_until_date()) < ceph_clock_now()) {
-    ldpp_dout(this, 0) << "ERROR: the retain until date must be in the future" << dendl;
+    s->err.message = "the retain-until date must be in the future";
+    ldpp_dout(this, 0) << "ERROR: " << s->err.message << dendl;
     op_ret = -EINVAL;
     return;
   }
@@ -7965,6 +7998,7 @@ void RGWPutObjRetention::execute()
     }
     if (ceph::real_clock::to_time_t(obj_retention.get_retain_until_date()) < ceph::real_clock::to_time_t(old_obj_retention.get_retain_until_date())) {
       if (old_obj_retention.get_mode().compare("GOVERNANCE") != 0 || !bypass_perm || !bypass_governance_mode) {
+       s->err.message = "proposed retain-until date shortens an existing retention period and governance bypass check failed";
         op_ret = -EACCES;
         return;
       }
@@ -7992,7 +8026,8 @@ void RGWGetObjRetention::pre_exec()
 void RGWGetObjRetention::execute()
 {
   if (!s->bucket_info.obj_lock_enabled()) {
-    ldpp_dout(this, 0) << "ERROR: bucket object lock not configured" << dendl;
+    s->err.message = "bucket object lock not configured";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_REQUEST;
     return;
   }
@@ -8036,7 +8071,8 @@ void RGWPutObjLegalHold::pre_exec()
 
 void RGWPutObjLegalHold::execute() {
   if (!s->bucket_info.obj_lock_enabled()) {
-    ldpp_dout(this, 0) << "ERROR: object legal hold can't be set if bucket object lock not configured" << dendl;
+    s->err.message = "object legal hold can't be set if bucket object lock not enabled";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_REQUEST;
     return;
   }
@@ -8088,7 +8124,8 @@ void RGWGetObjLegalHold::pre_exec()
 void RGWGetObjLegalHold::execute()
 {
   if (!s->bucket_info.obj_lock_enabled()) {
-    ldpp_dout(this, 0) << "ERROR: bucket object lock not configured" << dendl;
+    s->err.message = "bucket object lock not configured";
+    ldpp_dout(this, 4) << "ERROR: " << s->err.message << dendl;
     op_ret = -ERR_INVALID_REQUEST;
     return;
   }
@@ -8122,7 +8159,6 @@ void RGWGetClusterStat::execute()
   op_ret = this->store->getRados()->get_rados_handle()->cluster_stat(stats_op);
 }
 
-
 int RGWGetBucketPolicyStatus::verify_permission()
 {
   if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketPolicyStatus)) {