__u8 crush_rule);
int rados_pool_delete(rados_t cluster, const char *pool_name);
int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid);
+int rados_ioctx_pool_get_auid(rados_ioctx_t io, uint64_t *auid);
void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key);
int rados_ioctx_get_id(rados_ioctx_t io);
// set pool auid
int set_auid(uint64_t auid_);
+ // get pool auid
+ int get_auid(uint64_t *auid_);
+
// create an object
int create(const std::string& oid, bool exclusive);
int pool_create(string& name, unsigned long long auid=0, __u8 crush_rule=0);
int pool_delete(const char *name);
int pool_change_auid(rados_ioctx_t io, unsigned long long auid);
+ int pool_get_auid(rados_ioctx_t io, unsigned long long *auid);
int list(Objecter::ListContext *context, int max_entries);
return reply;
}
+int librados::RadosClient::
+pool_get_auid(rados_ioctx_t io, unsigned long long *auid)
+{
+ Mutex::Locker l(lock);
+ int pool_id = ((IoCtxImpl *)io)->poolid;
+ const pg_pool_t *pg = osdmap.get_pg_pool(pool_id);
+ if (!pg)
+ return -ENOENT;
+ *auid = pg->v.auid;
+ return 0;
+}
+
int librados::RadosClient::
snap_list(IoCtxImpl *io, vector<uint64_t> *snaps)
{
return io_ctx_impl->client->pool_change_auid(io_ctx_impl, auid_);
}
+int librados::IoCtx::
+get_auid(uint64_t *auid_)
+{
+ return io_ctx_impl->client->pool_get_auid(io_ctx_impl, (unsigned long long *)auid_);
+}
+
int librados::IoCtx::
create(const std::string& oid, bool exclusive)
{
return ctx->client->pool_change_auid(ctx, auid);
}
+extern "C" int rados_ioctx_pool_get_auid(rados_ioctx_t io, uint64_t *auid)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ return ctx->client->pool_get_auid(ctx, (unsigned long long *)auid);
+}
+
extern "C" void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key)
{
librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
*/
virtual int delete_bucket(std::string& id, std::string& bucket) = 0;
+ virtual int disable_bucket(std::string& bucket) { return -ENOTSUP; }
+ virtual int enable_bucket(std::string& bucket, uint64_t auid) { return -ENOTSUP; }
+ virtual int bucket_suspended(std::string& bucket, bool *suspended) {
+ *suspended = false;
+ return 0;
+ }
+
/**
* Delete an object.
* id: unused in current implementations
cerr << " user modify modify user\n";
cerr << " user info get user info\n";
cerr << " user rm remove user\n";
+ cerr << " user suspend suspend a user\n";
+ cerr << " user enable reenable user after suspension\n";
cerr << " subuser create create a new subuser\n" ;
cerr << " subuser modify modify subuser\n";
cerr << " subuser rm remove subuser\n";
OPT_USER_INFO,
OPT_USER_MODIFY,
OPT_USER_RM,
+ OPT_USER_SUSPEND,
+ OPT_USER_ENABLE,
OPT_SUBUSER_CREATE,
OPT_SUBUSER_MODIFY,
OPT_SUBUSER_RM,
return OPT_USER_MODIFY;
if (strcmp(cmd, "rm") == 0)
return OPT_USER_RM;
+ if (strcmp(cmd, "suspend") == 0)
+ return OPT_USER_SUSPEND;
+ if (strcmp(cmd, "enable") == 0)
+ return OPT_USER_ENABLE;
} else if (strcmp(prev_cmd, "subuser") == 0) {
if (strcmp(cmd, "create") == 0)
return OPT_SUBUSER_CREATE;
cerr << "ERROR: this should be fixed manually!" << std::endl;
}
+
int main(int argc, char **argv)
{
DEFINE_CONF_VARS(usage);
if (user_modify_op || opt_cmd == OPT_USER_CREATE ||
- opt_cmd == OPT_USER_INFO || opt_cmd == OPT_BUCKET_UNLINK || opt_cmd == OPT_BUCKET_LINK) {
+ opt_cmd == OPT_USER_INFO || opt_cmd == OPT_BUCKET_UNLINK || opt_cmd == OPT_BUCKET_LINK ||
+ opt_cmd == OPT_USER_SUSPEND || opt_cmd == OPT_USER_ENABLE) {
if (!user_id) {
cerr << "user_id was not specified, aborting" << std::endl;
usage();
}
}
+ if (opt_cmd == OPT_USER_SUSPEND || opt_cmd == OPT_USER_ENABLE) {
+ string id;
+ __u8 disable = (opt_cmd == OPT_USER_SUSPEND ? 1 : 0);
+
+ if (!user_id) {
+ cerr << "uid was not specified" << std::endl;
+ usage();
+ }
+ RGWUserBuckets buckets;
+ if (rgw_read_user_buckets(user_id, buckets, false) < 0) {
+ cout << "could not get buckets for uid " << user_id << std::endl;
+ }
+ map<string, RGWBucketEnt>& m = buckets.get_buckets();
+ map<string, RGWBucketEnt>::iterator iter;
+
+ int ret;
+ info.suspended = disable;
+ ret = rgw_store_user_info(info);
+ if (ret < 0) {
+ cerr << "ERROR: failed to store user info user=" << user_id << " ret=" << ret << std::endl;
+ exit(1);
+ }
+
+ if (disable)
+ RGW_LOG(0) << "disabling user buckets" << dendl;
+ else
+ RGW_LOG(0) << "enabling user buckets" << dendl;
+
+ bool fail = false;
+
+ for (iter = m.begin(); iter != m.end(); ++iter) {
+ RGWBucketEnt obj = iter->second;
+ if (disable)
+ ret = rgwstore->disable_bucket(obj.name);
+ else
+ ret = rgwstore->enable_bucket(obj.name, info.auid);
+ if (ret < 0) {
+ cerr << "ERROR: could not disable bucket " << obj.name << " ret=" << ret << std::endl;
+ fail = true;
+ }
+ }
+ if (fail)
+ return 1;
+ }
+
return 0;
}
#define RGW_BUCKETS_OBJ_PREFIX ".buckets"
-#define USER_INFO_VER 6
+#define USER_INFO_VER 7
#define RGW_MAX_CHUNK_SIZE (4*1024*1024)
#define RGW_REST_OPENSTACK 0x1
#define RGW_REST_OPENSTACK_AUTH 0x2
+#define RGW_SUSPENDED_USER_AUID -2
+
#define CGI_PRINTF(state, format, ...) do { \
int __ret = FCGX_FPrintF(state->fcgx->out, format, __VA_ARGS__); \
if (state->header_ended) \
#define ERR_INVALID_PART_ORDER 2008
#define ERR_NO_SUCH_UPLOAD 2009
+#define ERR_USER_SUSPENDED 2100
+
typedef void *RGWAccessHandle;
/* size should be the required string size + 1 */
string openstack_key;
map<string, RGWAccessKey> access_keys;
map<string, RGWSubUser> subusers;
+ __u8 suspended;
RGWUserInfo() : auid(0) {}
::encode(user_id, bl);
::encode(access_keys, bl);
::encode(subusers, bl);
+ ::encode(suspended, bl);
}
void decode(bufferlist::iterator& bl) {
__u32 ver;
::decode(access_keys, bl);
::decode(subusers, bl);
}
+ suspended = 0;
+ if (ver >= 7) {
+ ::decode(suspended, bl);
+ }
}
void clear() {
user_email.clear();
auid = CEPH_AUTH_UID_DEFAULT;
access_keys.clear();
+ suspended = 0;
}
};
WRITE_CLASS_ENCODER(RGWUserInfo)
abort_early(&s, -EPERM);
goto done;
}
+ if (s.user.suspended) {
+ RGW_LOG(10) << "user is suspended, uid=" << s.user.user_id << dendl;
+ abort_early(&s, -ERR_USER_SUSPENDED);
+ goto done;
+ }
ret = handler->read_permissions();
if (ret < 0) {
abort_early(&s, ret);
string oid = object;
rgw_obj obj;
+ if (!oid.empty()) {
+ bool suspended;
+ int ret = rgwstore->bucket_suspended(bucket, &suspended);
+ if (ret < 0)
+ return ret;
+ if (suspended)
+ return -ERR_USER_SUSPENDED;
+ }
+
if (!oid.empty() && !upload_id.empty()) {
RGWMPObj mp(oid, upload_id);
oid = mp.get_meta();
return 0;
}
+int RGWRados::disable_bucket(std::string& bucket)
+{
+ librados::IoCtx ctx;
+ int r = open_bucket_ctx(bucket, ctx);
+ if (r < 0)
+ return r;
+
+ ctx.set_auid(RGW_SUSPENDED_USER_AUID);
+
+ return 0;
+}
+
+int RGWRados::enable_bucket(std::string& bucket, uint64_t auid)
+{
+ librados::IoCtx ctx;
+ int r = open_bucket_ctx(bucket, ctx);
+ if (r < 0)
+ return r;
+
+ ctx.set_auid(auid);
+ return 0;
+}
+
+int RGWRados::bucket_suspended(std::string& bucket, bool *suspended)
+{
+ librados::IoCtx ctx;
+ int r = open_bucket_ctx(bucket, ctx);
+ if (r < 0)
+ return r;
+
+ uint64_t auid;
+ int ret = ctx.get_auid(&auid);
+ if (ret < 0)
+ return ret;
+
+ *suspended = (auid == RGW_SUSPENDED_USER_AUID);
+ return 0;
+}
/**
* Delete an object.
* id: unused
/** delete a bucket*/
virtual int delete_bucket(std::string& id, std::string& bucket);
+ virtual int disable_bucket(std::string& bucket);
+ virtual int enable_bucket(std::string& bucket, uint64_t auid);
+ virtual int bucket_suspended(std::string& bucket, bool *suspended);
+
/** Delete an object.*/
virtual int delete_obj(std::string& id, rgw_obj& src_obj);
{ ERR_INVALID_PART_ORDER, 400, "InvalidPartOrder" },
{ EACCES, 403, "AccessDenied" },
{ EPERM, 403, "AccessDenied" },
+ { ERR_USER_SUSPENDED, 403, "UserSuspended" },
{ ENOENT, 404, "NoSuchKey" },
{ ERR_NO_SUCH_BUCKET, 404, "NoSuchBucket" },
{ ERR_NO_SUCH_UPLOAD, 404, "NoSuchUpload" },