From 9974b7e58a0cdbd915f3a1a85de9a7eadb3d3ae1 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Thu, 16 Jun 2011 16:53:38 -0700 Subject: [PATCH] rgw: user suspension --- src/include/rados/librados.h | 1 + src/include/rados/librados.hpp | 3 ++ src/librados.cc | 25 +++++++++++++++ src/rgw/rgw_access.h | 7 +++++ src/rgw/rgw_admin.cc | 57 +++++++++++++++++++++++++++++++++- src/rgw/rgw_common.h | 13 +++++++- src/rgw/rgw_main.cc | 5 +++ src/rgw/rgw_op.cc | 9 ++++++ src/rgw/rgw_rados.cc | 38 +++++++++++++++++++++++ src/rgw/rgw_rados.h | 4 +++ src/rgw/rgw_rest.cc | 1 + 11 files changed, 161 insertions(+), 2 deletions(-) diff --git a/src/include/rados/librados.h b/src/include/rados/librados.h index efc661831c372..ae735bb2e96da 100644 --- a/src/include/rados/librados.h +++ b/src/include/rados/librados.h @@ -112,6 +112,7 @@ int rados_pool_create_with_all(rados_t cluster, const char *pool_name, uint64_t __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); diff --git a/src/include/rados/librados.hpp b/src/include/rados/librados.hpp index 4bcf96b6b9a64..fd7ec6468d7cf 100644 --- a/src/include/rados/librados.hpp +++ b/src/include/rados/librados.hpp @@ -150,6 +150,9 @@ namespace librados // 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); diff --git a/src/librados.cc b/src/librados.cc index 3c51689eb1497..85b9e91ef2afc 100644 --- a/src/librados.cc +++ b/src/librados.cc @@ -474,6 +474,7 @@ public: 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); @@ -1122,6 +1123,18 @@ pool_change_auid(rados_ioctx_t io, unsigned long long auid) 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 *snaps) { @@ -2395,6 +2408,12 @@ set_auid(uint64_t auid_) 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) { @@ -3269,6 +3288,12 @@ extern "C" int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid) 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; diff --git a/src/rgw/rgw_access.h b/src/rgw/rgw_access.h index b423052a40d70..d6838c9595986 100644 --- a/src/rgw/rgw_access.h +++ b/src/rgw/rgw_access.h @@ -96,6 +96,13 @@ public: */ 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 diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 42af27b607186..3fc07a6277a47 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -34,6 +34,8 @@ void usage() 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"; @@ -77,6 +79,8 @@ enum { OPT_USER_INFO, OPT_USER_MODIFY, OPT_USER_RM, + OPT_USER_SUSPEND, + OPT_USER_ENABLE, OPT_SUBUSER_CREATE, OPT_SUBUSER_MODIFY, OPT_SUBUSER_RM, @@ -177,6 +181,10 @@ static int get_cmd(const char *cmd, const char *prev_cmd, bool *need_more) 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; @@ -331,6 +339,7 @@ static void remove_old_indexes(RGWUserInfo& old_info, RGWUserInfo new_info) cerr << "ERROR: this should be fixed manually!" << std::endl; } + int main(int argc, char **argv) { DEFINE_CONF_VARS(usage); @@ -506,7 +515,8 @@ int main(int argc, char **argv) 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(); @@ -901,5 +911,50 @@ int main(int argc, char **argv) } } + 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& m = buckets.get_buckets(); + map::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; } diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index c5c0b895b924e..d9a9d2b035cb4 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -44,7 +44,7 @@ extern string rgw_root_bucket; #define RGW_BUCKETS_OBJ_PREFIX ".buckets" -#define USER_INFO_VER 6 +#define USER_INFO_VER 7 #define RGW_MAX_CHUNK_SIZE (4*1024*1024) @@ -57,6 +57,8 @@ extern string rgw_root_bucket; #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) \ @@ -86,6 +88,8 @@ extern string rgw_root_bucket; #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 */ @@ -221,6 +225,7 @@ struct RGWUserInfo string openstack_key; map access_keys; map subusers; + __u8 suspended; RGWUserInfo() : auid(0) {} @@ -245,6 +250,7 @@ struct RGWUserInfo ::encode(user_id, bl); ::encode(access_keys, bl); ::encode(subusers, bl); + ::encode(suspended, bl); } void decode(bufferlist::iterator& bl) { __u32 ver; @@ -273,6 +279,10 @@ struct RGWUserInfo ::decode(access_keys, bl); ::decode(subusers, bl); } + suspended = 0; + if (ver >= 7) { + ::decode(suspended, bl); + } } void clear() { @@ -281,6 +291,7 @@ struct RGWUserInfo user_email.clear(); auid = CEPH_AUTH_UID_DEFAULT; access_keys.clear(); + suspended = 0; } }; WRITE_CLASS_ENCODER(RGWUserInfo) diff --git a/src/rgw/rgw_main.cc b/src/rgw/rgw_main.cc index 559016b7eb13d..f80997921bc03 100644 --- a/src/rgw/rgw_main.cc +++ b/src/rgw/rgw_main.cc @@ -102,6 +102,11 @@ int main(int argc, const char **argv) 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); diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 4b6329ebd90d8..40d648924aa39 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -138,6 +138,15 @@ int read_acls(struct req_state *s, RGWAccessControlPolicy *policy, string& bucke 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(); diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index d8fd41272b480..3fe68e367fc59 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -486,6 +486,44 @@ int RGWRados::delete_bucket(std::string& id, std::string& bucket) 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 diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index 07070d7a91a6e..89f6a4937379c 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -61,6 +61,10 @@ public: /** 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); diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index 99926dc7c8f30..0288dac001a69 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -48,6 +48,7 @@ const static struct rgw_html_errors RGW_HTML_ERRORS[] = { { 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" }, -- 2.39.5