summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_op.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rgw/rgw_op.cc')
-rw-r--r--src/rgw/rgw_op.cc259
1 files changed, 181 insertions, 78 deletions
diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc
index 8378d9ef22e..7b0ca3134a3 100644
--- a/src/rgw/rgw_op.cc
+++ b/src/rgw/rgw_op.cc
@@ -25,8 +25,10 @@
#include "common/ceph_json.h"
#include "common/static_ptr.h"
#include "common/perf_counters_key.h"
+#include "rgw_cksum.h"
#include "rgw_cksum_digest.h"
#include "rgw_common.h"
+#include "common/split.h"
#include "rgw_tracer.h"
#include "rgw_rados.h"
@@ -331,19 +333,6 @@ static int get_obj_policy_from_attr(const DoutPrefixProvider *dpp,
return ret;
}
-
-static boost::optional<Policy>
-get_iam_policy_from_attr(CephContext* cct,
- const map<string, bufferlist>& attrs,
- const string& tenant)
-{
- if (auto i = attrs.find(RGW_ATTR_IAM_POLICY); i != attrs.end()) {
- return Policy(cct, &tenant, i->second.to_str(), false);
- } else {
- return none;
- }
-}
-
static boost::optional<PublicAccessBlockConfiguration>
get_public_access_conf_from_attr(const map<string, bufferlist>& attrs)
{
@@ -1350,9 +1339,9 @@ void RGWDeleteBucketTags::execute(optional_yield y)
}
op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this, y] {
- rgw::sal::Attrs attrs = s->bucket->get_attrs();
+ rgw::sal::Attrs& attrs = s->bucket->get_attrs();
attrs.erase(RGW_ATTR_TAGS);
- op_ret = s->bucket->merge_and_store_attrs(this, attrs, y);
+ op_ret = s->bucket->put_info(this, false, real_time(), y);
if (op_ret < 0) {
ldpp_dout(this, 0) << "RGWDeleteBucketTags() failed to remove RGW_ATTR_TAGS on bucket="
<< s->bucket->get_name()
@@ -3135,17 +3124,19 @@ static int load_bucket_stats(const DoutPrefixProvider* dpp, optional_yield y,
void RGWStatBucket::execute(optional_yield y)
{
- if (!s->bucket_exists) {
- op_ret = -ERR_NO_SUCH_BUCKET;
+ op_ret = get_params(y);
+ if (op_ret < 0) {
return;
}
- op_ret = driver->load_bucket(this, s->bucket->get_key(), &bucket, y);
- if (op_ret) {
+ if (!s->bucket_exists) {
+ op_ret = -ERR_NO_SUCH_BUCKET;
return;
}
- op_ret = load_bucket_stats(this, y, *s->bucket, stats);
+ if (report_stats) {
+ op_ret = load_bucket_stats(this, y, *s->bucket, stats);
+ }
}
int RGWListBucket::verify_permission(optional_yield y)
@@ -3569,54 +3560,62 @@ void RGWCreateBucket::execute(optional_yield y)
const rgw::SiteConfig& site = *s->penv.site;
const std::optional<RGWPeriod>& period = site.get_period();
const RGWZoneGroup& my_zonegroup = site.get_zonegroup();
-
- if (s->system_request) {
- // allow system requests to override the target zonegroup. for forwarded
- // requests, we'll create the bucket for the originating zonegroup
- createparams.zonegroup_id = s->info.args.get(RGW_SYS_PARAM_PREFIX "zonegroup");
- }
-
+ const std::string rgwx_zonegroup = s->info.args.get(RGW_SYS_PARAM_PREFIX "zonegroup");
const RGWZoneGroup* bucket_zonegroup = &my_zonegroup;
- if (createparams.zonegroup_id.empty()) {
- // default to the local zonegroup
- createparams.zonegroup_id = my_zonegroup.id;
- } else if (period) {
- auto z = period->period_map.zonegroups.find(createparams.zonegroup_id);
- if (z == period->period_map.zonegroups.end()) {
- ldpp_dout(this, 0) << "could not find zonegroup "
- << createparams.zonegroup_id << " in current period" << dendl;
- op_ret = -ENOENT;
- return;
- }
- bucket_zonegroup = &z->second;
- } else if (createparams.zonegroup_id != my_zonegroup.id) {
- ldpp_dout(this, 0) << "zonegroup does not match current zonegroup "
- << createparams.zonegroup_id << dendl;
- op_ret = -ENOENT;
- return;
- }
- // validate the LocationConstraint
+ // Validate LocationConstraint if it's provided and enforcement is strict
if (!location_constraint.empty() && !relaxed_region_enforcement) {
- // on the master zonegroup, allow any valid api_name. otherwise it has to
- // match the bucket's zonegroup
- if (period && my_zonegroup.is_master) {
- if (!period->period_map.zonegroups_by_api.count(location_constraint)) {
+ if (period) {
+ auto location_iter = period->period_map.zonegroups_by_api.find(location_constraint);
+ if (location_iter == period->period_map.zonegroups_by_api.end()) {
ldpp_dout(this, 0) << "location constraint (" << location_constraint
<< ") can't be found." << dendl;
op_ret = -ERR_INVALID_LOCATION_CONSTRAINT;
- s->err.message = "The specified location-constraint is not valid";
+ s->err.message = fmt::format("The {} location constraint is not valid.",
+ location_constraint);
return;
}
- } else if (bucket_zonegroup->api_name != location_constraint) {
+ bucket_zonegroup = &location_iter->second;
+ } else if (location_constraint != my_zonegroup.api_name) { // if we don't have a period, we can only use the current zonegroup - so check if the location matches by api name here
ldpp_dout(this, 0) << "location constraint (" << location_constraint
- << ") doesn't match zonegroup (" << bucket_zonegroup->api_name
- << ')' << dendl;
- op_ret = -ERR_INVALID_LOCATION_CONSTRAINT;
- s->err.message = "The specified location-constraint is not valid";
+ << ") doesn't match zonegroup (" << my_zonegroup.api_name << ")" << dendl;
+ op_ret = -ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION;
+ s->err.message = fmt::format("The {} location constraint is incompatible "
+ "for the region specific endpoint this request was sent to.",
+ location_constraint);
return;
}
}
+ // If it's a system request, use the provided zonegroup if available
+ else if (s->system_request && !rgwx_zonegroup.empty()) {
+ if (period) {
+ auto zonegroup_iter = period->period_map.zonegroups.find(rgwx_zonegroup);
+ if (zonegroup_iter == period->period_map.zonegroups.end()) {
+ ldpp_dout(this, 0) << "could not find zonegroup " << rgwx_zonegroup
+ << " in current period" << dendl;
+ op_ret = -ENOENT;
+ return;
+ }
+ bucket_zonegroup = &zonegroup_iter->second;
+ }
+ }
+
+ const bool enforce_location_match =
+ !period || // No period: no multisite, so no need to enforce location match.
+ !s->system_request || // All user requests are enforced to match zonegroup's location.
+ !my_zonegroup.is_master; // but if it's a system request (forwarded) only allow remote creation on master zonegroup.
+ if (enforce_location_match && !my_zonegroup.equals(bucket_zonegroup->get_id())) {
+ ldpp_dout(this, 0) << "location constraint (" << bucket_zonegroup->api_name
+ << ") doesn't match zonegroup (" << my_zonegroup.api_name << ")" << dendl;
+ op_ret = -ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION;
+ s->err.message = fmt::format("The {} location constraint is incompatible "
+ "for the region specific endpoint this request was sent to.",
+ bucket_zonegroup->api_name);
+ return;
+ }
+
+ // Set the final zonegroup ID
+ createparams.zonegroup_id = bucket_zonegroup->id;
// select and validate the placement target
op_ret = select_bucket_placement(this, *bucket_zonegroup, s->user->get_info(),
@@ -3625,7 +3624,7 @@ void RGWCreateBucket::execute(optional_yield y)
return;
}
- if (bucket_zonegroup == &my_zonegroup) {
+ if (my_zonegroup.equals(bucket_zonegroup->get_id())) {
// look up the zone placement pool
createparams.zone_placement = rgw::find_zone_placement(
this, site.get_zone_params(), createparams.placement_rule);
@@ -3714,7 +3713,6 @@ void RGWCreateBucket::execute(optional_yield y)
if (!driver->is_meta_master()) {
// apply bucket creation on the master zone first
- bufferlist in_data;
JSONParser jp;
op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id,
&in_data, &jp, s->info, y);
@@ -3791,7 +3789,10 @@ void RGWCreateBucket::execute(optional_yield y)
s->bucket->get_info().has_website = !s->bucket->get_info().website_conf.is_empty();
/* This will also set the quota on the bucket. */
- op_ret = s->bucket->merge_and_store_attrs(this, createparams.attrs, y);
+ s->bucket->set_attrs(std::move(createparams.attrs));
+ constexpr bool exclusive = false; // overwrite
+ constexpr ceph::real_time no_set_mtime{};
+ op_ret = s->bucket->put_info(this, exclusive, no_set_mtime, y);
} while (op_ret == -ECANCELED && tries++ < 20);
/* Restore the proper return code. */
@@ -4342,6 +4343,9 @@ void RGWPutObj::execute(optional_yield y)
}
return;
}
+
+ multipart_cksum_type = upload->cksum_type;
+
/* upload will go out of scope, so copy the dest placement for later use */
s->dest_placement = *pdest_placement;
pdest_placement = &s->dest_placement;
@@ -4472,11 +4476,12 @@ void RGWPutObj::execute(optional_yield y)
/* optional streaming checksum */
try {
cksum_filter =
- rgw::putobj::RGWPutObj_Cksum::Factory(filter, *s->info.env);
+ rgw::putobj::RGWPutObj_Cksum::Factory(filter, *s->info.env, multipart_cksum_type);
} catch (const rgw::io::Exception& e) {
op_ret = -e.code().value();
return;
}
+
if (cksum_filter) {
filter = &*cksum_filter;
}
@@ -4623,10 +4628,12 @@ void RGWPutObj::execute(optional_yield y)
if (cksum_filter) {
const auto& hdr = cksum_filter->header();
+ auto expected_ck = cksum_filter->expected(*s->info.env);
auto cksum_verify =
cksum_filter->verify(*s->info.env); // valid or no supplied cksum
cksum = get<1>(cksum_verify);
- if (std::get<0>(cksum_verify)) {
+ if ((!expected_ck) ||
+ std::get<0>(cksum_verify)) {
buffer::list cksum_bl;
ldpp_dout_fmt(this, 16,
@@ -4634,14 +4641,13 @@ void RGWPutObj::execute(optional_yield y)
"\n\tcomputed={} == \n\texpected={}",
hdr.second,
cksum->to_armor(),
- cksum_filter->expected(*s->info.env));
+ (!!expected_ck) ? expected_ck : "(checksum unavailable)");
cksum->encode(cksum_bl);
emplace_attr(RGW_ATTR_CKSUM, std::move(cksum_bl));
} else {
/* content checksum mismatch */
auto computed_ck = cksum->to_armor();
- auto expected_ck = cksum_filter->expected(*s->info.env);
ldpp_dout_fmt(this, 4,
"{} content checksum mismatch"
@@ -4844,7 +4850,8 @@ void RGWPostObj::execute(optional_yield y)
/* optional streaming checksum */
try {
cksum_filter =
- rgw::putobj::RGWPutObj_Cksum::Factory(filter, *s->info.env);
+ rgw::putobj::RGWPutObj_Cksum::Factory(
+ filter, *s->info.env, rgw::cksum::Type::none /* no override */);
} catch (const rgw::io::Exception& e) {
op_ret = -e.code().value();
return;
@@ -5192,7 +5199,10 @@ void RGWPutMetadataBucket::execute(optional_yield y)
/* Setting attributes also stores the provided bucket info. Due
* to this fact, the new quota settings can be serialized with
* the same call. */
- op_ret = s->bucket->merge_and_store_attrs(this, attrs, s->yield);
+ s->bucket->set_attrs(attrs);
+ constexpr bool exclusive = false; // overwrite
+ constexpr ceph::real_time no_set_mtime{};
+ op_ret = s->bucket->put_info(this, exclusive, no_set_mtime, s->yield);
return op_ret;
}, y);
}
@@ -5980,8 +5990,6 @@ void RGWGetACLs::execute(optional_yield y)
acls = ss.str();
}
-
-
int RGWPutACLs::verify_permission(optional_yield y)
{
bool perm;
@@ -6003,6 +6011,74 @@ int RGWPutACLs::verify_permission(optional_yield y)
return 0;
}
+uint16_t RGWGetObjAttrs::recognize_attrs(const std::string& hdr, uint16_t deflt)
+{
+ auto attrs{deflt};
+ auto sa = ceph::split(hdr, ",");
+ for (auto& k : sa) {
+ if (boost::iequals(k, "etag")) {
+ attrs |= as_flag(ReqAttributes::Etag);
+ }
+ if (boost::iequals(k, "checksum")) {
+ attrs |= as_flag(ReqAttributes::Checksum);
+ }
+ if (boost::iequals(k, "objectparts")) {
+ attrs |= as_flag(ReqAttributes::ObjectParts);
+ }
+ if (boost::iequals(k, "objectsize")) {
+ attrs |= as_flag(ReqAttributes::ObjectSize);
+ }
+ if (boost::iequals(k, "storageclass")) {
+ attrs |= as_flag(ReqAttributes::StorageClass);
+ }
+ }
+ return attrs;
+} /* RGWGetObjAttrs::recognize_attrs */
+
+int RGWGetObjAttrs::verify_permission(optional_yield y)
+{
+ bool perm = false;
+ auto [has_s3_existing_tag, has_s3_resource_tag] =
+ rgw_check_policy_condition(this, s);
+
+ if (! rgw::sal::Object::empty(s->object.get())) {
+
+ auto iam_action1 = s->object->get_instance().empty() ?
+ rgw::IAM::s3GetObject :
+ rgw::IAM::s3GetObjectVersion;
+
+ auto iam_action2 = s->object->get_instance().empty() ?
+ rgw::IAM::s3GetObjectAttributes :
+ rgw::IAM::s3GetObjectVersionAttributes;
+
+ if (has_s3_existing_tag || has_s3_resource_tag) {
+ rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag);
+ }
+
+ /* XXXX the following conjunction should be &&--but iam_action2 is currently not
+ * hooked up and always fails (but should succeed if the requestor has READ
+ * acess to the object) */
+ perm = (verify_object_permission(this, s, iam_action1) || /* && */
+ verify_object_permission(this, s, iam_action2));
+ }
+
+ if (! perm) {
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+void RGWGetObjAttrs::pre_exec()
+{
+ rgw_bucket_object_pre_exec(s);
+}
+
+void RGWGetObjAttrs::execute(optional_yield y)
+{
+ RGWGetObj::execute(y);
+} /* RGWGetObjAttrs::execute */
+
int RGWGetLC::verify_permission(optional_yield y)
{
auto [has_s3_existing_tag, has_s3_resource_tag] = rgw_check_policy_condition(this, s, false);
@@ -6384,9 +6460,9 @@ void RGWDeleteCORS::execute(optional_yield y)
return op_ret;
}
- rgw::sal::Attrs attrs(s->bucket_attrs);
+ rgw::sal::Attrs& attrs = s->bucket->get_attrs();
attrs.erase(RGW_ATTR_CORS);
- op_ret = s->bucket->merge_and_store_attrs(this, attrs, s->yield);
+ op_ret = s->bucket->put_info(this, false, real_time(), s->yield);
if (op_ret < 0) {
ldpp_dout(this, 0) << "RGWLC::RGWDeleteCORS() failed to set attrs on bucket=" << s->bucket->get_name()
<< " returned err=" << op_ret << dendl;
@@ -6670,6 +6746,14 @@ try_sum_part_cksums(const DoutPrefixProvider *dpp,
++parts_ix;
auto& part_cksum = part.second->get_cksum();
+ if (! part_cksum) {
+ ldpp_dout_fmt(dpp, 0,
+ "ERROR: multipart part checksum not present (ix=={})",
+ parts_ix);
+ op_ret = -ERR_INVALID_REQUEST;
+ return op_ret;
+ }
+
ldpp_dout_fmt(dpp, 16,
"INFO: {} iterate part: {} {} {}",
__func__, parts_ix, part_cksum->type_string(),
@@ -7040,17 +7124,30 @@ void RGWAbortMultipart::execute(optional_yield y)
return;
upload = s->bucket->get_multipart_upload(s->object->get_name(), upload_id);
+ meta_obj = upload->get_meta_obj();
+ meta_obj->set_in_extra_data(true);
+ meta_obj->get_obj_attrs(s->yield, this);
+
jspan_context trace_ctx(false, false);
if (tracing::rgw::tracer.is_enabled()) {
// read meta object attributes for trace info
- meta_obj = upload->get_meta_obj();
- meta_obj->set_in_extra_data(true);
- meta_obj->get_obj_attrs(s->yield, this);
extract_span_context(meta_obj->get_attrs(), trace_ctx);
}
multipart_trace = tracing::rgw::tracer.add_span(name(), trace_ctx);
+ int max_lock_secs_mp =
+ s->cct->_conf.get_val<int64_t>("rgw_mp_lock_max_time");
+ utime_t dur(max_lock_secs_mp, 0);
+ auto serializer = meta_obj->get_serializer(this, "RGWCompleteMultipart");
+ op_ret = serializer->try_lock(this, dur, y);
+ if (op_ret < 0) {
+ if (op_ret == -ENOENT) {
+ op_ret = -ERR_NO_SUCH_UPLOAD;
+ }
+ return;
+ }
op_ret = upload->abort(this, s->cct, y);
+ serializer->unlock();
}
int RGWListMultipart::verify_permission(optional_yield y)
@@ -7354,6 +7451,12 @@ void RGWDeleteMultiObj::execute(optional_yield y)
return;
}
+ if (multi_delete->objects.empty()) {
+ s->err.message = "Missing required element Object";
+ op_ret = -ERR_MALFORMED_XML;
+ return;
+ }
+
constexpr int DEFAULT_MAX_NUM = 1000;
int max_num = s->cct->_conf->rgw_delete_multi_obj_max_num;
if (max_num < 0) {
@@ -8509,9 +8612,9 @@ void RGWDeleteBucketPolicy::execute(optional_yield y)
}
op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this] {
- rgw::sal::Attrs attrs(s->bucket_attrs);
+ rgw::sal::Attrs& attrs = s->bucket->get_attrs();
attrs.erase(RGW_ATTR_IAM_POLICY);
- op_ret = s->bucket->merge_and_store_attrs(this, attrs, s->yield);
+ op_ret = s->bucket->put_info(this, false, real_time(), s->yield);
return op_ret;
}, y);
}
@@ -9029,9 +9132,9 @@ void RGWDeleteBucketPublicAccessBlock::execute(optional_yield y)
}
op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this] {
- rgw::sal::Attrs attrs(s->bucket_attrs);
+ rgw::sal::Attrs& attrs = s->bucket->get_attrs();
attrs.erase(RGW_ATTR_PUBLIC_ACCESS);
- op_ret = s->bucket->merge_and_store_attrs(this, attrs, s->yield);
+ op_ret = s->bucket->put_info(this, false, real_time(), s->yield);
return op_ret;
}, y);
}
@@ -9140,10 +9243,10 @@ void RGWDeleteBucketEncryption::execute(optional_yield y)
}
op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this, y] {
- rgw::sal::Attrs attrs = s->bucket->get_attrs();
+ rgw::sal::Attrs& attrs = s->bucket->get_attrs();
attrs.erase(RGW_ATTR_BUCKET_ENCRYPTION_POLICY);
attrs.erase(RGW_ATTR_BUCKET_ENCRYPTION_KEY_ID);
- op_ret = s->bucket->merge_and_store_attrs(this, attrs, y);
+ op_ret = s->bucket->put_info(this, false, real_time(), y);
return op_ret;
}, y);
}