]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: data sync: check user permission in user level sync
authorYehuda Sadeh <yehuda@redhat.com>
Sat, 23 Nov 2019 05:02:36 +0000 (21:02 -0800)
committerYehuda Sadeh <yehuda@redhat.com>
Tue, 28 Jan 2020 18:20:39 +0000 (10:20 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/rgw/rgw_admin.cc
src/rgw/rgw_bucket_sync.cc
src/rgw/rgw_bucket_sync.h
src/rgw/rgw_common.h
src/rgw/rgw_cr_rados.cc
src/rgw/rgw_cr_rados.h
src/rgw/rgw_data_sync.cc
src/rgw/rgw_data_sync.h
src/rgw/rgw_trim_bilog.cc
src/rgw/services/svc_bucket_sync_sobj.cc

index acfd7974152924d8baabfd732d417b88de46cff1..509a0ed5ac2e88ffa516f69b0704b2eef41aabad 100644 (file)
@@ -2397,15 +2397,16 @@ static int sync_info(std::optional<rgw_zone_id> opt_target_zone, std::optional<r
   if (eff_bucket) {
     rgw_bucket bucket;
     RGWBucketInfo bucket_info;
+    map<string, bufferlist> bucket_attrs;
 
-    int ret = init_bucket(*eff_bucket, bucket_info, bucket);
+    int ret = init_bucket(*eff_bucket, bucket_info, bucket, &bucket_attrs);
     if (ret < 0 && ret != -ENOENT) {
       cerr << "ERROR: init_bucket failed: " << cpp_strerror(-ret) << std::endl;
       return ret;
     }
 
     if (ret >= 0) {
-      bucket_handler.reset(handler->alloc_child(bucket_info));
+      bucket_handler.reset(handler->alloc_child(bucket_info, std::move(bucket_attrs)));
     } else {
       cerr << "WARNING: bucket not found, simulating result" << std::endl;
       bucket_handler.reset(handler->alloc_child(*eff_bucket, nullopt));
index 3a57f546a73f85a4beab4e9f70197d462a77135a..6ce7341b4173453c08241bd402ed37ba4c6211b4 100644 (file)
@@ -669,8 +669,10 @@ RGWBucketSyncPolicyHandler::RGWBucketSyncPolicyHandler(RGWSI_Zone *_zone_svc,
 }
 
 RGWBucketSyncPolicyHandler::RGWBucketSyncPolicyHandler(const RGWBucketSyncPolicyHandler *_parent,
-                                                       const RGWBucketInfo& _bucket_info) : parent(_parent),
-                                                                                            bucket_info(_bucket_info) {
+                                                       const RGWBucketInfo& _bucket_info,
+                                                       map<string, bufferlist>&& _bucket_attrs) : parent(_parent),
+                                                                                                       bucket_info(_bucket_info),
+                                                                                                       bucket_attrs(std::move(_bucket_attrs)) {
   if (_bucket_info.sync_policy) {
     sync_policy = *_bucket_info.sync_policy;
 
@@ -705,9 +707,10 @@ RGWBucketSyncPolicyHandler::RGWBucketSyncPolicyHandler(const RGWBucketSyncPolicy
                                               parent->flow_mgr.get()));
 }
 
-RGWBucketSyncPolicyHandler *RGWBucketSyncPolicyHandler::alloc_child(const RGWBucketInfo& bucket_info) const
+RGWBucketSyncPolicyHandler *RGWBucketSyncPolicyHandler::alloc_child(const RGWBucketInfo& bucket_info,
+                                                                    map<string, bufferlist>&& bucket_attrs) const
 {
-  return new RGWBucketSyncPolicyHandler(this, bucket_info);
+  return new RGWBucketSyncPolicyHandler(this, bucket_info, std::move(bucket_attrs));
 }
 
 RGWBucketSyncPolicyHandler *RGWBucketSyncPolicyHandler::alloc_child(const rgw_bucket& bucket,
index a57c461de85435594a531dfd2216862683261b9e..8545d4986d5bbc6c26673ef99e45872307c3803f 100644 (file)
@@ -280,6 +280,7 @@ class RGWBucketSyncPolicyHandler {
   RGWSI_Bucket_Sync *bucket_sync_svc;
   rgw_zone_id zone_id;
   std::optional<RGWBucketInfo> bucket_info;
+  std::optional<map<string, bufferlist> > bucket_attrs;
   std::optional<rgw_bucket> bucket;
   std::unique_ptr<RGWBucketSyncFlowManager> flow_mgr;
   rgw_sync_policy_info sync_policy;
@@ -308,7 +309,8 @@ class RGWBucketSyncPolicyHandler {
   }
 
   RGWBucketSyncPolicyHandler(const RGWBucketSyncPolicyHandler *_parent,
-                             const RGWBucketInfo& _bucket_info);
+                             const RGWBucketInfo& _bucket_info,
+                             map<string, bufferlist>&& _bucket_attrs);
 
   RGWBucketSyncPolicyHandler(const RGWBucketSyncPolicyHandler *_parent,
                              const rgw_bucket& _bucket,
@@ -319,7 +321,8 @@ public:
                             RGWSI_Bucket_Sync *bucket_sync_svc,
                              std::optional<rgw_zone_id> effective_zone = std::nullopt);
 
-  RGWBucketSyncPolicyHandler *alloc_child(const RGWBucketInfo& bucket_info) const;
+  RGWBucketSyncPolicyHandler *alloc_child(const RGWBucketInfo& bucket_info,
+                                          map<string, bufferlist>&& bucket_attrs) const;
   RGWBucketSyncPolicyHandler *alloc_child(const rgw_bucket& bucket,
                                           std::optional<rgw_sync_policy_info> sync_policy) const;
 
@@ -367,6 +370,10 @@ public:
     return bucket_info;
   }
 
+  const std::optional<map<string, bufferlist> >& get_bucket_attrs() const {
+    return bucket_attrs;
+  }
+
   void get_pipes(RGWBucketSyncFlowManager::pipe_set **_sources, RGWBucketSyncFlowManager::pipe_set **_targets) { /* return raw pipes (with zone name) */
     *_sources = &source_pipes;
     *_targets = &target_pipes;
index d11f6a81acfa4cae807ef6bc61b3707f241c0ae0..497af6bc8aea7d178cfb9b95d11a7faab70a93a1 100644 (file)
@@ -2496,6 +2496,13 @@ bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
                                       RGWAccessControlPolicy * const user_acl,
                                       const int perm);
 
+bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp,
+                                        struct perm_state_base * const s,
+                                       RGWAccessControlPolicy * const user_acl,
+                                       RGWAccessControlPolicy * const bucket_acl,
+                                       RGWAccessControlPolicy * const object_acl,
+                                       const int perm);
+
 /** Check if the req_state's user has the necessary permissions
  * to do the requested action */
 rgw::IAM::Effect eval_user_policies(const vector<rgw::IAM::Policy>& user_policies,
index 93748ef24569a757aff4e89a6122e19b35d60030..b1da90104cf77dcd273ff1498e3ad0e6519b1940 100644 (file)
@@ -533,9 +533,10 @@ int RGWAsyncGetBucketInstanceInfo::_send_request()
   int r;
   if (!bucket.bucket_id.empty()) {
     RGWSysObjectCtx obj_ctx = store->svc()->sysobj->init_obj_ctx();
-    r = store->getRados()->get_bucket_instance_info(obj_ctx, bucket, bucket_info, nullptr, nullptr, null_yield);
+    r = store->getRados()->get_bucket_instance_info(obj_ctx, bucket, bucket_info, nullptr, &attrs, null_yield);
   } else {
-    r = store->ctl()->bucket->read_bucket_info(bucket, &bucket_info, null_yield);
+    r = store->ctl()->bucket->read_bucket_info(bucket, &bucket_info, null_yield,
+                                               RGWBucketCtl::BucketInstance::GetParams().set_attrs(&attrs));
   }
   if (r < 0) {
     ldout(store->ctx(), 0) << "ERROR: failed to get bucket instance info for "
index 289ff5464863daae6495b556cee17e195451c021..36752997eb4263af7489aa13c2c980b5c3de3e90 100644 (file)
@@ -863,6 +863,7 @@ public:
     : RGWAsyncRadosRequest(caller, cn), store(_store), bucket(bucket) {}
 
   RGWBucketInfo bucket_info;
+  map<string, bufferlist> attrs;
 };
 
 class RGWGetBucketInstanceInfoCR : public RGWSimpleCoroutine {
@@ -870,15 +871,17 @@ class RGWGetBucketInstanceInfoCR : public RGWSimpleCoroutine {
   rgw::sal::RGWRadosStore *store;
   rgw_bucket bucket;
   RGWBucketInfo *bucket_info;
+  map<string, bufferlist> *pattrs;
 
   RGWAsyncGetBucketInstanceInfo *req{nullptr};
   
 public:
   // rgw_bucket constructor
   RGWGetBucketInstanceInfoCR(RGWAsyncRadosProcessor *_async_rados, rgw::sal::RGWRadosStore *_store,
-                             const rgw_bucket& _bucket, RGWBucketInfo *_bucket_info)
+                             const rgw_bucket& _bucket, RGWBucketInfo *_bucket_info,
+                             map<string, bufferlist> *_pattrs)
     : RGWSimpleCoroutine(_store->ctx()), async_rados(_async_rados), store(_store),
-      bucket(_bucket), bucket_info(_bucket_info) {}
+      bucket(_bucket), bucket_info(_bucket_info), pattrs(_pattrs) {}
   ~RGWGetBucketInstanceInfoCR() override {
     request_cleanup();
   }
@@ -898,6 +901,9 @@ public:
     if (bucket_info) {
       *bucket_info = std::move(req->bucket_info);
     }
+    if (pattrs) {
+      *pattrs = std::move(req->attrs);
+    }
     return req->get_ret_status();
   }
 };
index 101b6199741e27106936fb084b8b39a2cafcc71d..11fb88f561c79854de3b269a27e38df2108a39b9 100644 (file)
@@ -1047,10 +1047,16 @@ public:
   int operate() override;
 };
 
+struct all_bucket_info {
+  RGWBucketInfo bucket_info;
+  map<string, bufferlist> attrs;
+};
+
 struct rgw_sync_pipe_info_entity
 {
 private:
   RGWBucketInfo bucket_info;
+  map<string, bufferlist> bucket_attrs;
   bool _has_bucket_info{false};
 
 public:
@@ -1058,7 +1064,7 @@ public:
 
   rgw_sync_pipe_info_entity() {}
   rgw_sync_pipe_info_entity(const rgw_sync_bucket_entity& e,
-                            std::optional<RGWBucketInfo>& binfo) {
+                            std::optional<all_bucket_info>& binfo) {
     if (e.zone) {
       zone = *e.zone;
     }
@@ -1066,14 +1072,14 @@ public:
       return;
     }
     if (!binfo ||
-        binfo->bucket != *e.bucket) {
+        binfo->bucket_info.bucket != *e.bucket) {
       bucket_info.bucket = *e.bucket;
     } else {
       set_bucket_info(*binfo);
     }
   }
 
-  void update_empty_bucket_info(const std::map<rgw_bucket, RGWBucketInfo>& buckets_info) {
+  void update_empty_bucket_info(const std::map<rgw_bucket, all_bucket_info>& buckets_info) {
     if (_has_bucket_info) {
       return;
     }
@@ -1093,8 +1099,9 @@ public:
     return _has_bucket_info;
   }
 
-  void set_bucket_info(const RGWBucketInfo& _bucket_info) {
-    bucket_info = _bucket_info;
+  void set_bucket_info(const all_bucket_info& all_info) {
+    bucket_info = all_info.bucket_info;
+    bucket_attrs = all_info.attrs;
     _has_bucket_info = true;
   }
 
@@ -1131,10 +1138,10 @@ struct rgw_sync_pipe_handler_info {
 
   rgw_sync_pipe_handler_info() {}
   rgw_sync_pipe_handler_info(const RGWBucketSyncFlowManager::pipe_handler& _handler,
-                     std::optional<RGWBucketInfo> source_bucket_info,
-                     std::optional<RGWBucketInfo> target_bucket_info) : handler(_handler),
-                                                                        source(handler.source, source_bucket_info),
-                                                                        target(handler.dest, target_bucket_info) {
+                     std::optional<all_bucket_info> source_bucket_info,
+                     std::optional<all_bucket_info> target_bucket_info) : handler(_handler),
+                                                                          source(handler.source, source_bucket_info),
+                                                                          target(handler.dest, target_bucket_info) {
   }
 
   bool operator<(const rgw_sync_pipe_handler_info& p) const {
@@ -1147,7 +1154,7 @@ struct rgw_sync_pipe_handler_info {
     return (target < p.target);
   }
 
-  void update_empty_bucket_info(const std::map<rgw_bucket, RGWBucketInfo>& buckets_info) {
+  void update_empty_bucket_info(const std::map<rgw_bucket, all_bucket_info>& buckets_info) {
     source.update_empty_bucket_info(buckets_info);
     target.update_empty_bucket_info(buckets_info);
   }
@@ -1168,8 +1175,8 @@ struct rgw_sync_pipe_info_set {
   }
 
   void insert(const RGWBucketSyncFlowManager::pipe_handler& handler,
-              std::optional<RGWBucketInfo>& source_bucket_info,
-              std::optional<RGWBucketInfo>& target_bucket_info) {
+              std::optional<all_bucket_info>& source_bucket_info,
+              std::optional<all_bucket_info>& target_bucket_info) {
     rgw_sync_pipe_handler_info p(handler, source_bucket_info, target_bucket_info);
     handlers.insert(p);
   }
@@ -1186,7 +1193,7 @@ struct rgw_sync_pipe_info_set {
     return handlers.empty();
   }
 
-  void update_empty_bucket_info(const std::map<rgw_bucket, RGWBucketInfo>& buckets_info) {
+  void update_empty_bucket_info(const std::map<rgw_bucket, all_bucket_info>& buckets_info) {
     if (buckets_info.empty()) {
       return;
     }
@@ -1971,16 +1978,188 @@ int RGWDefaultSyncModule::create_instance(CephContext *cct, const JSONFormattabl
   return 0;
 }
 
+class RGWUserPermHandler {
+  friend struct Init;
+  friend class Bucket;
+
+  RGWDataSyncEnv *sync_env;
+  rgw_user uid;
+
+  struct _info {
+    RGWUserInfo user_info;
+    rgw::IAM::Environment env;
+    std::unique_ptr<rgw::auth::Identity> identity;
+    RGWAccessControlPolicy user_acl;
+  };
+
+  std::shared_ptr<_info> info;
+
+  struct Init;
+
+  std::shared_ptr<Init> init_action;
+
+  struct Init : public RGWGenericAsyncCR::Action {
+    RGWDataSyncEnv *sync_env;
+
+    rgw_user uid;
+    std::shared_ptr<RGWUserPermHandler::_info> info;
+
+    int ret{0};
+    
+    Init(RGWUserPermHandler *handler) : sync_env(handler->sync_env),
+                                        uid(handler->uid),
+                                        info(handler->info) {}
+    int operate() override {
+      auto user_ctl = sync_env->store->getRados()->ctl.user;
+
+      ret = user_ctl->get_info_by_uid(uid, &info->user_info, null_yield);
+      if (ret < 0) {
+        return ret;
+      }
+
+      info->identity = rgw::auth::transform_old_authinfo(sync_env->cct,
+                                                         uid,
+                                                         RGW_PERM_FULL_CONTROL,
+                                                         false, /* system_request? */
+                                                         TYPE_RGW);
+
+      map<string, bufferlist> uattrs;
+
+      ret = user_ctl->get_attrs_by_uid(uid, &uattrs, null_yield);
+      if (ret == 0) {
+        ret = RGWUserPermHandler::policy_from_attrs(sync_env->cct, uattrs, &info->user_acl);
+      }
+      if (ret == -ENOENT) {
+        info->user_acl.create_default(uid, info->user_info.display_name);
+      }
+
+      return 0;
+    }
+  };
+
+public:
+  RGWUserPermHandler(RGWDataSyncEnv *_sync_env,
+                     const rgw_user& _uid) : sync_env(_sync_env),
+                                             uid(_uid) {}
+
+  RGWCoroutine *init_cr() {
+    info = make_shared<_info>();
+    init_action = make_shared<Init>(this);
+
+    return new RGWGenericAsyncCR(sync_env->cct,
+                                 sync_env->async_rados,
+                                 init_action);
+  }
+
+  class Bucket {
+    RGWDataSyncEnv *sync_env;
+    std::shared_ptr<_info> info;
+    RGWAccessControlPolicy bucket_acl;
+    std::optional<perm_state> ps;
+  public:
+    Bucket() {}
+
+    int init(RGWUserPermHandler *handler,
+             const RGWBucketInfo& bucket_info,
+             const map<string, bufferlist>& bucket_attrs);
+
+    bool verify_bucket_permission(int perm);
+    bool verify_object_permission(const map<string, bufferlist>& obj_attrs,
+                                  int perm);
+  };
+
+  static int policy_from_attrs(CephContext *cct,
+                               const map<string, bufferlist>& attrs,
+                               RGWAccessControlPolicy *acl) {
+    acl->set_ctx(cct);
+
+    auto aiter = attrs.find(RGW_ATTR_ACL);
+    if (aiter == attrs.end()) {
+      return -ENOENT;
+    }
+    auto iter = aiter->second.begin();
+    try {
+      acl->decode(iter);
+    } catch (buffer::error& err) {
+      ldout(cct, 0) << "ERROR: " << __func__ << "(): could not decode policy, caught buffer::error" << dendl;
+      return -EIO;
+    }
+
+    return 0;
+  }
+
+  int init_bucket(const RGWBucketInfo& bucket_info,
+                  const map<string, bufferlist>& bucket_attrs,
+                  Bucket *bs) {
+    return bs->init(this, bucket_info, bucket_attrs);
+  }
+};
+
+int RGWUserPermHandler::Bucket::init(RGWUserPermHandler *handler,
+                                     const RGWBucketInfo& bucket_info,
+                                     const map<string, bufferlist>& bucket_attrs)
+{
+  sync_env = handler->sync_env;
+  info = handler->info;
+
+  int r = RGWUserPermHandler::policy_from_attrs(sync_env->cct, bucket_attrs, &bucket_acl);
+  if (r < 0) {
+    return r;
+  }
+
+  ps.emplace(sync_env->cct,
+             info->env,
+             info->identity.get(),
+             bucket_info,
+             info->identity->get_perm_mask(),
+             false, /* defer to bucket acls */
+             nullptr, /* referer */
+             false); /* request_payer */
+
+  return 0;
+}
+
+bool RGWUserPermHandler::Bucket::verify_bucket_permission(int perm)
+{
+  return verify_bucket_permission_no_policy(sync_env->dpp,
+                                            &(*ps),
+                                            &info->user_acl,
+                                            &bucket_acl,
+                                            perm);
+}
+
+bool RGWUserPermHandler::Bucket::verify_object_permission(const map<string, bufferlist>& obj_attrs,
+                                                          int perm)
+{
+  RGWAccessControlPolicy obj_acl;
+
+  int r = policy_from_attrs(sync_env->cct, obj_attrs, &obj_acl);
+  if (r < 0) {
+    return r;
+  }
+
+  return verify_bucket_permission_no_policy(sync_env->dpp,
+                                            &(*ps),
+                                            &bucket_acl,
+                                            &obj_acl,
+                                            perm);
+}
+
 class RGWFetchObjFilter_Sync : public RGWFetchObjFilter_Default {
   rgw_bucket_sync_pipe sync_pipe;
 
+  std::shared_ptr<RGWUserPermHandler::Bucket> bucket_perms;
+
   std::optional<ceph::real_time> mtime;
   std::optional<string> etag;
   std::optional<uint64_t> obj_size;
 
+  std::unique_ptr<rgw::auth::Identity> identity;
+
 public:
-  RGWFetchObjFilter_Sync(rgw_bucket_sync_pipe& _sync_pipe) : sync_pipe(_sync_pipe) {
-  }
+  RGWFetchObjFilter_Sync(rgw_bucket_sync_pipe& _sync_pipe,
+                         std::shared_ptr<RGWUserPermHandler::Bucket>& _bucket_perms) : sync_pipe(_sync_pipe),
+                                                                                       bucket_perms(_bucket_perms) {}
 
   int filter(CephContext *cct,
              const rgw_obj_key& source_key,
@@ -2022,22 +2201,10 @@ int RGWFetchObjFilter_Sync::filter(CephContext *cct,
   std::optional<std::map<string, bufferlist> > new_attrs;
 
   if (params.mode == rgw_sync_pipe_params::MODE_USER) {
-#if 0
-    RGWAccessControlPolicy policy;
-    auto iter = obj_attrs.find(RGW_ATTR_ACL);
-    if (iter == obj_attrs.end()) {
-      ldout(cct, 0) << "ERROR: " << __func__ << ": No policy header to object: aborting sync" << dendl;
-      return abort_err;
-    }
-    try {
-      auto it = iter->second.cbegin();
-      decode(policy, it);
-    } catch (buffer::error &err) {
-      ldout(cct, 0) << "ERROR: " << __func__ << ": caught buffer::error couldn't decode policy " << dendl;
-      return abort_err;
+    if (!bucket_perms->verify_object_permission(obj_attrs, RGW_PERM_READ)) {
+      ldout(cct, 0) << "ERROR: " << __func__ << ": permission check failed: user not allowed to fetch object" << dendl;
+      return -EPERM;
     }
-#endif
-    
   }
 
   if (!dest_placement_rule &&
@@ -2056,12 +2223,12 @@ int RGWFetchObjFilter_Sync::filter(CephContext *cct,
                                            prule);
 }
 
-
 class RGWObjFetchCR : public RGWCoroutine {
   RGWDataSyncCtx *sc;
   RGWDataSyncEnv *sync_env;
   rgw_bucket_sync_pipe& sync_pipe;
   rgw_obj_key& key;
+  std::optional<rgw_obj_key> dest_key;
   std::optional<uint64_t> versioned_epoch;
   rgw_zone_set *zones_trace;
 
@@ -2078,15 +2245,21 @@ class RGWObjFetchCR : public RGWCoroutine {
   std::optional<rgw_user> param_acl_translation;
   std::optional<string> param_storage_class;
   rgw_sync_pipe_params::Mode param_mode;
+
+  std::optional<RGWUserPermHandler> user_perms;
+  std::shared_ptr<RGWUserPermHandler::Bucket> source_bucket_perms;
+  RGWUserPermHandler::Bucket dest_bucket_perms;
 public:
   RGWObjFetchCR(RGWDataSyncCtx *_sc,
                 rgw_bucket_sync_pipe& _sync_pipe,
                 rgw_obj_key& _key,
+                std::optional<rgw_obj_key> _dest_key,
                 std::optional<uint64_t> _versioned_epoch,
                 rgw_zone_set *_zones_trace) : RGWCoroutine(_sc->cct),
                                               sc(_sc), sync_env(_sc->env),
                                               sync_pipe(_sync_pipe),
                                               key(_key),
+                                              dest_key(_dest_key),
                                               versioned_epoch(_versioned_epoch),
                                               zones_trace(_zones_trace) {}
 
@@ -2154,19 +2327,54 @@ public:
         param_mode = params.mode;
       }
 
-      yield {
-        auto filter = make_shared<RGWFetchObjFilter_Sync>(sync_pipe);
+      if (param_mode == rgw_sync_pipe_params::MODE_USER) {
+        if (!param_user) {
+          ldout(cct, 20) << "ERROR: " << __func__ << ": user level sync but user param not set" << dendl;
+          return set_cr_error(-EPERM);
+        }
+        user_perms.emplace(sync_env, *param_user);
 
-        std::optional<rgw_user> uid;
-        if (param_mode == rgw_sync_pipe_params::MODE_USER) {
-          uid = param_user;
+        yield call(user_perms->init_cr());
+        if (retcode < 0) {
+          ldout(cct, 20) << "ERROR: " << __func__ << ": failed to init user perms manager for uid=" << *param_user << dendl;
+          return set_cr_error(retcode);
+        }
+
+        /* verify that user is allowed to write at the target bucket */
+        int r = user_perms->init_bucket(sync_pipe.dest_bucket_info,
+                                        sync_pipe.dest_bucket_attrs,
+                                        &dest_bucket_perms);
+        if (r < 0) {
+          ldout(cct, 20) << "ERROR: " << __func__ << ": failed to init bucket perms manager for uid=" << *param_user << " bucket=" << sync_pipe.source_bucket_info.bucket.get_key() << dendl;
+          return set_cr_error(retcode);
+        }
+
+        if (!dest_bucket_perms.verify_bucket_permission(RGW_PERM_WRITE)) {
+          ldout(cct, 0) << "ERROR: " << __func__ << ": permission check failed: user not allowed to write into bucket (bucket=" << sync_pipe.info.dest_bs.bucket.get_key() << ")" << dendl;
+          return -EPERM;
         }
+
+        /* init source bucket permission structure */
+        source_bucket_perms = make_shared<RGWUserPermHandler::Bucket>();
+        r = user_perms->init_bucket(sync_pipe.source_bucket_info,
+                                        sync_pipe.source_bucket_attrs,
+                                        source_bucket_perms.get());
+        if (r < 0) {
+          ldout(cct, 20) << "ERROR: " << __func__ << ": failed to init bucket perms manager for uid=" << *param_user << " bucket=" << sync_pipe.source_bucket_info.bucket.get_key() << dendl;
+          return set_cr_error(retcode);
+        }
+      }
+
+      yield {
+
+        auto filter = make_shared<RGWFetchObjFilter_Sync>(sync_pipe, source_bucket_perms);
+
 #warning FIXME: race guard
         call(new RGWFetchRemoteObjCR(sync_env->async_rados, sync_env->store, sc->source_zone,
-                                     uid,
+                                     param_user,
                                      sync_pipe.info.source_bs.bucket,
                                      std::nullopt, sync_pipe.dest_bucket_info,
-                                     key, std::nullopt, versioned_epoch,
+                                     key, dest_key, versioned_epoch,
                                      true,
                                      std::static_pointer_cast<RGWFetchObjFilter>(filter),
                                      zones_trace, sync_env->counters, sync_env->dpp));
@@ -2185,9 +2393,7 @@ RGWCoroutine *RGWDefaultDataSyncModule::sync_object(RGWDataSyncCtx *sc, rgw_buck
 {
   auto sync_env = sc->env;
 
-  auto filter = make_shared<RGWFetchObjFilter_Sync>(sync_pipe);
-
-  return new RGWObjFetchCR(sc, sync_pipe, key, versioned_epoch, zones_trace);
+  return new RGWObjFetchCR(sc, sync_pipe, key, std::nullopt, versioned_epoch, zones_trace);
 }
 
 RGWCoroutine *RGWDefaultDataSyncModule::remove_object(RGWDataSyncCtx *sc, rgw_bucket_sync_pipe& sync_pipe, rgw_obj_key& key,
@@ -2264,14 +2470,7 @@ RGWCoroutine *RGWArchiveDataSyncModule::sync_object(RGWDataSyncCtx *sc, rgw_buck
     }
   }
 
-  auto filter = make_shared<RGWFetchObjFilter_Sync>(sync_pipe);
-
-  return new RGWFetchRemoteObjCR(sync_env->async_rados, sync_env->store, sc->source_zone, nullopt,
-                                 sync_pipe.info.source_bs.bucket, std::nullopt, sync_pipe.dest_bucket_info,
-                                 key, dest_key, versioned_epoch,
-                                 true,
-                                 std::static_pointer_cast<RGWFetchObjFilter>(filter),
-                                 zones_trace, nullptr, sync_env->dpp);
+  return new RGWObjFetchCR(sc, sync_pipe, key, dest_key, versioned_epoch, zones_trace);
 }
 
 RGWCoroutine *RGWArchiveDataSyncModule::remove_object(RGWDataSyncCtx *sc, rgw_bucket_sync_pipe& sync_pipe, rgw_obj_key& key,
@@ -3190,6 +3389,17 @@ public:
   }
 };
 
+static bool ignore_sync_error(int err) {
+  switch (err) {
+    case -ENOENT:
+    case -EPERM:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
 template <class T, class K>
 class RGWBucketSyncSingleEntryCR : public RGWCoroutine {
   RGWDataSyncCtx *sc;
@@ -3314,8 +3524,10 @@ public:
         set_status() << "failed to sync obj; retcode=" << retcode;
         tn->log(0, SSTR("ERROR: failed to sync object: "
             << bucket_shard_str{bs} << "/" << key.name));
-        error_ss << bucket_shard_str{bs} << "/" << key.name;
-        sync_status = retcode;
+        if (!ignore_sync_error(retcode)) {
+          error_ss << bucket_shard_str{bs} << "/" << key.name;
+          sync_status = retcode;
+        }
       }
       if (!error_ss.str().empty()) {
         yield call(sync_env->error_logger->log_error_cr(sc->conn->get_remote_id(), "data", error_ss.str(), -retcode, string("failed to sync object") + cpp_strerror(-sync_status)));
@@ -3853,10 +4065,10 @@ class RGWGetBucketPeersCR : public RGWCoroutine {
   std::optional<rgw_bucket> source_bucket;
 
   rgw_sync_pipe_info_set *pipes;
-  map<rgw_bucket, RGWBucketInfo> buckets_info;
-  map<rgw_bucket, RGWBucketInfo>::iterator siiter;
-  std::optional<RGWBucketInfo> target_bucket_info;
-  std::optional<RGWBucketInfo> source_bucket_info;
+  map<rgw_bucket, all_bucket_info> buckets_info;
+  map<rgw_bucket, all_bucket_info>::iterator siiter;
+  std::optional<all_bucket_info> target_bucket_info;
+  std::optional<all_bucket_info> source_bucket_info;
 
   rgw_sync_pipe_info_set::iterator siter;
 
@@ -4086,6 +4298,7 @@ class RGWSyncGetBucketInfoCR : public RGWCoroutine {
   RGWDataSyncEnv *sync_env;
   rgw_bucket bucket;
   RGWBucketInfo *pbucket_info;
+  map<string, bufferlist> *pattrs;
   RGWMetaSyncEnv meta_sync_env;
 
   RGWSyncTraceNodeRef tn;
@@ -4094,11 +4307,13 @@ public:
   RGWSyncGetBucketInfoCR(RGWDataSyncEnv *_sync_env,
                          const rgw_bucket& _bucket,
                          RGWBucketInfo *_pbucket_info,
+                         map<string, bufferlist> *_pattrs,
                          const RGWSyncTraceNodeRef& _tn_parent)
     : RGWCoroutine(_sync_env->cct),
       sync_env(_sync_env),
       bucket(_bucket),
       pbucket_info(_pbucket_info),
+      pattrs(_pattrs),
       tn(sync_env->sync_tracer->add_node(_tn_parent, "get_bucket_info",
                                          SSTR(bucket))) {
   }
@@ -4109,7 +4324,7 @@ public:
 int RGWSyncGetBucketInfoCR::operate()
 {
   reenter(this) {
-    yield call(new RGWGetBucketInstanceInfoCR(sync_env->async_rados, sync_env->store, bucket, pbucket_info));
+    yield call(new RGWGetBucketInstanceInfoCR(sync_env->async_rados, sync_env->store, bucket, pbucket_info, pattrs));
     if (retcode == -ENOENT) {
       /* bucket instance info has not been synced in yet, fetch it now */
       yield {
@@ -4130,7 +4345,7 @@ int RGWSyncGetBucketInfoCR::operate()
         return set_cr_error(retcode);
       }
 
-      yield call(new RGWGetBucketInstanceInfoCR(sync_env->async_rados, sync_env->store, bucket, pbucket_info));
+      yield call(new RGWGetBucketInstanceInfoCR(sync_env->async_rados, sync_env->store, bucket, pbucket_info, pattrs));
     }
     if (retcode < 0) {
       tn->log(0, SSTR("ERROR: failed to retrieve bucket info for bucket=" << bucket_str{bucket}));
@@ -4160,10 +4375,10 @@ void RGWGetBucketPeersCR::update_from_target_bucket_policy()
 
   for (siter = pipes->begin(); siter != pipes->end(); ++siter) {
     if (!siter->source.has_bucket_info()) {
-      buckets_info.emplace(siter->source.get_bucket(), RGWBucketInfo());
+      buckets_info.emplace(siter->source.get_bucket(), all_bucket_info());
     }
     if (!siter->target.has_bucket_info()) {
-      buckets_info.emplace(siter->target.get_bucket(), RGWBucketInfo());
+      buckets_info.emplace(siter->target.get_bucket(), all_bucket_info());
     }
   }
 }
@@ -4185,10 +4400,10 @@ void RGWGetBucketPeersCR::update_from_source_bucket_policy()
 
   for (siter = pipes->begin(); siter != pipes->end(); ++siter) {
     if (!siter->source.has_bucket_info()) {
-      buckets_info.emplace(siter->source.get_bucket(), RGWBucketInfo());
+      buckets_info.emplace(siter->source.get_bucket(), all_bucket_info());
     }
     if (!siter->target.has_bucket_info()) {
-      buckets_info.emplace(siter->target.get_bucket(), RGWBucketInfo());
+      buckets_info.emplace(siter->target.get_bucket(), all_bucket_info());
     }
   }
 }
@@ -4228,7 +4443,15 @@ int RGWGetBucketPeersCR::operate()
         return set_cr_error(retcode);
       }
 
-      source_bucket_info = source_policy->policy_handler->get_bucket_info();
+      if (source_policy->policy_handler) {
+        auto& opt_bucket_info = source_policy->policy_handler->get_bucket_info();
+        auto& opt_attrs = source_policy->policy_handler->get_bucket_attrs();
+        if (opt_bucket_info && opt_attrs) {
+          source_bucket_info.emplace();
+          source_bucket_info->bucket_info = *opt_bucket_info;
+          source_bucket_info->attrs = *opt_attrs;
+        }
+      }
 
       if (!target_bucket) {
         get_hint_targets_action = make_shared<GetHintTargets>(sync_env, *source_bucket);
@@ -4267,8 +4490,11 @@ int RGWGetBucketPeersCR::operate()
     update_from_source_bucket_policy();
 
     for (siiter = buckets_info.begin(); siiter != buckets_info.end(); ++siiter) {
-      if (siiter->second.bucket.name.empty()) {
-        yield call(new RGWSyncGetBucketInfoCR(sync_env, siiter->first, &siiter->second, tn));
+      if (siiter->second.bucket_info.bucket.name.empty()) {
+        yield call(new RGWSyncGetBucketInfoCR(sync_env, siiter->first,
+                                              &siiter->second.bucket_info,
+                                              &siiter->second.attrs,
+                                              tn));
       }
     }
 
@@ -4326,7 +4552,8 @@ int RGWRunBucketSyncCoroutine::operate()
 
     tn->log(20, SSTR("sync status for source bucket: " << sync_status.state));
 
-    yield call(new RGWSyncGetBucketInfoCR(sync_env, sync_pair.source_bs.bucket, &sync_pipe.source_bucket_info, tn));
+    yield call(new RGWSyncGetBucketInfoCR(sync_env, sync_pair.source_bs.bucket, &sync_pipe.source_bucket_info,
+                                          &sync_pipe.source_bucket_attrs, tn));
     if (retcode < 0) {
       tn->log(0, SSTR("ERROR: failed to retrieve bucket info for bucket=" << bucket_str{sync_pair.source_bs.bucket}));
       lease_cr->go_down();
@@ -4334,7 +4561,8 @@ int RGWRunBucketSyncCoroutine::operate()
       return set_cr_error(retcode);
     }
 
-    yield call(new RGWSyncGetBucketInfoCR(sync_env, sync_pair.dest_bs.bucket, &sync_pipe.dest_bucket_info, tn));
+    yield call(new RGWSyncGetBucketInfoCR(sync_env, sync_pair.dest_bs.bucket, &sync_pipe.dest_bucket_info, 
+                                          &sync_pipe.dest_bucket_attrs, tn));
     if (retcode < 0) {
       tn->log(0, SSTR("ERROR: failed to retrieve bucket info for bucket=" << bucket_str{sync_pair.source_bs.bucket}));
       lease_cr->go_down();
index 6a9c9a4d8afd5a302104ea698e0a85c9a2ec6f53..a8ea0e083d120d2dbb42841308ff6c1e6e3bd163 100644 (file)
@@ -43,7 +43,9 @@ inline ostream& operator<<(ostream& out, const rgw_bucket_sync_pair_info& p) {
 struct rgw_bucket_sync_pipe {
   rgw_bucket_sync_pair_info info;
   RGWBucketInfo source_bucket_info;
+  map<string, bufferlist> source_bucket_attrs;
   RGWBucketInfo dest_bucket_info;
+  map<string, bufferlist> dest_bucket_attrs;
 
   RGWBucketSyncFlowManager::pipe_rules_ref& get_rules() {
     return info.handler.rules;
index aa075949ffeb23e33fc87fc3f6432c3246ac2021..ac1ca25df5d972a85fcba444bd8ba94ded9d932a 100644 (file)
@@ -468,7 +468,7 @@ int BucketTrimInstanceCR::operate()
       }
       // in parallel, read the local bucket instance info
       spawn(new RGWGetBucketInstanceInfoCR(store->svc()->rados->get_async_processor(), store,
-                                           bucket, &bucket_info),
+                                           bucket, &bucket_info, nullptr),
             false);
     }
     // wait for a response from each peer. all must respond to attempt trim
index da3c9874f24afce2af1cef8c69debbceded49d62..005f09170a28d1fd8f61deb0b0adbd0e979bae5b 100644 (file)
@@ -180,12 +180,13 @@ int RGWSI_Bucket_Sync_SObj::do_get_policy_handler(RGWSI_Bucket_X_Ctx& ctx,
   rgw_cache_entry_info cache_info;
 
   RGWBucketInfo bucket_info;
+  map<string, bufferlist> attrs;
 
   int r = svc.bucket_sobj->read_bucket_instance_info(ctx.bi,
                                                      bucket_key,
                                                      &bucket_info,
                                                      nullptr,
-                                                     nullptr,
+                                                     &attrs,
                                                      y,
                                                      &cache_info);
   if (r < 0) {
@@ -201,7 +202,7 @@ int RGWSI_Bucket_Sync_SObj::do_get_policy_handler(RGWSI_Bucket_X_Ctx& ctx,
     return -ENOENT;
   }
 
-  e.handler.reset(zone_policy_handler->alloc_child(bucket_info));
+  e.handler.reset(zone_policy_handler->alloc_child(bucket_info, std::move(attrs)));
 
   r = e.handler->init(y);
   if (r < 0) {