int RGWCopyObj::verify_permission()
{
  RGWAccessControlPolicy src_acl(s->cct);
  boost::optional<Policy> src_policy;
  op_ret = get_params();
  if (op_ret < 0)
    return op_ret;

  op_ret = get_system_versioning_params(s, &olh_epoch, &version_id);
  if (op_ret < 0) {
    return op_ret;
  }
  map<string, bufferlist> src_attrs;

  RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);

  if (s->bucket_instance_id.empty()) {
    op_ret = store->get_bucket_info(obj_ctx, src_tenant_name, src_bucket_name, src_bucket_info, NULL, &src_attrs);
  } else {
    /* will only happen in intra region sync where the source and dest bucket is the same */
    op_ret = store->get_bucket_instance_info(obj_ctx, s->bucket_instance_id, src_bucket_info, NULL, &src_attrs);
  }
  if (op_ret < 0) {
    if (op_ret == -ENOENT) {
      op_ret = -ERR_NO_SUCH_BUCKET;
    }
    return op_ret;
  }

  src_bucket = src_bucket_info.bucket;

  /* get buckets info (source and dest) */
  if (s->local_source &&  source_zone.empty()) {
    rgw_obj src_obj(src_bucket, src_object);
    store->set_atomic(s->obj_ctx, src_obj);
    store->set_prefetch_data(s->obj_ctx, src_obj);

    /* check source object permissions */
    op_ret = read_obj_policy(store, s, src_bucket_info, src_attrs, &src_acl,
			     src_policy, src_bucket, src_object);
    if (op_ret < 0) {
      return op_ret;
    }

    /* admin request overrides permission checks */
    if (!s->auth.identity->is_admin_of(src_acl.get_owner().get_id())) {
      if (src_policy) {
	auto e = src_policy->eval(s->env, *s->auth.identity,
				  src_object.instance.empty() ?
				  rgw::IAM::s3GetObject :
				  rgw::IAM::s3GetObjectVersion,
				  ARN(src_obj));
	if (e == Effect::Deny) {
	  return -EACCES;
	} else if (e == Effect::Pass &&
		   !src_acl.verify_permission(*s->auth.identity, s->perm_mask,
					      RGW_PERM_READ)) { 
	  return -EACCES;
	}
      } else if (!src_acl.verify_permission(*s->auth.identity,
					       s->perm_mask,
					    RGW_PERM_READ)) {
	return -EACCES;
      }
    }
  }

  RGWAccessControlPolicy dest_bucket_policy(s->cct);
  map<string, bufferlist> dest_attrs;

  if (src_bucket_name.compare(dest_bucket_name) == 0) { /* will only happen if s->local_source
                                                           or intra region sync */
    dest_bucket_info = src_bucket_info;
    dest_attrs = src_attrs;
  } else {
    op_ret = store->get_bucket_info(obj_ctx, dest_tenant_name, dest_bucket_name,
                                    dest_bucket_info, nullptr, &dest_attrs);
    if (op_ret < 0) {
      if (op_ret == -ENOENT) {
        op_ret = -ERR_NO_SUCH_BUCKET;
      }
      return op_ret;
    }
  }

  dest_bucket = dest_bucket_info.bucket;

  rgw_obj dest_obj(dest_bucket, dest_object);
  store->set_atomic(s->obj_ctx, dest_obj);

  /* check dest bucket permissions */
  op_ret = read_bucket_policy(store, s, dest_bucket_info, dest_attrs,
                              &dest_bucket_policy, dest_bucket);
  if (op_ret < 0) {
    return op_ret;
  }
  auto dest_iam_policy = get_iam_policy_from_attr(s->cct, store, dest_attrs, dest_bucket.tenant);
  /* admin request overrides permission checks */
  if (! s->auth.identity->is_admin_of(dest_policy.get_owner().get_id())){
    if (dest_iam_policy != boost::none) {
      rgw_add_to_iam_environment(s->env, "s3:x-amz-copy-source", copy_source);
      rgw_add_to_iam_environment(s->env, "s3:x-amz-metadata-directive", md_directive);

      auto e = dest_iam_policy->eval(s->env, *s->auth.identity,
                                     rgw::IAM::s3PutObject,
                                     ARN(dest_obj));
      if (e == Effect::Deny) {
        return -EACCES;
      } else if (e == Effect::Pass &&
                 ! dest_bucket_policy.verify_permission(*s->auth.identity,
                                                        s->perm_mask,
                                                        RGW_PERM_WRITE)){
        return -EACCES;
      }
    }
  } else if (! dest_bucket_policy.verify_permission(*s->auth.identity, s->perm_mask,
                                                    RGW_PERM_WRITE)) {
    return -EACCES;
  }

  op_ret = init_dest_policy();
  if (op_ret < 0) {
    return op_ret;
  }

  return 0;
}