rgw/rgw_usage.cc \
rgw/rgw_json_enc.cc \
rgw/rgw_user.cc \
- rgw/rgw_tools.cc \
+ rgw/rgw_bucket.cc\
+ rgw/rgw_tools.cc \
rgw/rgw_rados.cc \
rgw/rgw_op.cc \
rgw/rgw_common.cc \
rgw/rgw_rest_swift.cc \
rgw/rgw_rest_s3.cc \
rgw/rgw_rest_usage.cc \
+ rgw/rgw_rest_user.cc \
+ rgw/rgw_rest_bucket.cc \
rgw/rgw_http_client.cc \
rgw/rgw_swift.cc \
rgw/rgw_swift_auth.cc \
rgw/rgw_rest_s3.h\
rgw/rgw_rest_admin.h\
rgw/rgw_rest_usage.h\
- rgw/rgw_tools.h\
+ rgw/rgw_rest_user.h\
+ rgw/rgw_rest_bucket.h\
+ rgw/rgw_tools.h\
rgw/rgw_usage.h\
rgw/rgw_user.h\
- sample.ceph.conf\
+ rgw/rgw_bucket.h\
+ sample.ceph.conf\
tools/common.h\
test/osd/RadosModel.h\
test/osd/Object.h\
#include "common/armor.h"
#include "rgw_user.h"
+#include "rgw_bucket.h"
#include "rgw_rados.h"
#include "rgw_acl.h"
#include "rgw_acl_s3.h"
OPT_CAPS_RM,
};
-static uint32_t str_to_perm(const char *str)
-{
- if (strcasecmp(str, "read") == 0)
- return RGW_PERM_READ;
- else if (strcasecmp(str, "write") == 0)
- return RGW_PERM_WRITE;
- else if (strcasecmp(str, "readwrite") == 0)
- return RGW_PERM_READ | RGW_PERM_WRITE;
- else if (strcasecmp(str, "full") == 0)
- return RGW_PERM_FULL_CONTROL;
-
- usage_exit();
- return 0; // unreachable
-}
-
static int get_cmd(const char *cmd, const char *prev_cmd, bool *need_more)
{
*need_more = false;
encode_json("user_info", info, formatter);
formatter->flush(cout);
cout << std::endl;
-
-}
-
-static int create_bucket(string bucket_str, string& user_id, string& display_name)
-{
- RGWAccessControlPolicy policy, old_policy;
- map<string, bufferlist> attrs;
- bufferlist aclbl;
- string no_oid;
- rgw_obj obj;
- RGWBucketInfo bucket_info;
-
- int ret;
-
- // defaule policy (private)
- policy.create_default(user_id, display_name);
- policy.encode(aclbl);
-
- ret = store->get_bucket_info(NULL, bucket_str, bucket_info);
- if (ret < 0)
- return ret;
-
- rgw_bucket& bucket = bucket_info.bucket;
-
- ret = store->create_bucket(user_id, bucket, attrs);
- if (ret && ret != -EEXIST)
- goto done;
-
- obj.init(bucket, no_oid);
-
- ret = store->set_attr(NULL, obj, RGW_ATTR_ACL, aclbl);
- if (ret < 0) {
- cerr << "couldn't set acl on bucket" << std::endl;
- }
-
- ret = rgw_add_bucket(store, user_id, bucket);
-
- dout(20) << "ret=" << ret << dendl;
-
- if (ret == -EEXIST)
- ret = 0;
-done:
- return ret;
-}
-
-static void remove_old_indexes(RGWUserInfo& old_info, RGWUserInfo& new_info)
-{
- int ret;
- bool success = true;
-
- if (!old_info.user_id.empty() && old_info.user_id.compare(new_info.user_id) != 0) {
- ret = rgw_remove_uid_index(store, old_info.user_id);
- if (ret < 0 && ret != -ENOENT) {
- cerr << "ERROR: could not remove index for uid " << old_info.user_id << " return code: " << ret << std::endl;
- success = false;
- }
- }
-
- if (!old_info.user_email.empty() &&
- old_info.user_email.compare(new_info.user_email) != 0) {
- ret = rgw_remove_email_index(store, old_info.user_email);
- if (ret < 0 && ret != -ENOENT) {
- cerr << "ERROR: could not remove index for email " << old_info.user_email << " return code: " << ret << std::endl;
- success = false;
- }
- }
-
- map<string, RGWAccessKey>::iterator old_iter;
- for (old_iter = old_info.swift_keys.begin(); old_iter != old_info.swift_keys.end(); ++old_iter) {
- RGWAccessKey& swift_key = old_iter->second;
- map<string, RGWAccessKey>::iterator new_iter = new_info.swift_keys.find(swift_key.id);
- if (new_iter == new_info.swift_keys.end()) {
- ret = rgw_remove_swift_name_index(store, swift_key.id);
- if (ret < 0 && ret != -ENOENT) {
- cerr << "ERROR: could not remove index for swift_name " << swift_key.id << " return code: " << ret << std::endl;
- success = false;
- }
- }
- }
-
- /* we're not removing access keys here.. keys are removed explicitly using the key rm command and removing the old key
- index is handled there */
-
- if (!success)
- cerr << "ERROR: this should be fixed manually!" << std::endl;
-}
-
-static bool char_is_unreserved_url(char c)
-{
- if (isalnum(c))
- return true;
-
- switch (c) {
- case '-':
- case '.':
- case '_':
- case '~':
- return true;
- default:
- return false;
- }
}
-static bool validate_access_key(string& key)
-{
- const char *p = key.c_str();
- while (*p) {
- if (!char_is_unreserved_url(*p))
- return false;
- p++;
- }
- return true;
-}
static void dump_bucket_usage(map<RGWObjCategory, RGWBucketStats>& stats, Formatter *formatter)
{
return 0;
}
-enum ObjectKeyType {
- KEY_TYPE_SWIFT,
- KEY_TYPE_S3,
-};
-
-static void check_bad_index_multipart(RGWRados *store, rgw_bucket& bucket, bool fix)
-{
- int max = 1000;
- string prefix;
- string marker;
- string delim;
-
- map<string, bool> common_prefixes;
- string ns = "multipart";
-
- bool is_truncated;
- list<string> objs_to_unlink;
- map<string, bool> meta_objs;
- map<string, string> all_objs;
-
- do {
- vector<RGWObjEnt> result;
- int r = store->list_objects(bucket, max, prefix, delim, marker,
- result, common_prefixes, false, ns,
- &is_truncated, NULL);
-
- if (r < 0) {
- cerr << "failed to list objects in bucket=" << bucket << " err=" << cpp_strerror(-r) << std::endl;
- return;
- }
-
- vector<RGWObjEnt>::iterator iter;
- for (iter = result.begin(); iter != result.end(); ++iter) {
- RGWObjEnt& ent = *iter;
-
- rgw_obj obj(bucket, ent.name);
- obj.set_ns(ns);
-
- string& oid = obj.object;
- marker = oid;
-
- int pos = oid.find_last_of('.');
- if (pos < 0)
- continue;
-
- string name = oid.substr(0, pos);
- string suffix = oid.substr(pos + 1);
-
- if (suffix.compare("meta") == 0) {
- meta_objs[name] = true;
- } else {
- all_objs[oid] = name;
- }
- }
-
- } while (is_truncated);
-
- map<string, string>::iterator aiter;
- for (aiter = all_objs.begin(); aiter != all_objs.end(); ++aiter) {
- string& name = aiter->second;
-
- if (meta_objs.find(name) == meta_objs.end()) {
- objs_to_unlink.push_back(aiter->first);
- }
- }
-
- if (objs_to_unlink.empty())
- return;
-
- if (!fix) {
- cout << "Need to unlink the following objects from bucket=" << bucket << std::endl;
- } else {
- cout << "Unlinking the following objects from bucket=" << bucket << std::endl;
- }
- for (list<string>::iterator oiter = objs_to_unlink.begin(); oiter != objs_to_unlink.end(); ++oiter) {
- cout << *oiter << std::endl;
- }
-
- if (fix) {
- int r = store->remove_objs_from_index(bucket, objs_to_unlink);
- if (r < 0) {
- cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-r) << std::endl;
- }
+class StoreDestructor {
+ RGWRados *store;
+public:
+ StoreDestructor(RGWRados *_s) : store(_s) {}
+ ~StoreDestructor() {
+ RGWStoreManager::close_storage(store);
}
-}
+};
-static void check_bad_user_bucket_mapping(RGWRados *store, const string& user_id, bool fix)
+static int init_bucket(string& bucket_name, rgw_bucket& bucket)
{
- RGWUserBuckets user_buckets;
- int ret = rgw_read_user_buckets(store, user_id, user_buckets, false);
- if (ret < 0) {
- cerr << "failed to read user buckets: " << cpp_strerror(-ret) << std::endl;
- return;
- }
-
- map<string, RGWBucketEnt>& buckets = user_buckets.get_buckets();
- for (map<string, RGWBucketEnt>::iterator i = buckets.begin();
- i != buckets.end();
- ++i) {
- RGWBucketEnt& bucket_ent = i->second;
- rgw_bucket& bucket = bucket_ent.bucket;
-
+ if (!bucket_name.empty()) {
RGWBucketInfo bucket_info;
- int r = store->get_bucket_info(NULL, bucket.name, bucket_info);
+ int r = store->get_bucket_info(NULL, bucket_name, bucket_info);
if (r < 0) {
- cerr << "could not get bucket info for bucket=" << bucket << std::endl;
- continue;
- }
-
- rgw_bucket& actual_bucket = bucket_info.bucket;
-
- if (actual_bucket.name.compare(bucket.name) != 0 ||
- actual_bucket.pool.compare(bucket.pool) != 0 ||
- actual_bucket.marker.compare(bucket.marker) != 0 ||
- actual_bucket.bucket_id.compare(bucket.bucket_id) != 0) {
- cout << "bucket info mismatch: expected " << actual_bucket << " got " << bucket << std::endl;
- if (fix) {
- cout << "fixing" << std::endl;
- r = rgw_add_bucket(store, user_id, actual_bucket);
- if (r < 0) {
- cerr << "failed to fix bucket: " << cpp_strerror(-r) << std::endl;
- }
- }
- }
- }
-}
-
-static int remove_object(RGWRados *store, rgw_bucket& bucket, std::string& object)
-{
- RGWRadosCtx *rctx = new RGWRadosCtx(store);
- rgw_obj obj(bucket,object);
-
- int ret = store->delete_obj(rctx, obj);
-
- return ret;
-}
-
-static int remove_bucket(RGWRados *store, rgw_bucket& bucket, bool delete_children)
-{
- map<RGWObjCategory, RGWBucketStats> stats;
- std::vector<RGWObjEnt> objs;
- std::string prefix, delim, marker, ns;
- map<string, bool> common_prefixes;
- rgw_obj obj;
- RGWBucketInfo info;
- bufferlist bl;
-
- int ret = store->get_bucket_stats(bucket, stats);
-
- if (ret < 0)
- return ret;
-
- obj.bucket = bucket;
- int max = 1000;
-
- ret = rgw_get_obj(store, NULL, store->zone.domain_root, bucket.name, bl, NULL);
-
- bufferlist::iterator iter = bl.begin();
- try {
- ::decode(info, iter);
- } catch (buffer::error& err) {
- cerr << "ERROR: could not decode buffer info, caught buffer::error" << std::endl;
- return -EIO;
- }
-
- if (delete_children) {
- ret = store->list_objects(bucket, max, prefix, delim, marker, objs, common_prefixes,
- false, ns, (bool *)false, NULL);
- if (ret < 0)
- return ret;
-
- while (!objs.empty()) {
- std::vector<RGWObjEnt>::iterator it = objs.begin();
- for (it = objs.begin(); it != objs.end(); ++it) {
- ret = remove_object(store, bucket, (*it).name);
- if (ret < 0)
- return ret;
- }
- objs.clear();
-
- ret = store->list_objects(bucket, max, prefix, delim, marker, objs, common_prefixes,
- false, ns, (bool *)false, NULL);
- if (ret < 0)
- return ret;
+ cerr << "could not get bucket info for bucket=" << bucket_name << std::endl;
+ return r;
}
+ bucket = bucket_info.bucket;
}
-
- ret = store->delete_bucket(bucket);
- if (ret < 0) {
- cerr << "ERROR: could not remove bucket " << bucket.name << std::endl;
-
- return ret;
- }
-
- ret = rgw_remove_user_bucket_info(store, info.owner, bucket);
- if (ret < 0) {
- cerr << "ERROR: unable to remove user bucket information" << std::endl;
- }
-
- return ret;
-}
-
-static bool bucket_object_check_filter(const string& name)
-{
- string ns;
- string obj = name;
- return rgw_obj::translate_raw_obj_to_obj_in_ns(obj, ns);
+ return 0;
}
static int read_input(const string& infile, bufferlist& bl)
}
return 0;
}
-
-class StoreDestructor {
- RGWRados *store;
-public:
- StoreDestructor(RGWRados *_s) : store(_s) {}
- ~StoreDestructor() {
- RGWStoreManager::close_storage(store);
- }
-};
-
int main(int argc, char **argv)
{
vector<const char*> args;
std::string date, subuser, access, format;
std::string start_date, end_date;
std::string key_type_str;
- ObjectKeyType key_type = KEY_TYPE_S3;
+ int key_type = KEY_TYPE_UNDEFINED;
rgw_bucket bucket;
uint32_t perm_mask = 0;
- bool specified_perm_mask = false;
RGWUserInfo info;
int opt_cmd = OPT_NO_CMD;
bool need_more;
- int gen_secret = false;
- int gen_key = false;
- bool implicit_gen_secret = true;
- bool implicit_gen_key = true;
- char secret_key_buf[SECRET_KEY_LEN + 1];
- char public_id_buf[PUBLIC_ID_LEN + 1];
- bool user_modify_op;
+ int gen_access_key = 0;
+ int gen_secret_key = 0;
+ bool set_perm = false;
string bucket_id;
Formatter *formatter = NULL;
int purge_data = false;
map<string, bool> categories;
string caps;
int check_objects = false;
- string infile;
+ std::string infile;
+ RGWUserAdminOpState user_op;
+ RGWBucketAdminOpState bucket_op;
std::string val;
std::ostringstream errs;
cerr << "bad key type: " << key_type_str << std::endl;
return usage();
}
- } else if (ceph_argparse_binary_flag(args, i, &gen_key, NULL, "--gen-access-key", (char*)NULL)) {
- implicit_gen_key = false;
- } else if (ceph_argparse_binary_flag(args, i, &gen_secret, NULL, "--gen-secret", (char*)NULL)) {
- implicit_gen_secret = false;
+ } else if (ceph_argparse_binary_flag(args, i, &gen_access_key, NULL, "--gen-access-key", (char*)NULL)) {
+ // do nothing
+ } else if (ceph_argparse_binary_flag(args, i, &gen_secret_key, NULL, "--gen-secret", (char*)NULL)) {
+ // do nothing
} else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show_log_entries", (char*)NULL)) {
// do nothing
} else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show_log_sum", (char*)NULL)) {
end_date = val;
} else if (ceph_argparse_witharg(args, i, &val, "--access", (char*)NULL)) {
access = val;
- perm_mask = str_to_perm(access.c_str());
- specified_perm_mask = true;
+ perm_mask = rgw_str_to_perm(access.c_str());
+ set_perm = true;
} else if (ceph_argparse_witharg(args, i, &val, "--bucket-id", (char*)NULL)) {
bucket_id = val;
if (bucket_id.empty()) {
} else if (ceph_argparse_binary_flag(args, i, &fix, NULL, "--fix", (char*)NULL)) {
// do nothing
} else if (ceph_argparse_binary_flag(args, i, &check_objects, NULL, "--check-objects", (char*)NULL)) {
- // do nothing
+ // do nothing
} else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
caps = val;
} else if (ceph_argparse_witharg(args, i, &val, "-i", "--infile", (char*)NULL)) {
return usage();
}
- if (!subuser.empty()) {
- char *suser = strdup(subuser.c_str());
- char *p = strchr(suser, ':');
- if (p) {
- *p = '\0';
- if (!user_id.empty()) {
- if (user_id != suser) {
- cerr << "bad subuser " << subuser << " for uid " << user_id << std::endl;
- return 1;
- }
- } else {
- user_id = suser;
- }
- subuser = p + 1;
- }
- free(suser);
- }
-
- if (opt_cmd == OPT_KEY_RM && key_type == KEY_TYPE_S3 && access_key.empty()) {
- cerr << "error: access key was not specified" << std::endl;
- return usage();
- }
-
- user_modify_op = (opt_cmd == OPT_USER_MODIFY || opt_cmd == OPT_SUBUSER_MODIFY ||
- opt_cmd == OPT_SUBUSER_CREATE || opt_cmd == OPT_SUBUSER_RM ||
- opt_cmd == OPT_KEY_CREATE || opt_cmd == OPT_KEY_RM || opt_cmd == OPT_USER_RM ||
- opt_cmd == OPT_CAPS_ADD || opt_cmd == OPT_CAPS_RM);
+ RGWStreamFlusher f(formatter, cout);
store = RGWStoreManager::get_storage(g_ceph_context, false);
if (!store) {
StoreDestructor store_destructor(store);
- if (opt_cmd != OPT_USER_CREATE &&
- opt_cmd != OPT_LOG_SHOW && opt_cmd != OPT_LOG_LIST && opt_cmd != OPT_LOG_RM &&
- user_id.empty()) {
- bool found = false;
- string s;
- if (!found && (!user_email.empty())) {
- s = user_email;
- if (rgw_get_user_info_by_email(store, s, info) >= 0) {
- found = true;
- } else {
- cerr << "could not find user by specified email" << std::endl;
- }
- }
- if (!found && (!access_key.empty())) {
- s = access_key;
- if (rgw_get_user_info_by_access_key(store, s, info) >= 0) {
- found = true;
- } else {
- cerr << "could not find user by specified access key" << std::endl;
- }
- }
- if (found)
- user_id = info.user_id.c_str();
+ /* populate user operation */
+
+ if (!user_id.empty()) {
+ user_op.set_user_id(user_id);
+ bucket_op.set_user_id(user_id);
}
+ if (!display_name.empty())
+ user_op.set_display_name(display_name);
- 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_SUSPEND || opt_cmd == OPT_USER_ENABLE) {
- if (user_id.empty()) {
- cerr << "user_id was not specified, aborting" << std::endl;
- return usage();
- }
+ if (!user_email.empty())
+ user_op.set_user_email(user_email);
- bool found = (rgw_get_user_info_by_uid(store, user_id, info) >= 0);
+ if (!access_key.empty())
+ user_op.set_access_key(access_key);
- if (opt_cmd == OPT_USER_CREATE) {
- if (found) {
- if (info.display_name.compare(display_name) != 0 ||
- info.user_email.compare(user_email) != 0) {
- cerr << "error: user already exists with different display_name/email" << std::endl;
- return 1;
- }
- /* turn into OPT_USER_MODIFY */
- opt_cmd = OPT_USER_MODIFY;
- user_modify_op = true;
- }
- } else if (!found) {
- cerr << "error reading user info, aborting" << std::endl;
- return 1;
- }
- }
+ if (!secret_key.empty())
+ user_op.set_secret_key(secret_key);
- bool subuser_found = false;
+ if (!subuser.empty())
+ user_op.set_subuser(subuser);
- if (!subuser.empty()) {
- map<string, RGWSubUser>::iterator iter = info.subusers.find(subuser);
- subuser_found = (iter != info.subusers.end());
+ if (!caps.empty())
+ user_op.set_caps(caps);
- if (!subuser_found && opt_cmd != OPT_SUBUSER_CREATE && opt_cmd != OPT_USER_CREATE) {
- cerr << "subuser specified but was not found, aborting" << std::endl;
- return 1;
- }
- }
+ user_op.set_purge_data(purge_data);
- if (opt_cmd == OPT_SUBUSER_CREATE || opt_cmd == OPT_SUBUSER_MODIFY ||
- opt_cmd == OPT_SUBUSER_RM) {
- if (subuser.empty()) {
- cerr << "subuser creation was requires specifying subuser name" << std::endl;
- return 1;
- }
- if (opt_cmd == OPT_SUBUSER_CREATE) {
- if (subuser_found) {
- cerr << "error: subuser already exists" << std::endl;
- return 1;
- }
- if (!key_type_str.empty() && key_type == KEY_TYPE_S3) {
- cerr << "error: subusers may not be created with an S3 key, aborting" << std::endl;
- return 1;
- }
- } else if (!subuser_found) {
- cerr << "error: subuser doesn't exist" << std::endl;
- return 1;
- }
- }
+ if (purge_keys)
+ user_op.set_purge_keys();
- bool keys_not_requested = (access_key.empty() && secret_key.empty() && !gen_secret && !gen_key &&
- opt_cmd != OPT_KEY_CREATE);
+ if (gen_access_key)
+ user_op.set_gen_access();
- if (opt_cmd == OPT_USER_CREATE || (user_modify_op && !keys_not_requested)) {
- int ret;
+ if (gen_secret_key)
+ user_op.set_gen_secret();
- if (opt_cmd == OPT_USER_CREATE && display_name.empty()) {
- cerr << "display name was not specified, aborting" << std::endl;
- return 0;
- }
+ if (max_buckets >= 0)
+ user_op.set_max_buckets(max_buckets);
- if ((secret_key.empty() && implicit_gen_secret) || gen_secret) {
- ret = gen_rand_base64(g_ceph_context, secret_key_buf, sizeof(secret_key_buf));
- if (ret < 0) {
- cerr << "aborting" << std::endl;
- return 1;
- }
- secret_key = secret_key_buf;
- }
- if ((access_key.empty() && implicit_gen_key) || gen_key) {
- RGWUserInfo duplicate_check;
- string duplicate_check_id;
- do {
- ret = gen_rand_alphanumeric_upper(g_ceph_context, public_id_buf, sizeof(public_id_buf));
- if (ret < 0) {
- cerr << "aborting" << std::endl;
- return 1;
- }
- access_key = public_id_buf;
- duplicate_check_id = access_key;
- } while (!rgw_get_user_info_by_access_key(store, duplicate_check_id, duplicate_check));
- }
- }
+ if (set_perm)
+ user_op.set_perm(perm_mask);
- map<string, RGWAccessKey>::iterator kiter;
- map<string, RGWSubUser>::iterator uiter;
- RGWUserInfo old_info = info;
+ if (key_type != KEY_TYPE_UNDEFINED)
+ user_op.set_key_type(key_type);
- if (!bucket_name.empty()) {
- string bucket_name_str = bucket_name;
- RGWBucketInfo bucket_info;
- int r = store->get_bucket_info(NULL, bucket_name_str, bucket_info);
- if (r < 0) {
- cerr << "could not get bucket info for bucket=" << bucket_name_str << std::endl;
- return r;
+ // set suspension operation parameters
+ if (opt_cmd == OPT_USER_ENABLE)
+ user_op.set_suspension(false);
+ else if (opt_cmd == OPT_USER_SUSPEND)
+ user_op.set_suspension(true);
+
+ // RGWUser to use for user operations
+ RGWUser user;
+ int ret = 0;
+ if (!user_id.empty() || !subuser.empty()) {
+ ret = user.init(store, user_op);
+ if (ret < 0) {
+ cerr << "user.init failed: " << cpp_strerror(-ret) << std::endl;
+ return -ret;
}
- bucket = bucket_info.bucket;
}
- int err;
+ /* populate bucket operation */
+ bucket_op.set_bucket_name(bucket_name);
+ bucket_op.set_object(object);
+ bucket_op.set_check_objects(check_objects);
+ bucket_op.set_delete_children(delete_child_objects);
+
+ // required to gather errors from operations
+ std::string err_msg;
+
+ bool output_user_info = true;
+
switch (opt_cmd) {
+ case OPT_USER_INFO:
+ break;
case OPT_USER_CREATE:
- case OPT_USER_MODIFY:
- case OPT_SUBUSER_CREATE:
- case OPT_SUBUSER_MODIFY:
- case OPT_KEY_CREATE:
- case OPT_CAPS_ADD:
- case OPT_CAPS_RM:
- if (!user_id.empty())
- info.user_id = user_id;
- if (max_buckets >= 0)
- info.max_buckets = max_buckets;
- if (key_type == KEY_TYPE_SWIFT) {
- access_key = info.user_id;
- access_key.append(":");
- access_key.append(subuser);
+ ret = user.add(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not create user: " << err_msg << std::endl;
+ return -ret;
}
- if ((!access_key.empty()) && (!secret_key.empty())) {
- if (key_type == KEY_TYPE_S3 && !validate_access_key(access_key)) {
- cerr << "access key contains illegal characters" << std::endl;
- return 1;
- }
- RGWAccessKey k;
- k.id = access_key;
- k.key = secret_key;
- if (!subuser.empty())
- k.subuser = subuser;
- if (key_type == KEY_TYPE_SWIFT)
- info.swift_keys[access_key] = k;
- else
- info.access_keys[access_key] = k;
- } else if (opt_cmd == OPT_KEY_CREATE && (access_key.empty() || secret_key.empty())) {
- if (key_type == KEY_TYPE_SWIFT)
- cerr << "swift key modification requires both subuser and secret key" << std::endl;
- else
- cerr << "access key modification requires both access key and secret key" << std::endl;
- return 1;
- } else if (opt_cmd == OPT_CAPS_ADD) {
- err = info.caps.add_from_string(caps);
- if (err < 0) {
- cerr << "failed to add caps, err=" << cpp_strerror(-err) << std::endl;
- return 1;
- }
- } else if (opt_cmd == OPT_CAPS_RM) {
- err = info.caps.remove_from_string(caps);
- if (err < 0) {
- cerr << "failed to remove caps, err=" << cpp_strerror(-err) << std::endl;
- return 1;
- }
+
+ break;
+ case OPT_USER_RM:
+ ret = user.remove(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not remove user: " << err_msg << std::endl;
+ return -ret;
+ }
+
+ output_user_info = false;
+ break;
+ case OPT_USER_ENABLE:
+ case OPT_USER_SUSPEND:
+ case OPT_USER_MODIFY:
+ ret = user.modify(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not modify user: " << err_msg << std::endl;
+ return -ret;
}
- if (!display_name.empty())
- info.display_name = display_name;
- if (!user_email.empty())
- info.user_email = user_email;
- if (!subuser.empty()) {
- RGWSubUser u = info.subusers[subuser];
- u.name = subuser;
- if (specified_perm_mask)
- u.perm_mask = perm_mask;
-
- info.subusers[subuser] = u;
+
+ break;
+ case OPT_SUBUSER_CREATE:
+ ret = user.subusers.add(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not create subuser: " << err_msg << std::endl;
+ return -ret;
}
- if ((err = rgw_store_user_info(store, info, &old_info, false)) < 0) {
- cerr << "error storing user info: " << cpp_strerror(-err) << std::endl;
- break;
+
+ break;
+ case OPT_SUBUSER_MODIFY:
+ ret = user.subusers.modify(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not modify subuser: " << err_msg << std::endl;
+ return -ret;
}
- remove_old_indexes(old_info, info);
+ ret = user.info(info, &err_msg);
+ if (ret < 0) {
+ cerr << "could not fetch user info: " << err_msg << std::endl;
+ return -ret;
+ }
show_user_info(info, formatter);
- break;
+ break;
case OPT_SUBUSER_RM:
- uiter = info.subusers.find(subuser);
- assert (uiter != info.subusers.end());
- info.subusers.erase(uiter);
- if (purge_keys) {
- map<string, RGWAccessKey> *keys_map;
- access_key = info.user_id;
- access_key.append(":");
- access_key.append(subuser);
- keys_map = &info.swift_keys;
- kiter = keys_map->find(access_key);
- if (kiter != keys_map->end()) {
- rgw_remove_key_index(store, kiter->second);
- keys_map->erase(kiter);
- }
+ ret = user.subusers.remove(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not remove subuser: " << err_msg << std::endl;
+ return -ret;
}
- if ((err = rgw_store_user_info(store, info, &old_info, false)) < 0) {
- cerr << "error storing user info: " << cpp_strerror(-err) << std::endl;
- break;
+
+ break;
+ case OPT_CAPS_ADD:
+ ret = user.caps.add(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not add caps: " << err_msg << std::endl;
+ return -ret;
+ }
+
+ break;
+ case OPT_CAPS_RM:
+ ret = user.caps.remove(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not add remove caps: " << err_msg << std::endl;
+ return -ret;
}
- remove_old_indexes(old_info, info);
- show_user_info(info, formatter);
break;
+ case OPT_KEY_CREATE:
+ ret = user.keys.add(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not create key: " << err_msg << std::endl;
+ return -ret;
+ }
+ break;
case OPT_KEY_RM:
- {
- map<string, RGWAccessKey> *keys_map;
- if (key_type == KEY_TYPE_SWIFT) {
- access_key = info.user_id;
- access_key.append(":");
- access_key.append(subuser);
- keys_map = &info.swift_keys;
- } else {
- keys_map = &info.access_keys;
- }
- kiter = keys_map->find(access_key);
- if (kiter == keys_map->end()) {
- cerr << "key not found" << std::endl;
- } else {
- rgw_remove_key_index(store, kiter->second);
- keys_map->erase(kiter);
- if ((err = rgw_store_user_info(store, info, &old_info, false)) < 0) {
- cerr << "error storing user info: " << cpp_strerror(-err) << std::endl;
- break;
- }
- }
+ ret = user.keys.remove(user_op, &err_msg);
+ if (ret < 0) {
+ cerr << "could not remove key: " << err_msg << std::endl;
+ return -ret;
}
- show_user_info(info, formatter);
+
break;
+ default:
+ output_user_info = false;
+ }
- case OPT_USER_INFO:
+ // output the result of a user operation
+ if (output_user_info) {
+ ret = user.info(info, &err_msg);
+ if (ret < 0) {
+ cerr << "could not fetch user info: " << err_msg << std::endl;
+ return -ret;
+ }
show_user_info(info, formatter);
- break;
}
if (opt_cmd == OPT_POLICY) {
- bufferlist bl;
- rgw_obj obj(bucket, object);
- int ret = store->get_attr(NULL, obj, RGW_ATTR_ACL, bl);
-
- RGWAccessControlPolicy_S3 policy(g_ceph_context);
+ int ret = RGWBucketAdminOp::get_policy(store, bucket_op, cout);
if (ret >= 0) {
- bufferlist::iterator iter = bl.begin();
- try {
- policy.decode(iter);
- } catch (buffer::error& err) {
- dout(0) << "ERROR: caught buffer::error, could not decode policy" << dendl;
- return -EIO;
- }
- policy.to_xml(cout);
cout << std::endl;
}
}
- if (opt_cmd == OPT_BUCKETS_LIST) {
- RGWAccessHandle handle;
-
- formatter->reset();
- formatter->open_array_section("buckets");
- if (!user_id.empty()) {
- RGWUserBuckets buckets;
- if (rgw_read_user_buckets(store, user_id, buckets, false) < 0) {
- cerr << "list buckets: could not get buckets for uid " << user_id << std::endl;
- } else {
- map<string, RGWBucketEnt>& m = buckets.get_buckets();
- map<string, RGWBucketEnt>::iterator iter;
+ if (opt_cmd == OPT_BUCKETS_LIST || opt_cmd == OPT_BUCKET_STATS) {
+ if (opt_cmd == OPT_BUCKET_STATS)
+ bucket_op.set_fetch_stats(true);
- for (iter = m.begin(); iter != m.end(); ++iter) {
- RGWBucketEnt obj = iter->second;
- formatter->dump_string("bucket", obj.bucket.name);
- }
- }
- } else {
- if (store->list_buckets_init(&handle) < 0) {
- cerr << "list buckets: no buckets found" << std::endl;
- } else {
- RGWObjEnt obj;
- while (store->list_buckets_next(obj, &handle) >= 0) {
- formatter->dump_string("bucket", obj.name);
- }
- }
- }
- formatter->close_section();
- formatter->flush(cout);
- cout << std::endl;
+ RGWBucketAdminOp::info(store, bucket_op, f);
}
if (opt_cmd == OPT_BUCKET_LINK) {
- if (bucket_name.empty()) {
- cerr << "bucket name was not specified" << std::endl;
- return usage();
- }
- string uid_str(user_id);
-
- string no_oid;
- bufferlist aclbl;
- rgw_obj obj(bucket, no_oid);
-
- int r = store->get_attr(NULL, obj, RGW_ATTR_ACL, aclbl);
- if (r >= 0) {
- RGWAccessControlPolicy policy;
- ACLOwner owner;
- try {
- bufferlist::iterator iter = aclbl.begin();
- ::decode(policy, iter);
- owner = policy.get_owner();
- } catch (buffer::error& err) {
- dout(10) << "couldn't decode policy" << dendl;
- return -EINVAL;
- }
- //cout << "bucket is linked to user '" << owner.get_id() << "'.. unlinking" << std::endl;
- r = rgw_remove_user_bucket_info(store, owner.get_id(), bucket);
- if (r < 0) {
- cerr << "could not unlink policy from user '" << owner.get_id() << "'" << std::endl;
- return r;
- }
-
- // now update the user for the bucket...
- if (info.display_name.empty()) {
- cerr << "WARNING: user " << info.user_id << " has no display name set" << std::endl;
- } else {
- policy.create_default(info.user_id, info.display_name);
-
- // ...and encode the acl
- aclbl.clear();
- policy.encode(aclbl);
-
- r = store->set_attr(NULL, obj, RGW_ATTR_ACL, aclbl);
- if (r < 0)
- return r;
-
- r = rgw_add_bucket(store, info.user_id, bucket);
- if (r < 0)
- return r;
- }
- } else {
- // the bucket seems not to exist, so we should probably create it...
- r = create_bucket(bucket_name.c_str(), uid_str, info.display_name);
- if (r < 0)
- cerr << "error linking bucket to user: r=" << r << std::endl;
- return -r;
- }
+ RGWBucketAdminOp::link(store, bucket_op);
}
if (opt_cmd == OPT_BUCKET_UNLINK) {
- if (bucket_name.empty()) {
- cerr << "bucket name was not specified" << std::endl;
- return usage();
- }
-
- int r = rgw_remove_user_bucket_info(store, user_id, bucket);
- if (r < 0)
- cerr << "error unlinking bucket " << cpp_strerror(-r) << std::endl;
- return -r;
+ RGWBucketAdminOp::unlink(store, bucket_op);
}
if (opt_cmd == OPT_TEMP_REMOVE) {
}
}
- if (opt_cmd == OPT_USER_RM) {
- RGWUserBuckets buckets;
-
- if (rgw_read_user_buckets(store, user_id, buckets, false) >= 0) {
- map<string, RGWBucketEnt>& m = buckets.get_buckets();
-
- if (!m.empty() && purge_data) {
- int ret;
- for (std::map<string, RGWBucketEnt>::iterator it = m.begin(); it != m.end(); ++it) {
- ret = remove_bucket(store, ((*it).second).bucket, true);
-
- if (ret < 0)
- return ret;
- }
- }
-
- if (!m.empty() && !purge_data) {
- cerr << "ERROR: specify --purge-data to remove a user with a non-empty bucket list" << std::endl;
- return 1;
- }
- }
- rgw_delete_user(store, info);
- }
-
if (opt_cmd == OPT_POOL_ADD) {
if (pool_name.empty()) {
cerr << "need to specify pool to add!" << std::endl;
cout << std::endl;
}
- if (opt_cmd == OPT_BUCKET_STATS) {
- if (bucket_name.empty() && user_id.empty()) {
- cerr << "either bucket or uid needs to be specified" << std::endl;
- return usage();
- }
- formatter->reset();
- if (user_id.empty()) {
- bucket_stats(bucket, formatter);
- } else {
- RGWUserBuckets buckets;
- if (rgw_read_user_buckets(store, user_id, buckets, false) < 0) {
- cerr << "could not get buckets for uid " << user_id << std::endl;
- } else {
- formatter->open_array_section("buckets");
- map<string, RGWBucketEnt>& m = buckets.get_buckets();
- for (map<string, RGWBucketEnt>::iterator iter = m.begin(); iter != m.end(); ++iter) {
- RGWBucketEnt obj = iter->second;
- bucket_stats(obj.bucket, formatter);
- }
- formatter->close_section();
- }
- }
- formatter->flush(cout);
- cout << std::endl;
- }
-
- if (opt_cmd == OPT_USER_SUSPEND || opt_cmd == OPT_USER_ENABLE) {
- __u8 disable = (opt_cmd == OPT_USER_SUSPEND ? 1 : 0);
-
- if (user_id.empty()) {
- cerr << "uid was not specified" << std::endl;
- return usage();
- }
- RGWUserBuckets buckets;
- if (rgw_read_user_buckets(store, user_id, buckets, false) < 0) {
- cerr << "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(store, info, &old_info, false);
- if (ret < 0) {
- cerr << "ERROR: failed to store user info user=" << user_id << " ret=" << ret << std::endl;
- return 1;
- }
-
- if (disable)
- dout(0) << "disabling user buckets" << dendl;
- else
- dout(0) << "enabling user buckets" << dendl;
-
- vector<rgw_bucket> bucket_names;
- for (iter = m.begin(); iter != m.end(); ++iter) {
- RGWBucketEnt obj = iter->second;
- bucket_names.push_back(obj.bucket);
- }
- ret = store->set_buckets_enabled(bucket_names, !disable);
- if (ret < 0) {
- cerr << "ERROR: failed to change pool" << std::endl;
- return 1;
- }
- }
-
if (opt_cmd == OPT_USAGE_SHOW) {
uint64_t start_epoch = 0;
uint64_t end_epoch = (uint64_t)-1;
}
}
- RGWStreamFlusher f(formatter, cout);
ret = RGWUsage::show(store, user_id, start_epoch, end_epoch,
show_log_entries, show_log_sum, &categories,
}
if (opt_cmd == OPT_OBJECT_RM) {
- int ret = remove_object(store, bucket, object);
+ int ret = init_bucket(bucket_name, bucket);
+ if (ret < 0) {
+ cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
+ return -ret;
+ }
+ ret = rgw_remove_object(store, bucket, object);
if (ret < 0) {
cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
- return 1;
+ return -ret;
}
}
if (opt_cmd == OPT_OBJECT_UNLINK) {
+ int ret = init_bucket(bucket_name, bucket);
+ if (ret < 0) {
+ cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
+ return -ret;
+ }
list<string> oid_list;
oid_list.push_back(object);
- int ret = store->remove_objs_from_index(bucket, oid_list);
+ ret = store->remove_objs_from_index(bucket, oid_list);
if (ret < 0) {
cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
return 1;
}
if (opt_cmd == OPT_BUCKET_CHECK) {
- check_bad_index_multipart(store, bucket, fix);
-
- map<RGWObjCategory, RGWBucketStats> existing_stats;
- map<RGWObjCategory, RGWBucketStats> calculated_stats;
-
- if (check_objects) {
- if (!fix) {
- cerr << "--check-objects flag requires --fix" << std::endl;
- return 1;
- }
-#define BUCKET_TAG_TIMEOUT 30
- cout << "Checking objects, decreasing bucket 2-phase commit timeout.\n"
- "** Note that timeout will reset only when operation completes successfully **" << std::endl;
-
- store->cls_obj_set_bucket_tag_timeout(bucket, BUCKET_TAG_TIMEOUT);
-
- string prefix;
- string marker;
- bool is_truncated = true;
-
- while (is_truncated) {
- map<string, RGWObjEnt> result;
- int r = store->cls_bucket_list(bucket, marker, prefix, 1000,
- result, &is_truncated, &marker,
- bucket_object_check_filter);
-
- if (r < 0 && r != -ENOENT) {
- cerr << "ERROR: failed operation r=" << r << std::endl;
- }
-
- if (r == -ENOENT)
- break;
-
- map<string, RGWObjEnt>::iterator iter;
- for (iter = result.begin(); iter != result.end(); ++iter) {
- cout << iter->first << std::endl;
- }
-
- }
-
- store->cls_obj_set_bucket_tag_timeout(bucket, 0);
-
- }
- int r = store->bucket_check_index(bucket, &existing_stats, &calculated_stats);
- if (r < 0) {
- cerr << "failed to check index err=" << cpp_strerror(-r) << std::endl;
- return r;
- }
-
- formatter->open_object_section("check_result");
- formatter->open_object_section("existing_header");
- dump_bucket_usage(existing_stats, formatter);
- formatter->close_section();
- formatter->open_object_section("calculated_header");
- dump_bucket_usage(calculated_stats, formatter);
- formatter->close_section();
- formatter->close_section();
- formatter->flush(cout);
-
- if (fix) {
- r = store->bucket_rebuild_index(bucket);
- if (r < 0) {
- cerr << "failed to rebuild index err=" << cpp_strerror(-r) << std::endl;
- return r;
- }
- }
-
+ RGWBucketAdminOp::check_index(store, bucket_op, f);
}
if (opt_cmd == OPT_BUCKET_RM) {
- int ret = remove_bucket(store, bucket, delete_child_objects);
-
- if (ret < 0) {
- cerr << "ERROR: bucket remove returned: " << cpp_strerror(-ret) << std::endl;
- return 1;
- }
+ RGWBucketAdminOp::remove_bucket(store, bucket_op);
}
if (opt_cmd == OPT_GC_LIST) {
--- /dev/null
+#include <errno.h>
+
+#include <string>
+#include <map>
+
+#include "common/errno.h"
+#include "rgw_rados.h"
+#include "rgw_acl.h"
+#include "rgw_acl_s3.h"
+
+#include "include/types.h"
+#include "rgw_bucket.h"
+#include "rgw_user.h"
+#include "rgw_string.h"
+
+// until everything is moved from rgw_common
+#include "rgw_common.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+#define BUCKET_TAG_TIMEOUT 30
+
+using namespace std;
+
+// define as static when RGWBucket implementation compete
+void rgw_get_buckets_obj(string& user_id, string& buckets_obj_id)
+{
+ buckets_obj_id = user_id;
+ buckets_obj_id += RGW_BUCKETS_OBJ_PREFIX;
+}
+
+static int rgw_read_buckets_from_attr(RGWRados *store, string& user_id, RGWUserBuckets& buckets)
+{
+ bufferlist bl;
+ rgw_obj obj(store->zone.user_uid_pool, user_id);
+ int ret = store->get_attr(NULL, obj, RGW_ATTR_BUCKETS, bl);
+ if (ret)
+ return ret;
+
+ bufferlist::iterator iter = bl.begin();
+ try {
+ buckets.decode(iter);
+ } catch (buffer::error& err) {
+ ldout(store->ctx(), 0) << "ERROR: failed to decode buckets info, caught buffer::error" << dendl;
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
+ * Returns: 0 on success, -ERR# on failure.
+ */
+int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, bool need_stats)
+{
+ int ret;
+ buckets.clear();
+ if (store->supports_omap()) {
+ string buckets_obj_id;
+ rgw_get_buckets_obj(user_id, buckets_obj_id);
+ bufferlist bl;
+ rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id);
+ bufferlist header;
+ map<string,bufferlist> m;
+
+ ret = store->omap_get_all(obj, header, m);
+ if (ret == -ENOENT)
+ ret = 0;
+
+ if (ret < 0)
+ return ret;
+
+ for (map<string,bufferlist>::iterator q = m.begin(); q != m.end(); q++) {
+ bufferlist::iterator iter = q->second.begin();
+ RGWBucketEnt bucket;
+ ::decode(bucket, iter);
+ buckets.add(bucket);
+ }
+ } else {
+ ret = rgw_read_buckets_from_attr(store, user_id, buckets);
+ switch (ret) {
+ case 0:
+ break;
+ case -ENODATA:
+ ret = 0;
+ return 0;
+ default:
+ return ret;
+ }
+ }
+
+ if (need_stats) {
+ map<string, RGWBucketEnt>& m = buckets.get_buckets();
+ int r = store->update_containers_stats(m);
+ if (r < 0) {
+ ldout(store->ctx(), 0) << "ERROR: could not get stats for buckets" << dendl;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Store the set of buckets associated with a user on a n xattr
+ * not used with all backends
+ * This completely overwrites any previously-stored list, so be careful!
+ * Returns 0 on success, -ERR# otherwise.
+ */
+int rgw_write_buckets_attr(RGWRados *store, string user_id, RGWUserBuckets& buckets)
+{
+ bufferlist bl;
+ buckets.encode(bl);
+
+ rgw_obj obj(store->zone.user_uid_pool, user_id);
+
+ int ret = store->set_attr(NULL, obj, RGW_ATTR_BUCKETS, bl);
+
+ return ret;
+}
+
+int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket)
+{
+ int ret;
+ string& bucket_name = bucket.name;
+
+ if (store->supports_omap()) {
+ bufferlist bl;
+
+ RGWBucketEnt new_bucket;
+ new_bucket.bucket = bucket;
+ new_bucket.size = 0;
+ time(&new_bucket.mtime);
+ ::encode(new_bucket, bl);
+
+ string buckets_obj_id;
+ rgw_get_buckets_obj(user_id, buckets_obj_id);
+
+ rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id);
+ ret = store->omap_set(obj, bucket_name, bl);
+ if (ret < 0) {
+ ldout(store->ctx(), 0) << "ERROR: error adding bucket to directory: "
+ << cpp_strerror(-ret)<< dendl;
+ }
+ } else {
+ RGWUserBuckets buckets;
+
+ ret = rgw_read_user_buckets(store, user_id, buckets, false);
+ RGWBucketEnt new_bucket;
+
+ switch (ret) {
+ case 0:
+ case -ENOENT:
+ case -ENODATA:
+ new_bucket.bucket = bucket;
+ new_bucket.size = 0;
+ time(&new_bucket.mtime);
+ buckets.add(new_bucket);
+ ret = rgw_write_buckets_attr(store, user_id, buckets);
+ break;
+ default:
+ ldout(store->ctx(), 10) << "rgw_write_buckets_attr returned " << ret << dendl;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int rgw_remove_user_bucket_info(RGWRados *store, string user_id, rgw_bucket& bucket)
+{
+ int ret;
+
+ if (store->supports_omap()) {
+ bufferlist bl;
+
+ string buckets_obj_id;
+ rgw_get_buckets_obj(user_id, buckets_obj_id);
+
+ rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id);
+ ret = store->omap_del(obj, bucket.name);
+ if (ret < 0) {
+ ldout(store->ctx(), 0) << "ERROR: error removing bucket from directory: "
+ << cpp_strerror(-ret)<< dendl;
+ }
+ } else {
+ RGWUserBuckets buckets;
+
+ ret = rgw_read_user_buckets(store, user_id, buckets, false);
+
+ if (ret == 0 || ret == -ENOENT) {
+ buckets.remove(bucket.name);
+ ret = rgw_write_buckets_attr(store, user_id, buckets);
+ }
+ }
+
+ return ret;
+}
+
+int RGWBucket::create_bucket(string bucket_str, string& user_id, string& display_name)
+{
+ RGWAccessControlPolicy policy, old_policy;
+ map<string, bufferlist> attrs;
+ bufferlist aclbl;
+ string no_oid;
+ rgw_obj obj;
+ RGWBucketInfo bucket_info;
+
+ int ret;
+
+ // defaule policy (private)
+ policy.create_default(user_id, display_name);
+ policy.encode(aclbl);
+
+ ret = store->get_bucket_info(NULL, bucket_str, bucket_info);
+ if (ret < 0)
+ return ret;
+
+ rgw_bucket& bucket = bucket_info.bucket;
+
+ ret = store->create_bucket(user_id, bucket, attrs);
+ if (ret && ret != -EEXIST)
+ goto done;
+
+ obj.init(bucket, no_oid);
+
+ ret = store->set_attr(NULL, obj, RGW_ATTR_ACL, aclbl);
+ if (ret < 0) {
+ lderr(store->ctx()) << "ERROR: failed to set acl on bucket" << dendl;
+ goto done;
+ }
+
+ ret = rgw_add_bucket(store, user_id, bucket);
+
+ if (ret == -EEXIST)
+ ret = 0;
+done:
+ return ret;
+}
+
+static void dump_mulipart_index_results(list<std::string>& objs_to_unlink,
+ Formatter *f)
+{
+ // make sure that an appropiately titled header has been opened previously
+ list<std::string>::iterator oiter = objs_to_unlink.begin();
+
+ f->open_array_section("invalid_multipart_entries");
+
+ for ( ; oiter != objs_to_unlink.end(); ++oiter) {
+ f->dump_string("object", *oiter);
+ }
+
+ f->close_section();
+}
+
+void check_bad_user_bucket_mapping(RGWRados *store, const string& user_id, bool fix)
+{
+ RGWUserBuckets user_buckets;
+ int ret = rgw_read_user_buckets(store, user_id, user_buckets, false);
+ if (ret < 0) {
+ ldout(store->ctx(), 0) << "failed to read user buckets: " << cpp_strerror(-ret) << dendl;
+ return;
+ }
+
+ map<string, RGWBucketEnt>& buckets = user_buckets.get_buckets();
+ for (map<string, RGWBucketEnt>::iterator i = buckets.begin();
+ i != buckets.end();
+ ++i) {
+ RGWBucketEnt& bucket_ent = i->second;
+ rgw_bucket& bucket = bucket_ent.bucket;
+
+ RGWBucketInfo bucket_info;
+ int r = store->get_bucket_info(NULL, bucket.name, bucket_info);
+ if (r < 0) {
+ ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket << dendl;
+ continue;
+ }
+
+ rgw_bucket& actual_bucket = bucket_info.bucket;
+
+ if (actual_bucket.name.compare(bucket.name) != 0 ||
+ actual_bucket.pool.compare(bucket.pool) != 0 ||
+ actual_bucket.marker.compare(bucket.marker) != 0 ||
+ actual_bucket.bucket_id.compare(bucket.bucket_id) != 0) {
+ cout << "bucket info mismatch: expected " << actual_bucket << " got " << bucket << std::endl;
+ if (fix) {
+ cout << "fixing" << std::endl;
+ r = rgw_add_bucket(store, user_id, actual_bucket);
+ if (r < 0) {
+ cerr << "failed to fix bucket: " << cpp_strerror(-r) << std::endl;
+ }
+ }
+ }
+ }
+}
+
+static bool bucket_object_check_filter(const string& name)
+{
+ string ns;
+ string obj = name;
+ return rgw_obj::translate_raw_obj_to_obj_in_ns(obj, ns);
+}
+
+int rgw_remove_object(RGWRados *store, rgw_bucket& bucket, std::string& object)
+{
+ RGWRadosCtx rctx(store);
+
+ rgw_obj obj(bucket,object);
+
+ int ret = store->delete_obj((void *)&rctx, obj);
+
+ return ret;
+}
+
+int rgw_remove_bucket(RGWRados *store, rgw_bucket& bucket, bool delete_children)
+{
+ int ret;
+ map<RGWObjCategory, RGWBucketStats> stats;
+ std::vector<RGWObjEnt> objs;
+ std::string prefix, delim, marker, ns;
+ map<string, bool> common_prefixes;
+ rgw_obj obj;
+ RGWBucketInfo info;
+ bufferlist bl;
+
+ ret = store->get_bucket_stats(bucket, stats);
+ if (ret < 0)
+ return ret;
+
+ obj.bucket = bucket;
+ int max = 1000;
+
+ ret = rgw_get_obj(store, NULL, store->zone.domain_root,\
+ bucket.name, bl, NULL);
+
+ bufferlist::iterator iter = bl.begin();
+ try {
+ ::decode(info, iter);
+ } catch (buffer::error& err) {
+ //cerr << "ERROR: could not decode buffer info, caught buffer::error" << std::endl;
+ return -EIO;
+ }
+
+ if (delete_children) {
+ ret = store->list_objects(bucket, max, prefix, delim, marker,\
+ objs, common_prefixes,\
+ false, ns, (bool *)false, NULL);
+
+ if (ret < 0)
+ return ret;
+
+ while (!objs.empty()) {
+ std::vector<RGWObjEnt>::iterator it = objs.begin();
+ for (it = objs.begin(); it != objs.end(); ++it) {
+ ret = rgw_remove_object(store, bucket, (*it).name);
+ if (ret < 0)
+ return ret;
+ }
+ objs.clear();
+
+ ret = store->list_objects(bucket, max, prefix, delim, marker, objs, common_prefixes,
+ false, ns, (bool *)false, NULL);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ ret = store->delete_bucket(bucket);
+ if (ret < 0) {
+ lderr(store->ctx()) << "ERROR: could not remove bucket " << bucket.name << dendl;
+ return ret;
+ }
+
+ ret = rgw_remove_user_bucket_info(store, info.owner, bucket);
+ if (ret < 0) {
+ lderr(store->ctx()) << "ERROR: unable to remove user bucket information" << dendl;
+ }
+
+ return ret;
+}
+
+static void set_err_msg(std::string *sink, std::string msg)
+{
+ if (sink && !msg.empty())
+ *sink = msg;
+}
+
+int RGWBucket::init(RGWRados *storage, RGWBucketAdminOpState& op_state)
+{
+ if (!storage)
+ return -EINVAL;
+
+ store = storage;
+
+ RGWUserInfo info;
+ RGWBucketInfo bucket_info;
+
+ user_id = op_state.get_user_id();
+ bucket_name = op_state.get_bucket_name();
+ RGWUserBuckets user_buckets;
+
+ if (bucket_name.empty() && user_id.empty())
+ return -EINVAL;
+
+ if (!bucket_name.empty()) {
+ int r = store->get_bucket_info(NULL, bucket_name, bucket_info);
+ if (r < 0) {
+ ldout(store->ctx(), 0) << "could not get bucket info for bucket=" << bucket_name << dendl;
+ return r;
+ }
+
+ op_state.set_bucket(bucket_info.bucket);
+ }
+
+ if (!user_id.empty()) {
+ int r = rgw_get_user_info_by_uid(store, user_id, info);
+ if (r < 0)
+ return r;
+
+ r = rgw_read_user_buckets(store, user_id, user_buckets, true);
+ if (r < 0)
+ return r;
+
+ op_state.set_user_buckets(user_buckets);
+ op_state.display_name = info.display_name;
+ }
+
+ clear_failure();
+ return 0;
+}
+
+int RGWBucket::link(RGWBucketAdminOpState& op_state, std::string *err_msg)
+{
+ if (!op_state.is_user_op()) {
+ set_err_msg(err_msg, "empty user id");
+ return -EINVAL;
+ }
+
+ std::string no_oid;
+
+ std::string display_name = op_state.get_user_display_name();
+ rgw_bucket bucket = op_state.get_bucket();
+
+ string uid_str(user_id);
+ bufferlist aclbl;
+ rgw_obj obj(bucket, no_oid);
+
+ int r = store->get_attr(NULL, obj, RGW_ATTR_ACL, aclbl);
+ if (r >= 0) {
+ RGWAccessControlPolicy policy;
+ ACLOwner owner;
+ try {
+ bufferlist::iterator iter = aclbl.begin();
+ ::decode(policy, iter);
+ owner = policy.get_owner();
+ } catch (buffer::error& err) {
+ set_err_msg(err_msg, "couldn't decode policy");
+ return -EIO;
+ }
+
+ r = rgw_remove_user_bucket_info(store, owner.get_id(), bucket);
+ if (r < 0) {
+ set_err_msg(err_msg, "could not unlink policy from user " + owner.get_id());
+ return r;
+ }
+
+ // now update the user for the bucket...
+ if (display_name.empty()) {
+ ldout(store->ctx(), 0) << "WARNING: user " << user_id << " has no display name set" << dendl;
+ }
+ policy.create_default(user_id, display_name);
+
+ owner = policy.get_owner();
+ r = store->set_bucket_owner(bucket, owner);
+ if (r < 0) {
+ set_err_msg(err_msg, "failed to set bucket owner: " + cpp_strerror(-r));
+ return r;
+ }
+
+ // ...and encode the acl
+ aclbl.clear();
+ policy.encode(aclbl);
+
+ r = store->set_attr(NULL, obj, RGW_ATTR_ACL, aclbl);
+ if (r < 0)
+ return r;
+
+ r = rgw_add_bucket(store, user_id, bucket);
+ if (r < 0)
+ return r;
+ } else {
+ // the bucket seems not to exist, so we should probably create it...
+ r = create_bucket(bucket_name.c_str(), uid_str, display_name);
+ if (r < 0) {
+ set_err_msg(err_msg, "error linking bucket to user r=" + cpp_strerror(-r));
+ }
+
+ return r;
+ }
+
+ return 0;
+}
+
+int RGWBucket::unlink(RGWBucketAdminOpState& op_state, std::string *err_msg)
+{
+ rgw_bucket bucket = op_state.get_bucket();
+
+ if (!op_state.is_user_op()) {
+ set_err_msg(err_msg, "could not fetch user or user bucket info");
+ return -EINVAL;
+ }
+
+ int r = rgw_remove_user_bucket_info(store, user_id, bucket);
+ if (r < 0) {
+ set_err_msg(err_msg, "error unlinking bucket" + cpp_strerror(-r));
+ }
+
+ return r;
+}
+
+int RGWBucket::remove(RGWBucketAdminOpState& op_state, std::string *err_msg)
+{
+ bool delete_children = op_state.will_delete_children();
+ rgw_bucket bucket = op_state.get_bucket();
+
+ int ret = rgw_remove_bucket(store, bucket, delete_children);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove bucket" + cpp_strerror(-ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWBucket::remove_object(RGWBucketAdminOpState& op_state, std::string *err_msg)
+{
+ rgw_bucket bucket = op_state.get_bucket();
+ std::string object_name = op_state.get_object_name();
+
+ int ret = rgw_remove_object(store, bucket, object_name);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove object" + cpp_strerror(-ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+static void dump_bucket_index(map<string, RGWObjEnt> result, Formatter *f)
+{
+ map<string, RGWObjEnt>::iterator iter;
+ for (iter = result.begin(); iter != result.end(); ++iter) {
+ f->dump_string("object", iter->first);
+ }
+}
+
+static void dump_bucket_usage(map<RGWObjCategory, RGWBucketStats>& stats, Formatter *formatter)
+{
+ map<RGWObjCategory, RGWBucketStats>::iterator iter;
+
+ formatter->open_object_section("usage");
+ for (iter = stats.begin(); iter != stats.end(); ++iter) {
+ RGWBucketStats& s = iter->second;
+ const char *cat_name = rgw_obj_category_name(iter->first);
+ formatter->open_object_section(cat_name);
+ formatter->dump_int("size_kb", s.num_kb);
+ formatter->dump_int("size_kb_actual", s.num_kb_rounded);
+ formatter->dump_int("num_objects", s.num_objects);
+ formatter->close_section();
+ }
+ formatter->close_section();
+}
+
+static void dump_index_check(map<RGWObjCategory, RGWBucketStats> existing_stats,
+ map<RGWObjCategory, RGWBucketStats> calculated_stats,
+ Formatter *formatter)
+{
+ formatter->open_object_section("check_result");
+ formatter->open_object_section("existing_header");
+ dump_bucket_usage(existing_stats, formatter);
+ formatter->close_section();
+ formatter->open_object_section("calculated_header");
+ dump_bucket_usage(calculated_stats, formatter);
+ formatter->close_section();
+ formatter->close_section();
+ formatter->flush(cout);
+}
+
+int RGWBucket::check_bad_index_multipart(RGWBucketAdminOpState& op_state,
+ list<std::string>& objs_to_unlink, std::string *err_msg)
+{
+ bool fix_index = op_state.will_fix_index();
+ rgw_bucket bucket = op_state.get_bucket();
+
+ int max = 1000;
+ string prefix;
+ string marker;
+ string delim;
+
+ map<string, bool> common_prefixes;
+ string ns = "multipart";
+
+ bool is_truncated;
+ map<string, bool> meta_objs;
+ map<string, string> all_objs;
+
+ do {
+ vector<RGWObjEnt> result;
+ int r = store->list_objects(bucket, max, prefix, delim, marker,
+ result, common_prefixes, false, ns,
+ &is_truncated, NULL);
+
+ if (r < 0) {
+ set_err_msg(err_msg, "failed to list objects in bucket=" + bucket.name +
+ " err=" + cpp_strerror(-r));
+
+ return r;
+ }
+
+ vector<RGWObjEnt>::iterator iter;
+ for (iter = result.begin(); iter != result.end(); ++iter) {
+ RGWObjEnt& ent = *iter;
+
+ rgw_obj obj(bucket, ent.name);
+ obj.set_ns(ns);
+
+ string& oid = obj.object;
+ marker = oid;
+
+ int pos = oid.find_last_of('.');
+ if (pos < 0)
+ continue;
+
+ string name = oid.substr(0, pos);
+ string suffix = oid.substr(pos + 1);
+
+ if (suffix.compare("meta") == 0) {
+ meta_objs[name] = true;
+ } else {
+ all_objs[oid] = name;
+ }
+ }
+
+ } while (is_truncated);
+
+ map<string, string>::iterator aiter;
+ for (aiter = all_objs.begin(); aiter != all_objs.end(); ++aiter) {
+ string& name = aiter->second;
+
+ if (meta_objs.find(name) == meta_objs.end()) {
+ objs_to_unlink.push_back(aiter->first);
+ }
+ }
+
+ if (objs_to_unlink.empty())
+ return 0;
+
+ if (fix_index) {
+ int r = store->remove_objs_from_index(bucket, objs_to_unlink);
+ if (r < 0) {
+ set_err_msg(err_msg, "ERROR: remove_obj_from_index() returned error: " +
+ cpp_strerror(-r));
+
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+int RGWBucket::check_object_index(RGWBucketAdminOpState& op_state,
+ map<string, RGWObjEnt> result, std::string *err_msg)
+{
+
+ bool fix_index = op_state.will_fix_index();
+ rgw_bucket bucket = op_state.get_bucket();
+
+ if (!fix_index) {
+ set_err_msg(err_msg, "check-objects flag requires fix index enabled");
+ return -EINVAL;
+ }
+
+/*
+ dout(0) << "Checking objects, decreasing bucket 2-phase commit timeout.\n"\
+ << "** Note that timeout will reset only when operation completes successfully **" << dendl;
+*/
+ store->cls_obj_set_bucket_tag_timeout(bucket, BUCKET_TAG_TIMEOUT);
+
+ string prefix;
+ string marker;
+ bool is_truncated = true;
+
+ while (is_truncated) {
+ map<string, RGWObjEnt> result;
+ string ns;
+
+ int r = store->cls_bucket_list(bucket, marker, prefix, 1000, result,
+ &is_truncated, &marker,
+ bucket_object_check_filter);
+
+ if (r == -ENOENT) {
+ break;
+ } else if (r < 0 && r != -ENOENT) {
+ set_err_msg(err_msg, "ERROR: failed operation r=" + cpp_strerror(-r));
+ }
+ }
+
+ store->cls_obj_set_bucket_tag_timeout(bucket, 0);
+
+ return 0;
+}
+
+
+int RGWBucket::check_index(RGWBucketAdminOpState& op_state,
+ map<RGWObjCategory, RGWBucketStats>& existing_stats,
+ map<RGWObjCategory, RGWBucketStats>& calculated_stats,
+ std::string *err_msg)
+{
+ rgw_bucket bucket = op_state.get_bucket();
+ bool fix_index = op_state.will_fix_index();
+
+ int r = store->bucket_check_index(bucket, &existing_stats, &calculated_stats);
+ if (r < 0) {
+ set_err_msg(err_msg, "failed to check index error=" + cpp_strerror(-r));
+ return r;
+ }
+
+ if (fix_index) {
+ r = store->bucket_rebuild_index(bucket);
+ if (r < 0) {
+ set_err_msg(err_msg, "failed to rebuild index err=" + cpp_strerror(-r));
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+int RGWBucket::get_policy(RGWBucketAdminOpState& op_state, ostream& o)
+{
+ std::string object_name = op_state.get_object_name();
+ rgw_bucket bucket = op_state.get_bucket();
+
+ bufferlist bl;
+ rgw_obj obj(bucket, object_name);
+ int ret = store->get_attr(NULL, obj, RGW_ATTR_ACL, bl);
+ if (ret < 0)
+ return ret;
+
+ RGWAccessControlPolicy_S3 policy(g_ceph_context);
+ bufferlist::iterator iter = bl.begin();
+ try {
+ policy.decode(iter);
+ } catch (buffer::error& err) {
+ dout(0) << "ERROR: caught buffer::error, could not decode policy" << dendl;
+ return -EIO;
+ }
+ policy.to_xml(o);
+
+ return 0;
+}
+
+
+int RGWBucketAdminOp::get_policy(RGWRados *store, RGWBucketAdminOpState& op_state,
+ ostream& os)
+{
+ RGWBucket bucket;
+
+ int ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ ret = bucket.get_policy(op_state, os);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Wrappers to facilitate RESTful interface */
+
+
+int RGWBucketAdminOp::get_policy(RGWRados *store, RGWBucketAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ std::ostringstream policy_stream;
+
+ int ret = get_policy(store, op_state, policy_stream);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ flusher.start(0);
+
+ formatter->dump_string("policy", policy_stream.str());
+
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWBucketAdminOp::unlink(RGWRados *store, RGWBucketAdminOpState& op_state)
+{
+ RGWBucket bucket;
+
+ int ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ return bucket.unlink(op_state);
+}
+
+int RGWBucketAdminOp::link(RGWRados *store, RGWBucketAdminOpState& op_state)
+{
+ RGWBucket bucket;
+
+ int ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ return bucket.link(op_state);
+
+}
+
+int RGWBucketAdminOp::check_index(RGWRados *store, RGWBucketAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ int ret;
+ map<string, RGWObjEnt> result;
+ map<RGWObjCategory, RGWBucketStats> existing_stats;
+ map<RGWObjCategory, RGWBucketStats> calculated_stats;
+ list<std::string> objs_to_unlink;
+
+ RGWBucket bucket;
+
+ ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+ flusher.start(0);
+
+ ret = bucket.check_bad_index_multipart(op_state, objs_to_unlink);
+ if (ret < 0)
+ return ret;
+
+ dump_mulipart_index_results(objs_to_unlink, formatter);
+ flusher.flush();
+
+ ret = bucket.check_object_index(op_state, result);
+ if (ret < 0)
+ return ret;
+
+ dump_bucket_index(result, formatter);
+ flusher.flush();
+
+ ret = bucket.check_index(op_state, existing_stats, calculated_stats);
+ if (ret < 0)
+ return ret;
+
+ dump_index_check(existing_stats, calculated_stats, formatter);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWBucketAdminOp::remove_bucket(RGWRados *store, RGWBucketAdminOpState& op_state)
+{
+ RGWBucket bucket;
+
+ int ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ return bucket.remove(op_state);
+}
+
+int RGWBucketAdminOp::remove_object(RGWRados *store, RGWBucketAdminOpState& op_state)
+{
+ RGWBucket bucket;
+
+ int ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ return bucket.remove_object(op_state);
+}
+
+static int bucket_stats(RGWRados *store, std::string& bucket_name, Formatter *formatter)
+{
+ RGWBucketInfo bucket_info;
+ rgw_bucket bucket;
+ map<RGWObjCategory, RGWBucketStats> stats;
+
+ int r = store->get_bucket_info(NULL, bucket_name, bucket_info);
+ if (r < 0)
+ return r;
+
+ bucket = bucket_info.bucket;
+
+ int ret = store->get_bucket_stats(bucket, stats);
+ if (ret < 0) {
+ cerr << "error getting bucket stats ret=" << ret << std::endl;
+ return ret;
+ }
+
+ formatter->open_object_section("stats");
+ formatter->dump_string("bucket", bucket.name);
+ formatter->dump_string("pool", bucket.pool);
+
+ formatter->dump_string("id", bucket.bucket_id);
+ formatter->dump_string("marker", bucket.marker);
+ formatter->dump_string("owner", bucket_info.owner);
+ dump_bucket_usage(stats, formatter);
+ formatter->close_section();
+
+ return 0;
+}
+
+
+int RGWBucketAdminOp::info(RGWRados *store, RGWBucketAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWBucket bucket;
+ int ret = bucket.init(store, op_state);
+ if (ret < 0)
+ return ret;
+ string bucket_name = op_state.get_bucket_name();
+
+ Formatter *formatter = flusher.get_formatter();
+ flusher.start(0);
+
+ bool show_stats = op_state.will_fetch_stats();
+ if (op_state.is_user_op()) {
+ formatter->open_array_section("buckets");
+
+ RGWUserBuckets buckets = op_state.get_user_buckets();
+ map<string, RGWBucketEnt>& m = buckets.get_buckets();
+ map<string, RGWBucketEnt>::iterator iter;
+
+ for (iter = m.begin(); iter != m.end(); ++iter) {
+ std::string obj_name = iter->first;
+ if (show_stats)
+ bucket_stats(store, obj_name, formatter);
+ else
+ formatter->dump_string("bucket", obj_name);
+ }
+
+ formatter->close_section();
+ } else if (!bucket_name.empty()) {
+ bucket_stats(store, bucket_name, formatter);
+ } else {
+ RGWAccessHandle handle;
+
+ if (store->list_buckets_init(&handle) > 0) {
+ RGWObjEnt obj;
+ while (store->list_buckets_next(obj, &handle) >= 0) {
+ formatter->dump_string("bucket", obj.name);
+ if (show_stats)
+ bucket_stats(store, obj.name, formatter);
+ }
+ }
+ }
+
+ flusher.flush();
+
+ return 0;
+}
+
--- /dev/null
+#ifndef CEPH_RGW_BUCKET_H
+#define CEPH_RGW_BUCKET_H
+
+#include <string>
+
+#include "include/types.h"
+#include "rgw_common.h"
+#include "rgw_tools.h"
+
+#include "rgw_rados.h"
+
+#include "rgw_string.h"
+
+#include "common/Formatter.h"
+#include "rgw_formats.h"
+
+
+using namespace std;
+
+// define as static when RGWBucket implementation compete
+extern void rgw_get_buckets_obj(string& user_id, string& buckets_obj_id);
+
+
+/**
+ * Store a list of the user's buckets, with associated functinos.
+ */
+class RGWUserBuckets
+{
+ map<string, RGWBucketEnt> buckets;
+
+public:
+ RGWUserBuckets() {}
+ void encode(bufferlist& bl) const {
+ ::encode(buckets, bl);
+ }
+ void decode(bufferlist::iterator& bl) {
+ ::decode(buckets, bl);
+ }
+ /**
+ * Check if the user owns a bucket by the given name.
+ */
+ bool owns(string& name) {
+ map<string, RGWBucketEnt>::iterator iter;
+ iter = buckets.find(name);
+ return (iter != buckets.end());
+ }
+
+ /**
+ * Add a (created) bucket to the user's bucket list.
+ */
+ void add(RGWBucketEnt& bucket) {
+ buckets[bucket.bucket.name] = bucket;
+ }
+
+ /**
+ * Remove a bucket from the user's list by name.
+ */
+ void remove(string& name) {
+ map<string, RGWBucketEnt>::iterator iter;
+ iter = buckets.find(name);
+ if (iter != buckets.end()) {
+ buckets.erase(iter);
+ }
+ }
+
+ /**
+ * Get the user's buckets as a map.
+ */
+ map<string, RGWBucketEnt>& get_buckets() { return buckets; }
+
+ /**
+ * Cleanup data structure
+ */
+ void clear() { buckets.clear(); }
+
+ size_t count() { return buckets.size(); }
+};
+WRITE_CLASS_ENCODER(RGWUserBuckets)
+
+/**
+ * Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
+ * Returns: 0 on success, -ERR# on failure.
+ */
+extern int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, bool need_stats);
+
+/**
+ * Store the set of buckets associated with a user.
+ * This completely overwrites any previously-stored list, so be careful!
+ * Returns 0 on success, -ERR# otherwise.
+ */
+extern int rgw_write_buckets_attr(RGWRados *store, string user_id, RGWUserBuckets& buckets);
+
+extern int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket);
+extern int rgw_remove_user_bucket_info(RGWRados *store, string user_id, rgw_bucket& bucket);
+
+extern int rgw_remove_object(RGWRados *store, rgw_bucket& bucket, std::string& object);
+extern int rgw_remove_bucket(RGWRados *store, rgw_bucket& bucket, bool delete_children);
+
+extern void check_bad_user_bucket_mapping(RGWRados *store, const string& user_id, bool fix);
+
+struct RGWBucketAdminOpState {
+ std::string uid;
+ std::string display_name;
+ std::string bucket_name;
+ std::string bucket_id;
+ std::string object_name;
+
+ bool list_buckets;
+ bool stat_buckets;
+ bool check_objects;
+ bool fix_index;
+ bool delete_child_objects;
+ bool bucket_stored;
+
+ rgw_bucket bucket;
+ RGWUserBuckets buckets;
+
+ void set_fetch_stats(bool value) { stat_buckets = value; }
+ void set_check_objects(bool value) { check_objects = value; }
+ void set_fix_index(bool value) { fix_index = value; }
+ void set_delete_children(bool value) { delete_child_objects = value; }
+
+ void set_user_id(std::string& user_id) {
+ if (!user_id.empty())
+ uid = user_id;
+ }
+ void set_bucket_name(std::string& bucket_str) {
+ bucket_name = bucket_str;
+ }
+ void set_object(std::string& object_str) {
+ object_name = object_str;
+ }
+
+ std::string& get_user_id() { return uid; };
+ std::string& get_user_display_name() { return display_name; };
+ std::string& get_bucket_name() { return bucket_name; };
+ std::string& get_object_name() { return object_name; };
+
+ rgw_bucket& get_bucket() { return bucket; };
+ void set_bucket(rgw_bucket& _bucket) {
+ bucket = _bucket;
+ bucket_stored = true;
+ }
+
+ RGWUserBuckets& get_user_buckets() { return buckets; };
+ void set_user_buckets(RGWUserBuckets& _buckets) { buckets = _buckets; };
+
+ bool will_fetch_stats() { return stat_buckets; };
+ bool will_fix_index() { return fix_index; };
+ bool will_delete_children() { return delete_child_objects; };
+ bool will_check_objects() { return check_objects; };
+ bool is_user_op() { return !uid.empty(); };
+ bool is_system_op() { return uid.empty(); };
+ bool has_bucket_stored() { return bucket_stored; };
+
+ RGWBucketAdminOpState() : list_buckets(false), stat_buckets(false), check_objects(false),
+ fix_index(false), delete_child_objects(false),
+ bucket_stored(false) {}
+};
+
+/*
+ * A simple wrapper class for administrative bucket operations
+ */
+
+class RGWBucket
+{
+ RGWUserBuckets buckets;
+ RGWRados *store;
+ RGWAccessHandle handle;
+
+ std::string user_id;
+ std::string bucket_name;
+
+ bool failure;
+
+private:
+
+public:
+ RGWBucket() : store(NULL), failure(false) {}
+ int init(RGWRados *storage, RGWBucketAdminOpState& op_state);
+
+ int create_bucket(string bucket_str, string& user_id, string& display_name);
+
+ int check_bad_index_multipart(RGWBucketAdminOpState& op_state,
+ list<std::string>& objs_to_unlink, std::string *err_msg = NULL);
+
+ int check_object_index(RGWBucketAdminOpState& op_state,
+ map<string, RGWObjEnt> result, std::string *err_msg = NULL);
+
+ int check_index(RGWBucketAdminOpState& op_state,
+ map<RGWObjCategory, RGWBucketStats>& existing_stats,
+ map<RGWObjCategory, RGWBucketStats>& calculated_stats,
+ std::string *err_msg = NULL);
+
+ int remove(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL);
+ int link(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL);
+ int unlink(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL);
+
+ int remove_object(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL);
+ int get_policy(RGWBucketAdminOpState& op_state, ostream& o);
+
+ void clear_failure() { failure = false; };
+};
+
+class RGWBucketAdminOp
+{
+public:
+ static int get_policy(RGWRados *store, RGWBucketAdminOpState& op_state,
+ RGWFormatterFlusher& flusher);
+ static int get_policy(RGWRados *store, RGWBucketAdminOpState& op_state,
+ ostream& os);
+
+
+ static int unlink(RGWRados *store, RGWBucketAdminOpState& op_state);
+ static int link(RGWRados *store, RGWBucketAdminOpState& op_state);
+
+ static int check_index(RGWRados *store, RGWBucketAdminOpState& op_state,
+ RGWFormatterFlusher& flusher);
+
+ static int remove_bucket(RGWRados *store, RGWBucketAdminOpState& op_state);
+ static int remove_object(RGWRados *store, RGWBucketAdminOpState& op_state);
+ static int info(RGWRados *store, RGWBucketAdminOpState& op_state, RGWFormatterFlusher& flusher);
+};
+
+#endif
}
-req_state::req_state(CephContext *_cct, struct RGWEnv *e) : cct(_cct), cio(NULL), op(OP_UNKNOWN),
- bucket_cors(NULL), has_acl_header(false),
- os_auth_token(NULL),
- env(e)
+req_state::req_state(CephContext *_cct, struct RGWEnv *e) : cct(_cct), cio(NULL), op(OP_UNKNOWN),
+ bucket_cors(NULL), has_acl_header(false),
+ os_auth_token(NULL), env(e)
{
enable_ops_log = env->conf->enable_ops_log;
enable_usage_log = env->conf->enable_usage_log;
{
memset(t, 0, sizeof(*t));
const char *p = strptime(s, "%Y-%m-%dT%T", t);
-
if (!p) {
dout(0) << "parse_iso8601 failed" << dendl;
return false;
{
int pos = 0, fpos;
bool end = false;
+ bool admin_subresource_added = false;
if (str[pos] == '?') pos++;
while (!end) {
(name.compare("partNumber") == 0) ||
(name.compare("uploadId") == 0) ||
(name.compare("versionId") == 0) ||
- (name.compare("torrent") == 0) ||
- (name.compare("cors") == 0)) {
+ (name.compare("torrent") == 0)) {
sub_resources[name] = val;
} else if (name[0] == 'r') { // root of all evil
if ((name.compare("response-content-type") == 0) ||
sub_resources[name] = val;
has_resp_modifier = true;
}
+ } else if ((name.compare("subuser") == 0) ||
+ (name.compare("key") == 0) ||
+ (name.compare("caps") == 0) ||
+ (name.compare("index") == 0) ||
+ (name.compare("policy") == 0) ||
+ (name.compare("object") == 0)) {
+
+ if (!admin_subresource_added) {
+ sub_resources[name] = "";
+ admin_subresource_added = true;
+ }
}
}
#include "rgw_rest_swift.h"
#include "rgw_rest_admin.h"
#include "rgw_rest_usage.h"
+#include "rgw_rest_user.h"
+#include "rgw_rest_bucket.h"
#include "rgw_swift_auth.h"
#include "rgw_swift.h"
#include "rgw_log.h"
if (apis_map.count("admin") > 0) {
RGWRESTMgr_Admin *admin_resource = new RGWRESTMgr_Admin;
admin_resource->register_resource("usage", new RGWRESTMgr_Usage);
+ admin_resource->register_resource("user", new RGWRESTMgr_User);
+ admin_resource->register_resource("bucket", new RGWRESTMgr_Bucket);
rest.register_resource(g_conf->rgw_admin_entry, admin_resource);
}
#include "rgw_acl.h"
#include "rgw_acl_s3.h"
#include "rgw_user.h"
+#include "rgw_bucket.h"
#include "rgw_log.h"
#include "rgw_multi.h"
#include "rgw_multi_del.h"
#include "rgw_common.h"
#include "rgw_rados.h"
#include "rgw_user.h"
+#include "rgw_bucket.h"
#include "rgw_acl.h"
#include "rgw_cors.h"
return 0;
}
+
+int RGWRados::set_bucket_owner(rgw_bucket& bucket, ACLOwner& owner)
+{
+ RGWBucketInfo info;
+ map<string, bufferlist> attrs;
+ int r = get_bucket_info(NULL, bucket.name, info, &attrs);
+ if (r < 0) {
+ ldout(cct, 0) << "NOTICE: get_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl;
+ return r;
+ }
+
+ info.owner = owner.get_id();
+
+ r = put_bucket_info(bucket.name, info, false, &attrs);
+ if (r < 0) {
+ ldout(cct, 0) << "NOTICE: put_bucket_info on bucket=" << bucket.name << " returned err=" << r << dendl;
+ return r;
+ }
+
+ return 0;
+}
+
+
int RGWRados::set_buckets_enabled(vector<rgw_bucket>& buckets, bool enabled)
{
int ret = 0;
* Returns 0 on success, -ERR# otherwise.
*/ virtual int delete_bucket(rgw_bucket& bucket);
- virtual int set_buckets_enabled(std::vector<rgw_bucket>& buckets, bool enabled);
- virtual int bucket_suspended(rgw_bucket& bucket, bool *suspended);
+ int set_bucket_owner(rgw_bucket& bucket, ACLOwner& owner);
+ int set_buckets_enabled(std::vector<rgw_bucket>& buckets, bool enabled);
+ int bucket_suspended(rgw_bucket& bucket, bool *suspended);
/** Delete an object.*/
virtual int delete_obj(void *ctx, rgw_obj& src_obj);
return 0;
}
+int RESTArgs::get_uint32(struct req_state *s, const string& name, uint32_t def_val, uint32_t *val, bool *existed)
+{
+ bool exists;
+ string sval = s->args.get(name, &exists);
+
+ if (existed)
+ *existed = exists;
+
+ if (!exists) {
+ *val = def_val;
+ return 0;
+ }
+
+ int r = stringtoul(sval, val);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int RESTArgs::get_int32(struct req_state *s, const string& name, int32_t def_val, int32_t *val, bool *existed)
+{
+ bool exists;
+ string sval = s->args.get(name, &exists);
+
+ if (existed)
+ *existed = exists;
+
+ if (!exists) {
+ *val = def_val;
+ return 0;
+ }
+
+ int r = stringtol(sval, val);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int RESTArgs::get_time(struct req_state *s, const string& name, const utime_t& def_val, utime_t *val, bool *existed)
{
bool exists;
static int get_string(struct req_state *s, const string& name, const string& def_val, string *val, bool *existed = NULL);
static int get_uint64(struct req_state *s, const string& name, uint64_t def_val, uint64_t *val, bool *existed = NULL);
static int get_int64(struct req_state *s, const string& name, int64_t def_val, int64_t *val, bool *existed = NULL);
+ static int get_uint32(struct req_state *s, const string& name, uint32_t def_val, uint32_t *val, bool *existed = NULL);
+ static int get_int32(struct req_state *s, const string& name, int32_t def_val, int32_t *val, bool *existed = NULL);
static int get_time(struct req_state *s, const string& name, const utime_t& def_val, utime_t *val, bool *existed = NULL);
static int get_epoch(struct req_state *s, const string& name, uint64_t def_val, uint64_t *epoch, bool *existed = NULL);
static int get_bool(struct req_state *s, const string& name, bool def_val, bool *val, bool *existed = NULL);
--- /dev/null
+#include "rgw_op.h"
+#include "rgw_bucket.h"
+#include "rgw_rest_bucket.h"
+
+#include "include/str_list.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+class RGWOp_Bucket_Info : public RGWRESTOp {
+
+public:
+ RGWOp_Bucket_Info() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_READ);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "get_bucket_info"; }
+};
+
+void RGWOp_Bucket_Info::execute()
+{
+ RGWBucketAdminOpState op_state;
+
+ bool fetch_stats;
+
+ std::string uid;
+ std::string bucket;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+ RESTArgs::get_bool(s, "stats", false, &fetch_stats);
+
+
+ op_state.set_user_id(uid);
+ op_state.set_bucket_name(bucket);
+ op_state.set_fetch_stats(fetch_stats);
+
+ http_ret = RGWBucketAdminOp::info(store, op_state, flusher);
+}
+
+class RGWOp_Get_Policy : public RGWRESTOp {
+
+public:
+ RGWOp_Get_Policy() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_READ);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "get_policy"; }
+};
+
+void RGWOp_Get_Policy::execute()
+{
+ RGWBucketAdminOpState op_state;
+
+ std::string bucket;
+ std::string object;
+
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+ RESTArgs::get_string(s, "object", object, &object);
+
+ op_state.set_bucket_name(bucket);
+ op_state.set_object(object);
+
+ http_ret = RGWBucketAdminOp::get_policy(store, op_state, flusher);
+}
+
+class RGWOp_Check_Bucket_Index : public RGWRESTOp {
+
+public:
+ RGWOp_Check_Bucket_Index() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "check_bucket_index"; }
+};
+
+void RGWOp_Check_Bucket_Index::execute()
+{
+ std::string bucket;
+
+ bool fix_index;
+ bool check_objects;
+
+ RGWBucketAdminOpState op_state;
+
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+ RESTArgs::get_bool(s, "fix", false, &fix_index);
+ RESTArgs::get_bool(s, "check-objects", false, &check_objects);
+
+ op_state.set_bucket_name(bucket);
+ op_state.set_fix_index(fix_index);
+ op_state.set_check_objects(check_objects);
+
+ http_ret = RGWBucketAdminOp::check_index(store, op_state, flusher);
+}
+
+class RGWOp_Bucket_Link : public RGWRESTOp {
+
+public:
+ RGWOp_Bucket_Link() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "link_bucket"; }
+};
+
+void RGWOp_Bucket_Link::execute()
+{
+ std::string uid;
+ std::string bucket;
+
+ RGWBucketAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+
+ op_state.set_user_id(uid);
+ op_state.set_bucket_name(bucket);
+
+ http_ret = RGWBucketAdminOp::link(store, op_state);
+}
+
+class RGWOp_Bucket_Unlink : public RGWRESTOp {
+
+public:
+ RGWOp_Bucket_Unlink() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "unlink_bucket"; }
+};
+
+void RGWOp_Bucket_Unlink::execute()
+{
+ std::string uid;
+ std::string bucket;
+
+ RGWBucketAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+
+ op_state.set_user_id(uid);
+ op_state.set_bucket_name(bucket);
+
+ http_ret = RGWBucketAdminOp::unlink(store, op_state);
+}
+
+class RGWOp_Bucket_Remove : public RGWRESTOp {
+
+public:
+ RGWOp_Bucket_Remove() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "remove_bucket"; }
+};
+
+void RGWOp_Bucket_Remove::execute()
+{
+ std::string bucket;
+ bool delete_children;
+
+ RGWBucketAdminOpState op_state;
+
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+ RESTArgs::get_bool(s, "purge-objects", false, &delete_children);
+
+ op_state.set_bucket_name(bucket);
+ op_state.set_delete_children(delete_children);
+
+ http_ret = RGWBucketAdminOp::remove_bucket(store, op_state);
+}
+
+class RGWOp_Object_Remove: public RGWRESTOp {
+
+public:
+ RGWOp_Object_Remove() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("buckets", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "remove_object"; }
+};
+
+void RGWOp_Object_Remove::execute()
+{
+ std::string bucket;
+ std::string object;
+
+ RGWBucketAdminOpState op_state;
+
+ RESTArgs::get_string(s, "bucket", bucket, &bucket);
+ RESTArgs::get_string(s, "object", object, &object);
+
+ op_state.set_bucket_name(bucket);
+ op_state.set_object(object);
+
+ http_ret = RGWBucketAdminOp::remove_object(store, op_state);
+}
+
+RGWOp *RGWHandler_Bucket::op_get()
+{
+
+ if (s->args.sub_resource_exists("policy"))
+ return new RGWOp_Get_Policy;
+
+ if (s->args.sub_resource_exists("index"))
+ return new RGWOp_Check_Bucket_Index;
+
+ return new RGWOp_Bucket_Info;
+};
+
+RGWOp *RGWHandler_Bucket::op_put()
+{
+ return new RGWOp_Bucket_Link;
+};
+
+RGWOp *RGWHandler_Bucket::op_post()
+{
+ return new RGWOp_Bucket_Unlink;
+};
+
+RGWOp *RGWHandler_Bucket::op_delete()
+{
+ if (s->args.sub_resource_exists("object"))
+ return new RGWOp_Object_Remove;
+
+ return new RGWOp_Bucket_Remove;
+};
+
--- /dev/null
+#ifndef CEPH_RGW_REST_BUCKET_H
+#define CEPH_RGW_REST_BUCKET_H
+
+#include "rgw_rest.h"
+#include "rgw_rest_s3.h"
+
+
+class RGWHandler_Bucket : public RGWHandler_Auth_S3 {
+protected:
+ RGWOp *op_get();
+ RGWOp *op_put();
+ RGWOp *op_post();
+ RGWOp *op_delete();
+public:
+ RGWHandler_Bucket() {}
+ virtual ~RGWHandler_Bucket() {}
+
+ int read_permissions(RGWOp*) {
+ return 0;
+ }
+};
+
+class RGWRESTMgr_Bucket : public RGWRESTMgr {
+public:
+ RGWRESTMgr_Bucket() {}
+ virtual ~RGWRESTMgr_Bucket() {}
+
+ RGWHandler *get_handler(struct req_state *s) {
+ return new RGWHandler_Bucket;
+ }
+};
+
+#endif
return RGWHandler_ObjStore::init(store, s, cio);
}
+// subresources that we shouldn't include in the uri to sign
+static const char *nonsigned_subresources[] = {
+ "key",
+ "subuser",
+ "caps",
+ "index",
+ "object",
+ "policy",
+ NULL
+};
/*
* ?get the canonical amazon-style header for something?
string canon_resource;
get_canon_resource(s, canon_resource);
+
+ map<string, string> sub_resources = s->args.get_sub_resources();
+ map<string, string>::iterator sres_iter;
+
+ for (const char **sres = nonsigned_subresources; *sres; ++sres) {
+ sres_iter = sub_resources.find(*sres);
+ if (sres_iter != sub_resources.end()) {
+ size_t pos = canon_resource.find(*sres) -1;
+ size_t len = strlen(*sres) + 1;
+ std::string sres_val = sres_iter->second;
+ if (!sres_val.empty())
+ len += sres_val.size();
+ canon_resource.erase(pos, len);
+ }
+ }
+
dest.append(canon_resource);
return true;
--- /dev/null
+#include "rgw_op.h"
+#include "rgw_user.h"
+#include "rgw_rest_user.h"
+
+#include "include/str_list.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+class RGWOp_User_Info : public RGWRESTOp {
+
+public:
+ RGWOp_User_Info() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_READ);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "get_user_info"; }
+};
+
+void RGWOp_User_Info::execute()
+{
+ RGWUserAdminOpState op_state;
+
+ std::string uid;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+
+ op_state.set_user_id(uid);
+
+ http_ret = RGWUserAdminOp_User::info(store, op_state, flusher);
+}
+
+class RGWOp_User_Create : public RGWRESTOp {
+
+public:
+ RGWOp_User_Create() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "create_user"; }
+};
+
+void RGWOp_User_Create::execute()
+{
+ std::string uid;
+ std::string display_name;
+ std::string email;
+ std::string access_key;
+ std::string secret_key;
+ std::string key_type_str;
+ std::string caps;
+
+ bool gen_key;
+ bool suspended;
+
+ uint32_t max_buckets;
+ int32_t key_type = KEY_TYPE_UNDEFINED;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "display-name", display_name, &display_name);
+ RESTArgs::get_string(s, "email", email, &email);
+ RESTArgs::get_string(s, "access-key", access_key, &access_key);
+ RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
+ RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
+ RESTArgs::get_string(s, "user-caps", caps, &caps);
+ RESTArgs::get_bool(s, "generate-key", true, &gen_key);
+ RESTArgs::get_bool(s, "suspended", false, &suspended);
+ RESTArgs::get_uint32(s, "max-buckets", RGW_DEFAULT_MAX_BUCKETS, &max_buckets);
+
+ // FIXME: don't do double argument checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!display_name.empty())
+ op_state.set_display_name(display_name);
+
+ if (!email.empty())
+ op_state.set_user_email(email);
+
+ if (!caps.empty())
+ op_state.set_caps(caps);
+
+ if (!access_key.empty())
+ op_state.set_access_key(access_key);
+
+ if (!secret_key.empty())
+ op_state.set_secret_key(secret_key);
+
+ if (!key_type_str.empty()) {
+ if (key_type_str.compare("swift") == 0)
+ key_type = KEY_TYPE_SWIFT;
+ else if (key_type_str.compare("s3") == 0)
+ key_type = KEY_TYPE_S3;
+
+ op_state.set_key_type(key_type);
+ }
+
+ if (max_buckets != RGW_DEFAULT_MAX_BUCKETS)
+ op_state.set_max_buckets(max_buckets);
+
+ if (s->args.exists("suspended"))
+ op_state.set_suspension(suspended);
+
+ if (gen_key)
+ op_state.set_generate_key();
+
+ http_ret = RGWUserAdminOp_User::create(store, op_state, flusher);
+}
+
+class RGWOp_User_Modify : public RGWRESTOp {
+
+public:
+ RGWOp_User_Modify() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "modify_user"; }
+};
+
+void RGWOp_User_Modify::execute()
+{
+ std::string uid;
+ std::string display_name;
+ std::string email;
+ std::string access_key;
+ std::string secret_key;
+ std::string key_type_str;
+ std::string caps;
+
+ bool gen_key;
+ bool suspended;
+
+ uint32_t max_buckets;
+ int32_t key_type = KEY_TYPE_UNDEFINED;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "display-name", display_name, &display_name);
+ RESTArgs::get_string(s, "email", email, &email);
+ RESTArgs::get_string(s, "access-key", access_key, &access_key);
+ RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
+ RESTArgs::get_string(s, "user-caps", caps, &caps);
+ RESTArgs::get_bool(s, "generate-key", false, &gen_key);
+ RESTArgs::get_bool(s, "suspended", false, &suspended);
+ RESTArgs::get_uint32(s, "max-buckets", RGW_DEFAULT_MAX_BUCKETS, &max_buckets);
+ RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
+
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!display_name.empty())
+ op_state.set_display_name(display_name);
+
+ if (!email.empty())
+ op_state.set_user_email(email);
+
+ if (!caps.empty())
+ op_state.set_caps(caps);
+
+ if (!access_key.empty())
+ op_state.set_access_key(access_key);
+
+ if (!secret_key.empty())
+ op_state.set_secret_key(secret_key);
+
+ if (max_buckets != RGW_DEFAULT_MAX_BUCKETS)
+ op_state.set_max_buckets(max_buckets);
+
+ if (gen_key)
+ op_state.set_generate_key();
+
+ if (!key_type_str.empty()) {
+ if (key_type_str.compare("swift") == 0)
+ key_type = KEY_TYPE_SWIFT;
+ else if (key_type_str.compare("s3") == 0)
+ key_type = KEY_TYPE_S3;
+
+ op_state.set_key_type(key_type);
+ }
+
+ if (s->args.exists("suspended"))
+ op_state.set_suspension(suspended);
+
+ http_ret = RGWUserAdminOp_User::modify(store, op_state, flusher);
+}
+
+class RGWOp_User_Remove : public RGWRESTOp {
+
+public:
+ RGWOp_User_Remove() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "remove_user"; }
+};
+
+void RGWOp_User_Remove::execute()
+{
+ std::string uid;
+ bool purge_data;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_bool(s, "purge-data", false, &purge_data);
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ op_state.set_purge_data(purge_data);
+
+ http_ret = RGWUserAdminOp_User::remove(store, op_state, flusher);
+}
+
+class RGWOp_Subuser_Create : public RGWRESTOp {
+
+public:
+ RGWOp_Subuser_Create() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "create_subuser"; }
+};
+
+void RGWOp_Subuser_Create::execute()
+{
+ std::string uid;
+ std::string subuser;
+ std::string secret_key;
+ std::string perm_str;
+ std::string key_type_str;
+
+ bool gen_subuser = false; // FIXME placeholder
+ bool gen_secret;
+
+ uint32_t perm_mask = 0;
+ int32_t key_type = KEY_TYPE_SWIFT;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "subuser", subuser, &subuser);
+ RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
+ RESTArgs::get_string(s, "access", perm_str, &perm_str);
+ RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
+ //RESTArgs::get_bool(s, "generate-subuser", false, &gen_subuser);
+ RESTArgs::get_bool(s, "generate-secret", false, &gen_secret);
+
+ perm_mask = rgw_str_to_perm(perm_str.c_str());
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!subuser.empty())
+ op_state.set_subuser(subuser);
+
+ if (!secret_key.empty())
+ op_state.set_secret_key(secret_key);
+
+ if (perm_mask != 0)
+ op_state.set_perm(perm_mask);
+
+ op_state.set_generate_subuser(gen_subuser);
+
+ if (gen_secret)
+ op_state.set_gen_secret();
+
+ if (!key_type_str.empty()) {
+ if (key_type_str.compare("swift") == 0)
+ key_type = KEY_TYPE_SWIFT;
+ else if (key_type_str.compare("s3") == 0)
+ key_type = KEY_TYPE_S3;
+ }
+ op_state.set_key_type(key_type);
+
+ http_ret = RGWUserAdminOp_Subuser::create(store, op_state, flusher);
+}
+
+class RGWOp_Subuser_Modify : public RGWRESTOp {
+
+public:
+ RGWOp_Subuser_Modify() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "modify_subuser"; }
+};
+
+void RGWOp_Subuser_Modify::execute()
+{
+ std::string uid;
+ std::string subuser;
+ std::string secret_key;
+ std::string key_type_str;
+ std::string perm_str;
+
+ RGWUserAdminOpState op_state;
+
+ uint32_t perm_mask;
+ int32_t key_type = KEY_TYPE_SWIFT;
+
+ bool gen_secret;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "subuser", subuser, &subuser);
+ RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
+ RESTArgs::get_string(s, "access", perm_str, &perm_str);
+ RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
+ RESTArgs::get_bool(s, "generate-secret", false, &gen_secret);
+
+ perm_mask = rgw_str_to_perm(perm_str.c_str());
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!subuser.empty())
+ op_state.set_subuser(subuser);
+
+ if (!secret_key.empty())
+ op_state.set_secret_key(secret_key);
+
+ if (gen_secret)
+ op_state.set_gen_secret();
+
+ if (perm_mask != 0)
+ op_state.set_perm(perm_mask);
+
+ if (!key_type_str.empty()) {
+ if (key_type_str.compare("swift") == 0)
+ key_type = KEY_TYPE_SWIFT;
+ else if (key_type_str.compare("s3") == 0)
+ key_type = KEY_TYPE_S3;
+ }
+ op_state.set_key_type(key_type);
+
+ http_ret = RGWUserAdminOp_Subuser::modify(store, op_state, flusher);
+}
+
+class RGWOp_Subuser_Remove : public RGWRESTOp {
+
+public:
+ RGWOp_Subuser_Remove() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "remove_subuser"; }
+};
+
+void RGWOp_Subuser_Remove::execute()
+{
+ std::string uid;
+ std::string subuser;
+ bool purge_keys;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "subuser", subuser, &subuser);
+ RESTArgs::get_bool(s, "purge-keys", true, &purge_keys);
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!subuser.empty())
+ op_state.set_subuser(subuser);
+
+ if (purge_keys)
+ op_state.set_purge_keys();
+
+ http_ret = RGWUserAdminOp_Subuser::remove(store, op_state, flusher);
+}
+
+class RGWOp_Key_Create : public RGWRESTOp {
+
+public:
+ RGWOp_Key_Create() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "create_access_key"; }
+};
+
+void RGWOp_Key_Create::execute()
+{
+ std::string uid;
+ std::string subuser;
+ std::string access_key;
+ std::string secret_key;
+ std::string key_type_str;
+
+ int32_t key_type = KEY_TYPE_UNDEFINED;
+ bool gen_key;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "subuser", subuser, &subuser);
+ RESTArgs::get_string(s, "access-key", access_key, &access_key);
+ RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
+ RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
+ RESTArgs::get_bool(s, "generate-key", true, &gen_key);
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!subuser.empty())
+ op_state.set_subuser(subuser);
+
+ if (!access_key.empty())
+ op_state.set_access_key(access_key);
+
+ if (!secret_key.empty())
+ op_state.set_secret_key(secret_key);
+
+ if (gen_key)
+ op_state.set_generate_key();
+
+ if (!key_type_str.empty()) {
+ if (key_type_str.compare("swift") == 0)
+ key_type = KEY_TYPE_SWIFT;
+ else if (key_type_str.compare("s3") == 0)
+ key_type = KEY_TYPE_S3;
+
+ op_state.set_key_type(key_type);
+ }
+
+ http_ret = RGWUserAdminOp_Key::create(store, op_state, flusher);
+}
+
+class RGWOp_Key_Remove : public RGWRESTOp {
+
+public:
+ RGWOp_Key_Remove() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "remove_access_key"; }
+};
+
+void RGWOp_Key_Remove::execute()
+{
+ std::string uid;
+ std::string subuser;
+ std::string access_key;
+ std::string key_type_str;
+
+ int32_t key_type = KEY_TYPE_UNDEFINED;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "subuser", subuser, &subuser);
+ RESTArgs::get_string(s, "access-key", access_key, &access_key);
+ RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!subuser.empty())
+ op_state.set_subuser(subuser);
+
+ if (!access_key.empty())
+ op_state.set_access_key(access_key);
+
+ if (!key_type_str.empty()) {
+ if (key_type_str.compare("swift") == 0)
+ key_type = KEY_TYPE_SWIFT;
+ else if (key_type_str.compare("s3") == 0)
+ key_type = KEY_TYPE_S3;
+
+ op_state.set_key_type(key_type);
+ }
+
+ http_ret = RGWUserAdminOp_Key::remove(store, op_state, flusher);
+}
+
+class RGWOp_Caps_Add : public RGWRESTOp {
+
+public:
+ RGWOp_Caps_Add() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "add_user_caps"; }
+};
+
+void RGWOp_Caps_Add::execute()
+{
+ std::string uid;
+ std::string caps;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "user-caps", caps, &caps);
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!caps.empty())
+ op_state.set_caps(caps);
+
+ http_ret = RGWUserAdminOp_Caps::add(store, op_state, flusher);
+}
+
+class RGWOp_Caps_Remove : public RGWRESTOp {
+
+public:
+ RGWOp_Caps_Remove() {}
+
+ int check_caps(RGWUserCaps& caps) {
+ return caps.check_cap("users", RGW_CAP_WRITE);
+ }
+
+ void execute();
+
+ virtual const char *name() { return "remove_user_caps"; }
+};
+
+void RGWOp_Caps_Remove::execute()
+{
+ std::string uid;
+ std::string caps;
+
+ RGWUserAdminOpState op_state;
+
+ RESTArgs::get_string(s, "uid", uid, &uid);
+ RESTArgs::get_string(s, "user-caps", caps, &caps);
+
+ // FIXME: no double checking
+ if (!uid.empty())
+ op_state.set_user_id(uid);
+
+ if (!caps.empty())
+ op_state.set_caps(caps);
+
+ http_ret = RGWUserAdminOp_Caps::remove(store, op_state, flusher);
+}
+
+RGWOp *RGWHandler_User::op_get()
+{
+ return new RGWOp_User_Info;
+};
+
+RGWOp *RGWHandler_User::op_put()
+{
+ if (s->args.sub_resource_exists("subuser"))
+ return new RGWOp_Subuser_Create;
+
+ if (s->args.sub_resource_exists("key"))
+ return new RGWOp_Key_Create;
+
+ if (s->args.sub_resource_exists("caps"))
+ return new RGWOp_Caps_Add;
+
+ return new RGWOp_User_Create;
+};
+
+RGWOp *RGWHandler_User::op_post()
+{
+ if (s->args.sub_resource_exists("subuser"))
+ return new RGWOp_Subuser_Modify;
+
+ return new RGWOp_User_Modify;
+};
+
+RGWOp *RGWHandler_User::op_delete()
+{
+ if (s->args.sub_resource_exists("subuser"))
+ return new RGWOp_Subuser_Remove;
+
+ if (s->args.sub_resource_exists("key"))
+ return new RGWOp_Key_Remove;
+
+ if (s->args.sub_resource_exists("caps"))
+ return new RGWOp_Caps_Remove;
+
+ return new RGWOp_User_Remove;
+};
+
--- /dev/null
+#ifndef CEPH_RGW_REST_USER_H
+#define CEPH_RGW_REST_USER_H
+
+#include "rgw_rest.h"
+#include "rgw_rest_s3.h"
+
+
+class RGWHandler_User : public RGWHandler_Auth_S3 {
+protected:
+ RGWOp *op_get();
+ RGWOp *op_put();
+ RGWOp *op_post();
+ RGWOp *op_delete();
+public:
+ RGWHandler_User() {}
+ virtual ~RGWHandler_User() {}
+
+ int read_permissions(RGWOp*) {
+ return 0;
+ }
+};
+
+class RGWRESTMgr_User : public RGWRESTMgr {
+public:
+ RGWRESTMgr_User() {}
+ virtual ~RGWRESTMgr_User() {}
+
+ RGWHandler *get_handler(struct req_state *s) {
+ return new RGWHandler_User;
+ }
+};
+
+#endif
#include "include/types.h"
#include "rgw_user.h"
+#include "rgw_string.h"
+
+// until everything is moved from rgw_common
+#include "rgw_common.h"
+
+#include "rgw_bucket.h"
#define dout_subsys ceph_subsys_rgw
if (ret < 0)
return ret;
- if (info.user_email.size()) {
+ if (!info.user_email.empty()) {
if (!old_info ||
old_info->user_email.compare(info.user_email) != 0) { /* only if new index changed */
ret = rgw_put_system_obj(store, store->zone.user_email_pool, info.user_email, link_bl.c_str(), link_bl.length(), exclusive);
return rgw_get_user_info_from_index(store, access_key, store->zone.user_keys_pool, info);
}
-static void get_buckets_obj(string& user_id, string& buckets_obj_id)
-{
- buckets_obj_id = user_id;
- buckets_obj_id += RGW_BUCKETS_OBJ_PREFIX;
-}
-
-static int rgw_read_buckets_from_attr(RGWRados *store, string& user_id, RGWUserBuckets& buckets)
-{
- bufferlist bl;
- rgw_obj obj(store->zone.user_uid_pool, user_id);
- int ret = store->get_attr(NULL, obj, RGW_ATTR_BUCKETS, bl);
- if (ret)
- return ret;
-
- bufferlist::iterator iter = bl.begin();
- try {
- buckets.decode(iter);
- } catch (buffer::error& err) {
- ldout(store->ctx(), 0) << "ERROR: failed to decode buckets info, caught buffer::error" << dendl;
- return -EIO;
- }
- return 0;
-}
-
-/**
- * Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
- * Returns: 0 on success, -ERR# on failure.
- */
-int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, bool need_stats)
-{
- int ret;
- buckets.clear();
- if (store->supports_omap()) {
- string buckets_obj_id;
- get_buckets_obj(user_id, buckets_obj_id);
- bufferlist bl;
- rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id);
- bufferlist header;
- map<string,bufferlist> m;
-
- ret = store->omap_get_all(obj, header, m);
- if (ret == -ENOENT)
- ret = 0;
-
- if (ret < 0)
- return ret;
-
- for (map<string,bufferlist>::iterator q = m.begin(); q != m.end(); ++q) {
- bufferlist::iterator iter = q->second.begin();
- RGWBucketEnt bucket;
- ::decode(bucket, iter);
- buckets.add(bucket);
- }
- } else {
- ret = rgw_read_buckets_from_attr(store, user_id, buckets);
- switch (ret) {
- case 0:
- break;
- case -ENODATA:
- ret = 0;
- return 0;
- default:
- return ret;
- }
- }
-
- if (need_stats) {
- map<string, RGWBucketEnt>& m = buckets.get_buckets();
- int r = store->update_containers_stats(m);
- if (r < 0)
- ldout(store->ctx(), 0) << "ERROR: could not get stats for buckets" << dendl;
-
- }
- return 0;
-}
-
-/**
- * Store the set of buckets associated with a user on a n xattr
- * not used with all backends
- * This completely overwrites any previously-stored list, so be careful!
- * Returns 0 on success, -ERR# otherwise.
- */
-int rgw_write_buckets_attr(RGWRados *store, string user_id, RGWUserBuckets& buckets)
-{
- bufferlist bl;
- buckets.encode(bl);
-
- rgw_obj obj(store->zone.user_uid_pool, user_id);
-
- int ret = store->set_attr(NULL, obj, RGW_ATTR_BUCKETS, bl);
-
- return ret;
-}
-
-int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket)
-{
- int ret;
- string& bucket_name = bucket.name;
-
- if (store->supports_omap()) {
- bufferlist bl;
-
- RGWBucketEnt new_bucket;
- new_bucket.bucket = bucket;
- new_bucket.size = 0;
- time(&new_bucket.mtime);
- ::encode(new_bucket, bl);
-
- string buckets_obj_id;
- get_buckets_obj(user_id, buckets_obj_id);
-
- rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id);
- ret = store->omap_set(obj, bucket_name, bl);
- if (ret < 0) {
- ldout(store->ctx(), 0) << "ERROR: error adding bucket to directory: "
- << cpp_strerror(-ret)<< dendl;
- }
- } else {
- RGWUserBuckets buckets;
-
- ret = rgw_read_user_buckets(store, user_id, buckets, false);
- RGWBucketEnt new_bucket;
-
- switch (ret) {
- case 0:
- case -ENOENT:
- case -ENODATA:
- new_bucket.bucket = bucket;
- new_bucket.size = 0;
- time(&new_bucket.mtime);
- buckets.add(new_bucket);
- ret = rgw_write_buckets_attr(store, user_id, buckets);
- break;
- default:
- ldout(store->ctx(), 10) << "rgw_write_buckets_attr returned " << ret << dendl;
- break;
- }
- }
-
- return ret;
-}
-
-int rgw_remove_user_bucket_info(RGWRados *store, string user_id, rgw_bucket& bucket)
-{
- int ret;
-
- if (store->supports_omap()) {
- bufferlist bl;
-
- string buckets_obj_id;
- get_buckets_obj(user_id, buckets_obj_id);
-
- rgw_obj obj(store->zone.user_uid_pool, buckets_obj_id);
- ret = store->omap_del(obj, bucket.name);
- if (ret < 0) {
- ldout(store->ctx(), 0) << "ERROR: error removing bucket from directory: "
- << cpp_strerror(-ret)<< dendl;
- }
- } else {
- RGWUserBuckets buckets;
-
- ret = rgw_read_user_buckets(store, user_id, buckets, false);
-
- if (ret == 0 || ret == -ENOENT) {
- buckets.remove(bucket.name);
- ret = rgw_write_buckets_attr(store, user_id, buckets);
- }
- }
-
- return ret;
-}
-
int rgw_remove_key_index(RGWRados *store, RGWAccessKey& access_key)
{
rgw_obj obj(store->zone.user_keys_pool, access_key.id);
map<string, RGWBucketEnt>& buckets = user_buckets.get_buckets();
vector<rgw_bucket> buckets_vec;
for (map<string, RGWBucketEnt>::iterator i = buckets.begin();
- i != buckets.end();
- ++i) {
+ i != buckets.end();
+ ++i) {
RGWBucketEnt& bucket = i->second;
buckets_vec.push_back(bucket.bucket);
}
}
string buckets_obj_id;
- get_buckets_obj(info.user_id, buckets_obj_id);
+ rgw_get_buckets_obj(info.user_id, buckets_obj_id);
rgw_obj uid_bucks(store->zone.user_uid_pool, buckets_obj_id);
ldout(store->ctx(), 10) << "removing user buckets index" << dendl;
ret = store->delete_obj(NULL, uid_bucks);
return 0;
}
+
+static bool char_is_unreserved_url(char c)
+{
+ if (isalnum(c))
+ return true;
+
+ switch (c) {
+ case '-':
+ case '.':
+ case '_':
+ case '~':
+ return true;
+ default:
+ return false;
+ }
+}
+
+struct rgw_flags_desc {
+ uint32_t mask;
+ const char *str;
+};
+
+static struct rgw_flags_desc rgw_perms[] = {
+ { RGW_PERM_FULL_CONTROL, "full-control" },
+ { RGW_PERM_READ | RGW_PERM_WRITE, "read-write" },
+ { RGW_PERM_READ, "read" },
+ { RGW_PERM_WRITE, "write" },
+ { RGW_PERM_READ_ACP, "read-acp" },
+ { RGW_PERM_WRITE_ACP, "read-acp" },
+ { 0, NULL }
+};
+
+void rgw_perm_to_str(uint32_t mask, char *buf, int len)
+{
+ const char *sep = "";
+ int pos = 0;
+ if (!mask) {
+ snprintf(buf, len, "<none>");
+ return;
+ }
+ while (mask) {
+ uint32_t orig_mask = mask;
+ for (int i = 0; rgw_perms[i].mask; i++) {
+ struct rgw_flags_desc *desc = &rgw_perms[i];
+ if ((mask & desc->mask) == desc->mask) {
+ pos += snprintf(buf + pos, len - pos, "%s%s", sep, desc->str);
+ if (pos == len)
+ return;
+ sep = ", ";
+ mask &= ~desc->mask;
+ if (!mask)
+ return;
+ }
+ }
+ if (mask == orig_mask) // no change
+ break;
+ }
+}
+
+uint32_t rgw_str_to_perm(const char *str)
+{
+ if (strcasecmp(str, "read") == 0)
+ return RGW_PERM_READ;
+ else if (strcasecmp(str, "write") == 0)
+ return RGW_PERM_WRITE;
+ else if (strcasecmp(str, "readwrite") == 0)
+ return RGW_PERM_READ | RGW_PERM_WRITE;
+ else if (strcasecmp(str, "full") == 0)
+ return RGW_PERM_FULL_CONTROL;
+
+ return 0; // better to return no permission
+}
+
+static bool validate_access_key(string& key)
+{
+ const char *p = key.c_str();
+ while (*p) {
+ if (!char_is_unreserved_url(*p))
+ return false;
+ p++;
+ }
+ return true;
+}
+
+static void set_err_msg(std::string *sink, std::string msg)
+{
+ if (sink && !msg.empty())
+ *sink = msg;
+}
+
+static bool remove_old_indexes(RGWRados *store,
+ RGWUserInfo& old_info, RGWUserInfo& new_info, std::string *err_msg)
+{
+ int ret;
+ bool success = true;
+
+ if (!old_info.user_id.empty() && old_info.user_id.compare(new_info.user_id) != 0) {
+ ret = rgw_remove_uid_index(store, old_info.user_id);
+ if (ret < 0 && ret != -ENOENT) {
+ set_err_msg(err_msg, "ERROR: could not remove index for uid " + old_info.user_id);
+ success = false;
+ }
+ }
+
+ if (!old_info.user_email.empty() &&
+ old_info.user_email.compare(new_info.user_email) != 0) {
+ ret = rgw_remove_email_index(store, old_info.user_email);
+ if (ret < 0 && ret != -ENOENT) {
+ set_err_msg(err_msg, "ERROR: could not remove index for email " + old_info.user_email);
+ success = false;
+ }
+ }
+
+ map<string, RGWAccessKey>::iterator old_iter;
+ for (old_iter = old_info.swift_keys.begin(); old_iter != old_info.swift_keys.end(); ++old_iter) {
+ RGWAccessKey& swift_key = old_iter->second;
+ map<string, RGWAccessKey>::iterator new_iter = new_info.swift_keys.find(swift_key.id);
+ if (new_iter == new_info.swift_keys.end()) {
+ ret = rgw_remove_swift_name_index(store, swift_key.id);
+ if (ret < 0 && ret != -ENOENT) {
+ set_err_msg(err_msg, "ERROR: could not remove index for swift_name " + swift_key.id);
+ success = false;
+ }
+ }
+ }
+
+ return success;
+}
+
+/*
+ * Dump either the full user info or a subset to a formatter.
+ *
+ * NOTE: It is the caller's respnsibility to ensure that the
+ * formatter is flushed at the correct time.
+ */
+
+
+static void dump_subusers_info(Formatter *f, RGWUserInfo &info)
+{
+ map<string, RGWSubUser>::iterator uiter;
+
+ f->open_array_section("subusers");
+ for (uiter = info.subusers.begin(); uiter != info.subusers.end(); ++uiter) {
+ RGWSubUser& u = uiter->second;
+ f->open_object_section("user");
+ f->dump_format("id", "%s:%s", info.user_id.c_str(), u.name.c_str());
+ char buf[256];
+ rgw_perm_to_str(u.perm_mask, buf, sizeof(buf));
+ f->dump_string("permissions", buf);
+ f->close_section();
+ }
+ f->close_section();
+}
+
+static void dump_access_keys_info(Formatter *f, RGWUserInfo &info)
+{
+ map<string, RGWAccessKey>::iterator kiter;
+ f->open_array_section("keys");
+ for (kiter = info.access_keys.begin(); kiter != info.access_keys.end(); ++kiter) {
+ RGWAccessKey& k = kiter->second;
+ const char *sep = (k.subuser.empty() ? "" : ":");
+ const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str());
+ f->open_object_section("key");
+ f->dump_format("user", "%s%s%s", info.user_id.c_str(), sep, subuser);
+ f->dump_string("access_key", k.id);
+ f->dump_string("secret_key", k.key);
+ f->close_section();
+ }
+ f->close_section();
+}
+
+static void dump_swift_keys_info(Formatter *f, RGWUserInfo &info)
+{
+ map<string, RGWAccessKey>::iterator kiter;
+ f->open_array_section("swift_keys");
+ for (kiter = info.swift_keys.begin(); kiter != info.swift_keys.end(); ++kiter) {
+ RGWAccessKey& k = kiter->second;
+ const char *sep = (k.subuser.empty() ? "" : ":");
+ const char *subuser = (k.subuser.empty() ? "" : k.subuser.c_str());
+ f->open_object_section("key");
+ f->dump_format("user", "%s%s%s", info.user_id.c_str(), sep, subuser);
+ f->dump_string("secret_key", k.key);
+ f->close_section();
+ }
+ f->close_section();
+}
+
+static void dump_user_info(Formatter *f, RGWUserInfo &info)
+{
+ f->open_object_section("user_info");
+
+ f->dump_string("user_id", info.user_id);
+ f->dump_string("display_name", info.display_name);
+ f->dump_string("email", info.user_email);
+ f->dump_int("suspended", (int)info.suspended);
+ f->dump_int("max_buckets", (int)info.max_buckets);
+
+ dump_subusers_info(f, info);
+ dump_access_keys_info(f, info);
+ dump_swift_keys_info(f, info);
+ info.caps.dump(f);
+
+ f->close_section();
+}
+
+
+RGWAccessKeyPool::RGWAccessKeyPool(RGWUser* usr)
+{
+ user = usr;
+
+ if (!user) {
+ keys_allowed = false;
+ return;
+ }
+
+ keys_allowed = true;
+
+ store = user->get_store();
+}
+
+RGWAccessKeyPool::~RGWAccessKeyPool()
+{
+
+}
+
+int RGWAccessKeyPool::init(RGWUserAdminOpState& op_state)
+{
+ if (!op_state.is_initialized()) {
+ keys_allowed = false;
+ return -EINVAL;
+ }
+
+ std::string uid = op_state.get_user_id();
+ if (uid.compare(RGW_USER_ANON_ID) == 0) {
+ keys_allowed = false;
+ return -EACCES;
+ }
+
+ swift_keys = op_state.get_swift_keys();
+ access_keys = op_state.get_access_keys();
+
+ keys_allowed = true;
+
+ return 0;
+}
+
+/*
+ * Do a fairly exhaustive search for an existing key matching the parameters
+ * given. Also handles the case where no key type was specified and updates
+ * the operation state if needed.
+ */
+
+bool RGWAccessKeyPool::check_existing_key(RGWUserAdminOpState& op_state)
+{
+ bool existing_key = false;
+
+ int key_type = op_state.get_key_type();
+ std::string kid = op_state.get_access_key();
+ std::map<std::string, RGWAccessKey>::iterator kiter;
+ std::string swift_kid = op_state.build_default_swift_kid();
+
+ RGWUserInfo dup_info;
+
+ if (kid.empty() && swift_kid.empty())
+ return false;
+
+ switch (key_type) {
+ case KEY_TYPE_SWIFT:
+ kiter = swift_keys->find(kid);
+
+ existing_key = (kiter != swift_keys->end());
+ if (existing_key)
+ break;
+
+ if (swift_kid.empty())
+ return false;
+
+ kiter = swift_keys->find(swift_kid);
+
+ existing_key = (kiter != swift_keys->end());
+ if (existing_key)
+ op_state.set_access_key(swift_kid);
+
+ break;
+ case KEY_TYPE_S3:
+ kiter = access_keys->find(kid);
+ existing_key = (kiter != access_keys->end());
+
+ break;
+ default:
+ kiter = access_keys->find(kid);
+
+ existing_key = (kiter != access_keys->end());
+ if (existing_key) {
+ op_state.set_key_type(KEY_TYPE_S3);
+ break;
+ }
+
+ kiter = swift_keys->find(kid);
+
+ existing_key = (kiter != swift_keys->end());
+ if (existing_key) {
+ op_state.set_key_type(KEY_TYPE_SWIFT);
+ break;
+ }
+
+ // handle the case where the access key was not provided in user:key format
+ if (swift_kid.empty())
+ return false;
+
+ kiter = swift_keys->find(swift_kid);
+
+ existing_key = (kiter != swift_keys->end());
+ if (existing_key) {
+ op_state.set_access_key(swift_kid);
+ op_state.set_key_type(KEY_TYPE_SWIFT);
+ }
+ }
+
+ op_state.set_existing_key(existing_key);
+
+ return existing_key;
+}
+
+int RGWAccessKeyPool::check_op(RGWUserAdminOpState& op_state,
+ std::string *err_msg)
+{
+ std::string subprocess_msg;
+ RGWUserInfo dup_info;
+
+ if (!op_state.is_populated()) {
+ set_err_msg(err_msg, "user info was not populated");
+ return -EINVAL;
+ }
+
+ if (!keys_allowed) {
+ set_err_msg(err_msg, "keys not allowed for this user");
+ return -EACCES;
+ }
+
+ std::string access_key = op_state.get_access_key();
+ std::string secret_key = op_state.get_secret_key();
+
+ /* see if the access key or secret key was specified */
+ if (!op_state.will_gen_access() && access_key.empty()) {
+ set_err_msg(err_msg, "empty access key");
+ return -EINVAL;
+ }
+
+ // don't check for secret key because we may be doing a removal
+
+ check_existing_key(op_state);
+
+ // if a key type wasn't specified set it to s3
+ if (op_state.get_key_type() < 0)
+ op_state.set_key_type(KEY_TYPE_S3);
+
+ return 0;
+}
+
+// Generate a new random key
+int RGWAccessKeyPool::generate_key(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string duplicate_check_id;
+ std::string id;
+ std::string key;
+
+ std::pair<std::string, RGWAccessKey> key_pair;
+ RGWAccessKey new_key;
+ RGWUserInfo duplicate_check;
+
+ int ret = 0;
+ int key_type = op_state.get_key_type();
+ bool gen_access = op_state.will_gen_access();
+ bool gen_secret = op_state.will_gen_secret();
+ std::string subuser = op_state.get_subuser();
+
+ if (!keys_allowed) {
+ set_err_msg(err_msg, "access keys not allowed for this user");
+ return -EACCES;
+ }
+
+ if (op_state.has_existing_key()) {
+ set_err_msg(err_msg, "cannot create existing key");
+ return -EEXIST;
+ }
+
+ if (!gen_access) {
+ id = op_state.get_access_key();
+ }
+
+ if (!id.empty()) {
+ switch (key_type) {
+ case KEY_TYPE_SWIFT:
+ if (rgw_get_user_info_by_swift(store, id, duplicate_check) >= 0) {
+ set_err_msg(err_msg, "existing swift key in RGW system:" + id);
+ return -EEXIST;
+ }
+ case KEY_TYPE_S3:
+ if (rgw_get_user_info_by_access_key(store, id, duplicate_check) >= 0) {
+ set_err_msg(err_msg, "existing S3 key in RGW system:" + id);
+ return -EEXIST;
+ }
+ }
+ }
+
+ if (op_state.has_subuser())
+ new_key.subuser = op_state.get_subuser();
+
+ if (!gen_secret) {
+ key = op_state.get_secret_key();
+ } else if (gen_secret) {
+ char secret_key_buf[SECRET_KEY_LEN + 1];
+
+ ret = gen_rand_base64(g_ceph_context, secret_key_buf, sizeof(secret_key_buf));
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to generate secret key");
+ return ret;
+ }
+
+ key = secret_key_buf;
+ }
+
+ // Generate the access key
+ if (key_type == KEY_TYPE_S3 && gen_access) {
+ char public_id_buf[PUBLIC_ID_LEN + 1];
+
+ do {
+ int id_buf_size = sizeof(public_id_buf);
+ ret = gen_rand_alphanumeric_upper(g_ceph_context,
+ public_id_buf, id_buf_size);
+
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to generate access key");
+ return ret;
+ }
+
+ id = public_id_buf;
+ if (!validate_access_key(id))
+ continue;
+
+ } while (!rgw_get_user_info_by_access_key(store, id, duplicate_check));
+ }
+
+ if (key_type == KEY_TYPE_SWIFT && gen_access) {
+ id = op_state.build_default_swift_kid();
+ if (id.empty()) {
+ set_err_msg(err_msg, "empty swift access key");
+ return -EINVAL;
+ }
+
+ // check that the access key doesn't exist
+ if (rgw_get_user_info_by_swift(store, id, duplicate_check) >= 0) {
+ set_err_msg(err_msg, "cannot create existing swift key");
+ return -EEXIST;
+ }
+ }
+
+ // finally create the new key
+ new_key.id = id;
+ new_key.key = key;
+
+ key_pair.first = id;
+ key_pair.second = new_key;
+
+ if (key_type == KEY_TYPE_S3) {
+ access_keys->insert(key_pair);
+ } else if (key_type == KEY_TYPE_SWIFT) {
+ swift_keys->insert(key_pair);
+ }
+
+ return 0;
+}
+
+// modify an existing key
+int RGWAccessKeyPool::modify_key(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string id = op_state.get_access_key();
+ std::string key = op_state.get_secret_key();
+ int key_type = op_state.get_key_type();
+
+ RGWAccessKey modify_key;
+
+ pair<string, RGWAccessKey> key_pair;
+ map<std::string, RGWAccessKey>::iterator kiter;
+
+ if (id.empty()) {
+ set_err_msg(err_msg, "no access key specified");
+ return -EINVAL;
+ }
+
+ if (!op_state.has_existing_key()) {
+ set_err_msg(err_msg, "key does not exist");
+ return -EINVAL;
+ }
+
+ key_pair.first = id;
+
+ if (key_type == KEY_TYPE_SWIFT) {
+ kiter = swift_keys->find(id);
+ modify_key = kiter->second;
+ } else if (key_type == KEY_TYPE_S3) {
+ kiter = access_keys->find(id);
+ modify_key = kiter->second;
+ } else {
+ set_err_msg(err_msg, "invalid key type");
+ return -EINVAL;
+ }
+
+ if (op_state.will_gen_secret()) {
+ char secret_key_buf[SECRET_KEY_LEN + 1];
+
+ int ret;
+ int key_buf_size = sizeof(secret_key_buf);
+ ret = gen_rand_base64(g_ceph_context, secret_key_buf, key_buf_size);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to generate secret key");
+ return ret;
+ }
+
+ key = secret_key_buf;
+ }
+
+ if (key.empty()) {
+ set_err_msg(err_msg, "empty secret key");
+ return -EINVAL;
+ }
+
+ // update the access key with the new secret key
+ modify_key.key = key;
+
+ key_pair.second = modify_key;
+
+
+ if (key_type == KEY_TYPE_S3) {
+ (*access_keys)[id] = modify_key;
+ } else if (key_type == KEY_TYPE_SWIFT) {
+ (*swift_keys)[id] = modify_key;
+ }
+
+ return 0;
+}
+
+int RGWAccessKeyPool::execute_add(RGWUserAdminOpState& op_state,
+ std::string *err_msg, bool defer_user_update)
+{
+ int ret = 0;
+
+ std::string subprocess_msg;
+ int key_op = GENERATE_KEY;
+
+ // set the op
+ if (op_state.has_existing_key())
+ key_op = MODIFY_KEY;
+
+ switch (key_op) {
+ case GENERATE_KEY:
+ ret = generate_key(op_state, &subprocess_msg);
+ break;
+ case MODIFY_KEY:
+ ret = modify_key(op_state, &subprocess_msg);
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ // store the updated info
+ if (!defer_user_update)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWAccessKeyPool::add(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return add(op_state, err_msg, false);
+}
+
+int RGWAccessKeyPool::add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ int ret;
+ std::string subprocess_msg;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse request, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_add(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to add access key, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWAccessKeyPool::execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ int ret = 0;
+
+ int key_type = op_state.get_key_type();
+ std::string id = op_state.get_access_key();
+ map<std::string, RGWAccessKey>::iterator kiter;
+ map<std::string, RGWAccessKey> *keys_map;
+
+ if (!op_state.has_existing_key()) {
+ set_err_msg(err_msg, "unable to find access key");
+ return -EINVAL;
+ }
+
+ if (key_type == KEY_TYPE_S3) {
+ keys_map = access_keys;
+ } else if (key_type == KEY_TYPE_SWIFT) {
+ keys_map = swift_keys;
+ } else {
+ keys_map = NULL;
+ set_err_msg(err_msg, "invalid access key");
+ return -EINVAL;
+ }
+
+ kiter = keys_map->find(id);
+ if (kiter == keys_map->end()) {
+ set_err_msg(err_msg, "key not found");
+ return -EINVAL;
+ }
+
+ rgw_remove_key_index(store, kiter->second);
+ keys_map->erase(kiter);
+
+ if (!defer_user_update)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWAccessKeyPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return remove(op_state, err_msg, false);
+}
+
+int RGWAccessKeyPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ int ret;
+
+ std::string subprocess_msg;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse request, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_remove(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove access key, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+RGWSubUserPool::RGWSubUserPool(RGWUser *usr)
+{
+ if (!usr)
+ subusers_allowed = false;
+
+ subusers_allowed = true;
+
+ store = usr->get_store();
+ user = usr;
+}
+
+RGWSubUserPool::~RGWSubUserPool()
+{
+
+}
+
+int RGWSubUserPool::init(RGWUserAdminOpState& op_state)
+{
+ if (!op_state.is_initialized()) {
+ subusers_allowed = false;
+ return -EINVAL;
+ }
+
+ std::string uid = op_state.get_user_id();
+ if (uid.compare(RGW_USER_ANON_ID) == 0) {
+ subusers_allowed = false;
+ return -EACCES;
+ }
+
+ subuser_map = op_state.get_subusers();
+ if (subuser_map == NULL) {
+ subusers_allowed = false;
+ return -EINVAL;
+ }
+
+ subusers_allowed = true;
+
+ return 0;
+}
+
+bool RGWSubUserPool::exists(std::string subuser)
+{
+ if (subuser.empty())
+ return false;
+
+ if (!subuser_map)
+ return false;
+
+ if (subuser_map->count(subuser))
+ return true;
+
+ return false;
+}
+
+int RGWSubUserPool::check_op(RGWUserAdminOpState& op_state,
+ std::string *err_msg)
+{
+ bool existing = false;
+ string subprocess_msg;
+ std::string subuser = op_state.get_subuser();
+
+ if (!op_state.is_populated()) {
+ set_err_msg(err_msg, "user info was not populated");
+ return -EINVAL;
+ }
+
+ if (!subusers_allowed) {
+ set_err_msg(err_msg, "subusers not allowed for this user");
+ return -EACCES;
+ }
+
+ if (subuser.empty() && !op_state.will_gen_subuser()) {
+ set_err_msg(err_msg, "empty subuser name");
+ return -EINVAL;
+ }
+
+ // check if the subuser exists
+ if (!subuser.empty())
+ existing = exists(subuser);
+
+ op_state.set_existing_subuser(existing);
+
+ return 0;
+}
+
+int RGWSubUserPool::execute_add(RGWUserAdminOpState& op_state,
+ std::string *err_msg, bool defer_user_update)
+{
+ int ret = 0;
+ std::string subprocess_msg;
+
+ RGWSubUser subuser;
+ std::pair<std::string, RGWSubUser> subuser_pair;
+ std::string subuser_str = op_state.get_subuser();
+
+ subuser_pair.first = subuser_str;
+
+ // no duplicates
+ if (op_state.has_existing_subuser()) {
+ set_err_msg(err_msg, "subuser exists");
+ return -EEXIST;
+ }
+
+ // assumes key should be created
+ if (op_state.has_key_op()) {
+ ret = user->keys.add(op_state, &subprocess_msg, true);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to create subuser key, " + subprocess_msg);
+ return ret;
+ }
+ }
+
+ // create the subuser
+ subuser.name = subuser_str;
+
+ if (op_state.has_subuser_perm())
+ subuser.perm_mask = op_state.get_subuser_perm();
+
+ // insert the subuser into user info
+ subuser_pair.second = subuser;
+ subuser_map->insert(subuser_pair);
+
+ // attempt to save the subuser
+ if (!defer_user_update)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWSubUserPool::add(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return add(op_state, err_msg, false);
+}
+
+int RGWSubUserPool::add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ std::string subprocess_msg;
+ int ret;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse request, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_add(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to create subuser, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWSubUserPool::execute_remove(RGWUserAdminOpState& op_state,
+ std::string *err_msg, bool defer_user_update)
+{
+ int ret = 0;
+ std::string subprocess_msg;
+
+ std::string subuser_str = op_state.get_subuser();
+
+ map<std::string, RGWSubUser>::iterator siter;
+ siter = subuser_map->find(subuser_str);
+
+ if (!op_state.has_existing_subuser()) {
+ set_err_msg(err_msg, "subuser not found: " + subuser_str);
+ return -EINVAL;
+ }
+
+ if (op_state.will_purge_keys()) {
+ // error would be non-existance so don't check
+ user->keys.remove(op_state, &subprocess_msg, true);
+ }
+
+ //remove the subuser from the user info
+ subuser_map->erase(siter);
+
+ // attempt to save the subuser
+ if (!defer_user_update)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWSubUserPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return remove(op_state, err_msg, false);
+}
+
+int RGWSubUserPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ std::string subprocess_msg;
+ int ret;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse request, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_remove(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove subuser, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWSubUserPool::execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ int ret = 0;
+ std::string subprocess_msg;
+ std::map<std::string, RGWSubUser>::iterator siter;
+ std::pair<std::string, RGWSubUser> subuser_pair;
+
+ std::string subuser_str = op_state.get_subuser();
+ RGWSubUser subuser;
+
+ if (!op_state.has_existing_subuser()) {
+ set_err_msg(err_msg, "subuser does not exist");
+ return -EINVAL;
+ }
+
+ subuser_pair.first = subuser_str;
+
+ siter = subuser_map->find(subuser_str);
+ subuser = siter->second;
+
+ if (op_state.has_key_op()) {
+ ret = user->keys.add(op_state, &subprocess_msg, true);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to create subuser keys, " + subprocess_msg);
+ return ret;
+ }
+ }
+
+ if (op_state.has_subuser_perm())
+ subuser.perm_mask = op_state.get_subuser_perm();
+
+ subuser_pair.second = subuser;
+
+ subuser_map->erase(siter);
+ subuser_map->insert(subuser_pair);
+
+ // attempt to save the subuser
+ if (!defer_user_update)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWSubUserPool::modify(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return RGWSubUserPool::modify(op_state, err_msg, false);
+}
+
+int RGWSubUserPool::modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_user_update)
+{
+ std::string subprocess_msg;
+ int ret;
+
+ RGWSubUser subuser;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse request, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_modify(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to modify subuser, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+RGWUserCapPool::RGWUserCapPool(RGWUser *usr)
+{
+ user = usr;
+
+ if (!user) {
+ caps_allowed = false;
+ }
+}
+
+RGWUserCapPool::~RGWUserCapPool()
+{
+
+}
+
+int RGWUserCapPool::init(RGWUserAdminOpState& op_state)
+{
+ if (!op_state.is_initialized()) {
+ caps_allowed = false;
+ return -EINVAL;
+ }
+
+ std::string uid = op_state.get_user_id();
+ if (uid == RGW_USER_ANON_ID) {
+ caps_allowed = false;
+ return -EACCES;
+ }
+
+ caps = op_state.get_caps_obj();
+ if (!caps) {
+ caps_allowed = false;
+ return -EINVAL;
+ }
+
+ caps_allowed = true;
+
+ return 0;
+}
+
+int RGWUserCapPool::add(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return add(op_state, err_msg, false);
+}
+
+int RGWUserCapPool::add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save)
+{
+ int ret = 0;
+ std::string subprocess_msg;
+ std::string caps_str = op_state.get_caps();
+
+ if (!op_state.is_populated()) {
+ set_err_msg(err_msg, "user info was not populated");
+ return -EINVAL;
+ }
+
+ if (!caps_allowed) {
+ set_err_msg(err_msg, "caps not allowed for this user");
+ return -EACCES;
+ }
+
+ if (caps_str.empty()) {
+ set_err_msg(err_msg, "empty user caps");
+ return -EINVAL;
+ }
+
+ int r = caps->add_from_string(caps_str);
+ if (r < 0) {
+ set_err_msg(err_msg, "unable to add caps: " + caps_str);
+ return r;
+ }
+
+ if (!defer_save)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUserCapPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ return remove(op_state, err_msg, false);
+}
+
+int RGWUserCapPool::remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save)
+{
+ int ret = 0;
+ std::string subprocess_msg;
+
+ std::string caps_str = op_state.get_caps();
+
+ if (!op_state.is_populated()) {
+ set_err_msg(err_msg, "user info was not populated");
+ return -EINVAL;
+ }
+
+ if (!caps_allowed) {
+ set_err_msg(err_msg, "caps not allowed for this user");
+ return -EACCES;
+ }
+
+ if (caps_str.empty()) {
+ set_err_msg(err_msg, "empty user caps");
+ return -EINVAL;
+ }
+
+ int r = caps->remove_from_string(caps_str);
+ if (r < 0) {
+ set_err_msg(err_msg, "unable to remove caps: " + caps_str);
+ return r;
+ }
+
+ if (!defer_save)
+ ret = user->update(op_state, err_msg);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+RGWUser::RGWUser() : caps(this), keys(this), subusers(this)
+{
+ init_default();
+}
+
+int RGWUser::init(RGWRados *storage, RGWUserAdminOpState& op_state)
+{
+ init_default();
+
+ int ret = init_storage(storage);
+ if (ret < 0)
+ return ret;
+
+ ret = init(op_state);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+RGWUser::~RGWUser()
+{
+}
+
+void RGWUser::init_default()
+{
+ // use anonymous user info as a placeholder
+ rgw_get_anon_user(old_info);
+ user_id = RGW_USER_ANON_ID;
+
+ clear_populated();
+}
+
+int RGWUser::init_storage(RGWRados *storage)
+{
+ if (!storage) {
+ return -EINVAL;
+ }
+
+ store = storage;
+
+ clear_populated();
+
+ /* API wrappers */
+ keys = RGWAccessKeyPool(this);
+ caps = RGWUserCapPool(this);
+ subusers = RGWSubUserPool(this);
+
+ return 0;
+}
+
+int RGWUser::init(RGWUserAdminOpState& op_state)
+{
+ bool found = false;
+ std::string swift_user;
+ std::string uid = op_state.get_user_id();
+ std::string user_email = op_state.get_user_email();
+ std::string access_key = op_state.get_access_key();
+ std::string subuser = op_state.get_subuser();
+
+ int key_type = op_state.get_key_type();
+ if (key_type == KEY_TYPE_SWIFT) {
+ swift_user = op_state.get_access_key();
+ access_key.clear();
+ }
+
+ RGWUserInfo user_info;
+
+ clear_populated();
+
+ if (uid.empty() && !subuser.empty()) {
+ size_t pos = subuser.find(':');
+ if (pos != string::npos) {
+ uid = subuser.substr(0, pos);
+ op_state.set_user_id(uid);
+ }
+ }
+
+ if (!uid.empty() && (uid.compare(RGW_USER_ANON_ID) != 0))
+ found = (rgw_get_user_info_by_uid(store, uid, user_info) >= 0);
+
+ if (!user_email.empty() && !found)
+ found = (rgw_get_user_info_by_email(store, user_email, user_info) >= 0);
+
+ if (!swift_user.empty() && !found)
+ found = (rgw_get_user_info_by_swift(store, swift_user, user_info) >= 0);
+
+ if (!access_key.empty() && !found)
+ found = (rgw_get_user_info_by_access_key(store, access_key, user_info) >= 0);
+
+ op_state.set_existing_user(found);
+ if (found) {
+ op_state.set_user_info(user_info);
+ op_state.set_populated();
+
+ old_info = user_info;
+ set_populated();
+ }
+
+ user_id = user_info.user_id;
+ op_state.set_initialized();
+
+ // this may have been called by a helper object
+ int ret = init_members(op_state);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUser::init_members(RGWUserAdminOpState& op_state)
+{
+ int ret = 0;
+
+ ret = keys.init(op_state);
+ if (ret < 0)
+ return ret;
+
+ ret = subusers.init(op_state);
+ if (ret < 0)
+ return ret;
+
+ ret = caps.init(op_state);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUser::update(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ int ret;
+ std::string subprocess_msg;
+ RGWUserInfo user_info = op_state.get_user_info();
+
+ if (!store) {
+ set_err_msg(err_msg, "couldn't initialize storage");
+ return -EINVAL;
+ }
+
+ if (is_populated()) {
+ ret = rgw_store_user_info(store, user_info, &old_info, false);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to store user info");
+ return ret;
+ }
+
+ ret = remove_old_indexes(store, old_info, user_info, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove old user info, " + subprocess_msg);
+ return ret;
+ }
+ } else {
+ ret = rgw_store_user_info(store, user_info, NULL, false);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to store user info");
+ return ret;
+ }
+ }
+
+ old_info = user_info;
+ set_populated();
+
+ return 0;
+}
+
+int RGWUser::check_op(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string subprocess_msg;
+ bool same_id;
+ bool populated;
+ //bool existing_email = false; // this check causes a fault
+ std::string op_id = op_state.get_user_id();
+ std::string op_email = op_state.get_user_email();
+
+ RGWUserInfo user_info;
+
+ same_id = (user_id.compare(op_id) == 0);
+ populated = is_populated();
+
+ if (op_id.compare(RGW_USER_ANON_ID) == 0) {
+ set_err_msg(err_msg, "unable to perform operations on the anoymous user");
+ return -EINVAL;
+ }
+
+ if (populated && !same_id) {
+ set_err_msg(err_msg, "user id mismatch, operation id: " + op_id\
+ + " does not match: " + user_id);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int RGWUser::execute_add(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string subprocess_msg;
+ int ret = 0;
+ bool defer_user_update = true;
+
+ RGWUserInfo user_info;
+
+ std::string uid = op_state.get_user_id();
+ std::string user_email = op_state.get_user_email();
+ std::string display_name = op_state.get_display_name();
+
+ // fail if the user exists already
+ if (op_state.has_existing_user()) {
+ if ((user_email.empty() || old_info.user_email == user_email) &&
+ old_info.display_name == display_name) {
+ return execute_modify(op_state, err_msg);
+ }
+
+ set_err_msg(err_msg, "user: " + op_state.user_id + " exists");
+
+ return -EEXIST;
+ }
+
+ // fail if the user_info has already been populated
+ if (op_state.is_populated()) {
+ set_err_msg(err_msg, "cannot overwrite already populated user");
+ return -EEXIST;
+ }
+
+ // fail if the display name was not included
+ if (display_name.empty()) {
+ set_err_msg(err_msg, "no display name specified");
+ return -EINVAL;
+ }
+
+ // fail if the user email is a duplicate
+ if (op_state.has_existing_email()) {
+ set_err_msg(err_msg, "duplicate email provided");
+ return -EEXIST;
+ }
+
+ // set the user info
+ user_id = uid;
+ user_info.user_id = user_id;
+ user_info.display_name = display_name;
+
+ if (!user_email.empty())
+ user_info.user_email = user_email;
+
+ user_info.max_buckets = op_state.get_max_buckets();
+ user_info.suspended = op_state.get_suspension_status();
+
+ // update the request
+ op_state.set_user_info(user_info);
+ op_state.set_populated();
+
+ // update the helper objects
+ ret = init_members(op_state);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to initialize user");
+ return ret;
+ }
+
+ // see if we need to add an access key
+ if (op_state.has_key_op()) {
+ ret = keys.add(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to create access key, " + subprocess_msg);
+ return ret;
+ }
+ }
+
+ // see if we need to add some caps
+ if (op_state.has_caps_op()) {
+ ret = caps.add(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to add user capabilities, " + subprocess_msg);
+ return ret;
+ }
+ }
+
+ ret = update(op_state, err_msg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUser::add(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string subprocess_msg;
+ int ret;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_add(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to create user, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWUser::execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ int ret;
+
+ bool purge_data = op_state.will_purge_data();
+ std::string uid = op_state.get_user_id();
+ RGWUserInfo user_info = op_state.get_user_info();
+
+ if (!op_state.has_existing_user()) {
+ set_err_msg(err_msg, "user does not exist");
+ return -EINVAL;
+ }
+
+ RGWUserBuckets buckets;
+ ret = rgw_read_user_buckets(store, uid, buckets, false);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to read user bucket info");
+ return ret;
+ }
+
+ map<std::string, RGWBucketEnt>& m = buckets.get_buckets();
+ if (!m.empty() && !purge_data) {
+ set_err_msg(err_msg, "must specify purge data to remove user with buckets");
+ return -EEXIST; // change to code that maps to 409: conflict
+ }
+
+ if (!m.empty()) {
+ std::map<std::string, RGWBucketEnt>::iterator it;
+ for (it = m.begin(); it != m.end(); ++it) {
+ ret = rgw_remove_bucket(store, ((*it).second).bucket, true);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to delete user data");
+ return ret;
+ }
+ }
+ }
+
+ ret = rgw_delete_user(store, user_info);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove user from RADOS");
+ return ret;
+ }
+
+ op_state.clear_populated();
+ clear_populated();
+
+ return 0;
+}
+
+int RGWUser::remove(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string subprocess_msg;
+ int ret;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_remove(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to remove user, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWUser::execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ bool same_email = false;
+ bool populated = op_state.is_populated();
+ bool defer_user_update = true;
+ int ret = 0;
+ std::string subprocess_msg;
+ std::string op_email = op_state.get_user_email();
+ std::string display_name = op_state.get_display_name();
+
+ RGWUserInfo user_info;
+ RGWUserInfo duplicate_check;
+
+ // ensure that the user info has been populated or is populate-able
+ if (!op_state.has_existing_user() && !populated) {
+ set_err_msg(err_msg, "user not found");
+ return -ENOENT;
+ }
+
+ // if the user hasn't already been populated...attempt to
+ if (!populated) {
+ ret = init(op_state);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to retrieve user info");
+ return ret;
+ }
+ }
+
+ // ensure that we can modify the user's attributes
+ if (user_id == RGW_USER_ANON_ID) {
+ set_err_msg(err_msg, "unable to modify anonymous user's info");
+ return -EACCES;
+ }
+
+ user_info = old_info;
+
+ std::string old_email = old_info.user_email;
+ if (!op_email.empty()) {
+ same_email = (old_email.compare(op_email) == 0);
+
+ // make sure we are not adding a duplicate email
+ if (!same_email) {
+ ret = rgw_get_user_info_by_email(store, op_email, duplicate_check);
+ if (ret >= 0 && duplicate_check.user_id != user_id) {
+ set_err_msg(err_msg, "cannot add duplicate email");
+ return -EEXIST;
+ }
+ }
+ user_info.user_email = op_email;
+ }
+
+
+ // update the remaining user info
+ if (!display_name.empty())
+ user_info.display_name = display_name;
+
+ // will be set to RGW_DEFAULT_MAX_BUCKETS by default
+ uint32_t max_buckets = op_state.get_max_buckets();
+
+ ldout(store->ctx(), 0) << "max_buckets=" << max_buckets << " specified=" << op_state.max_buckets_specified << dendl;
+
+ if (op_state.max_buckets_specified)
+ user_info.max_buckets = max_buckets;
+
+ if (op_state.has_suspension_op()) {
+ __u8 suspended = op_state.get_suspension_status();
+ user_info.suspended = suspended;
+
+ RGWUserBuckets buckets;
+
+ if (user_id.empty()) {
+ set_err_msg(err_msg, "empty user id passed...aborting");
+ return -EINVAL;
+ }
+
+ ret = rgw_read_user_buckets(store, user_id, buckets, false);
+ if (ret < 0) {
+ set_err_msg(err_msg, "could not get buckets for uid: " + user_id);
+ return ret;
+ }
+
+ map<string, RGWBucketEnt>& m = buckets.get_buckets();
+ map<string, RGWBucketEnt>::iterator iter;
+
+ vector<rgw_bucket> bucket_names;
+ for (iter = m.begin(); iter != m.end(); ++iter) {
+ RGWBucketEnt obj = iter->second;
+ bucket_names.push_back(obj.bucket);
+ }
+
+ ret = store->set_buckets_enabled(bucket_names, !suspended);
+ if (ret < 0) {
+ set_err_msg(err_msg, "failed to change pool");
+ return ret;
+ }
+ }
+ op_state.set_user_info(user_info);
+
+ // if we're supposed to modify keys, do so
+ if (op_state.has_key_op()) {
+ ret = keys.add(op_state, &subprocess_msg, defer_user_update);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to create or modify keys, " + subprocess_msg);
+ return ret;
+ }
+ }
+
+ ret = update(op_state, err_msg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUser::modify(RGWUserAdminOpState& op_state, std::string *err_msg)
+{
+ std::string subprocess_msg;
+ int ret;
+
+ ret = check_op(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to parse parameters, " + subprocess_msg);
+ return ret;
+ }
+
+ ret = execute_modify(op_state, &subprocess_msg);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to modify user, " + subprocess_msg);
+ return ret;
+ }
+
+ return 0;
+}
+
+int RGWUser::info(RGWUserAdminOpState& op_state, RGWUserInfo& fetched_info, std::string *err_msg)
+{
+ int ret = init(op_state);
+ if (ret < 0) {
+ set_err_msg(err_msg, "unable to fetch user info");
+ return ret;
+ }
+
+ fetched_info = op_state.get_user_info();
+
+ return 0;
+}
+
+int RGWUser::info(RGWUserInfo& fetched_info, std::string *err_msg)
+{
+ if (!is_populated()) {
+ set_err_msg(err_msg, "no user info saved");
+ return -EINVAL;
+ }
+
+ fetched_info = old_info;
+
+ return 0;
+}
+
+int RGWUserAdminOp_User::info(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ if (!op_state.has_existing_user())
+ return -ENOENT;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ dump_user_info(formatter, info);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_User::create(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.add(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ dump_user_info(formatter, info);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_User::modify(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.modify(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ dump_user_info(formatter, info);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_User::remove(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+
+ ret = user.remove(op_state, NULL);
+
+ return ret;
+}
+
+int RGWUserAdminOp_Subuser::create(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.subusers.add(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ dump_subusers_info(formatter, info);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_Subuser::modify(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.subusers.modify(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ dump_subusers_info(formatter, info);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_Subuser::remove(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+
+ ret = user.subusers.remove(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUserAdminOp_Key::create(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.keys.add(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ int key_type = op_state.get_key_type();
+
+ if (key_type == KEY_TYPE_SWIFT)
+ dump_swift_keys_info(formatter, info);
+
+ else if (key_type == KEY_TYPE_S3)
+ dump_access_keys_info(formatter, info);
+
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_Key::remove(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+
+ ret = user.keys.remove(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int RGWUserAdminOp_Caps::add(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.caps.add(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ info.caps.dump(formatter);
+ flusher.flush();
+
+ return 0;
+}
+
+int RGWUserAdminOp_Caps::remove(RGWRados *store, RGWUserAdminOpState& op_state,
+ RGWFormatterFlusher& flusher)
+{
+ RGWUserInfo info;
+ RGWUser user;
+ int ret = user.init(store, op_state);
+ if (ret < 0)
+ return ret;
+
+ Formatter *formatter = flusher.get_formatter();
+
+ ret = user.caps.remove(op_state, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = user.info(info, NULL);
+ if (ret < 0)
+ return ret;
+
+ flusher.start(0);
+
+ info.caps.dump(formatter);
+ flusher.flush();
+
+ return 0;
+}
#include "rgw_common.h"
#include "rgw_tools.h"
+#include "rgw_rados.h"
+
+#include "rgw_string.h"
+
+#include "common/Formatter.h"
+#include "rgw_formats.h"
+
using namespace std;
#define RGW_USER_ANON_ID "anonymous"
+#define SECRET_KEY_LEN 40
+#define PUBLIC_ID_LEN 20
+#define RAND_SUBUSER_LEN 5
+
/**
* A string wrapper that includes encode/decode functions
* for easily accessing a UID in all forms
{
string user_id;
void encode(bufferlist& bl) const {
- ::encode(user_id, bl);
+ ::encode(user_id, bl);
}
void decode(bufferlist::iterator& bl) {
::decode(user_id, bl);
/**
* Store a list of the user's buckets, with associated functinos.
*/
-class RGWUserBuckets
-{
- map<string, RGWBucketEnt> buckets;
-
-public:
- RGWUserBuckets() {}
- void encode(bufferlist& bl) const {
- ::encode(buckets, bl);
- }
- void decode(bufferlist::iterator& bl) {
- ::decode(buckets, bl);
- }
- /**
- * Check if the user owns a bucket by the given name.
- */
- bool owns(string& name) {
- map<string, RGWBucketEnt>::iterator iter;
- iter = buckets.find(name);
- return (iter != buckets.end());
- }
-
- /**
- * Add a (created) bucket to the user's bucket list.
- */
- void add(RGWBucketEnt& bucket) {
- buckets[bucket.bucket.name] = bucket;
- }
-
- /**
- * Remove a bucket from the user's list by name.
- */
- void remove(string& name) {
- map<string, RGWBucketEnt>::iterator iter;
- iter = buckets.find(name);
- if (iter != buckets.end()) {
- buckets.erase(iter);
- }
- }
-
- /**
- * Get the user's buckets as a map.
- */
- map<string, RGWBucketEnt>& get_buckets() { return buckets; }
-
- /**
- * Cleanup data structure
- */
- void clear() { buckets.clear(); }
-
- size_t count() { return buckets.size(); }
-};
-WRITE_CLASS_ENCODER(RGWUserBuckets)
/**
* Get all the buckets owned by a user and fill up an RGWUserBuckets with them.
* Returns: 0 on success, -ERR# on failure.
*/
-extern int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, bool need_stats);
+//extern int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets, bool need_stats);
/**
* Store the set of buckets associated with a user.
* This completely overwrites any previously-stored list, so be careful!
* Returns 0 on success, -ERR# otherwise.
*/
-extern int rgw_write_buckets_attr(RGWRados *store, string user_id, RGWUserBuckets& buckets);
+//extern int rgw_write_buckets_attr(RGWRados *store, string user_id, RGWUserBuckets& buckets);
-extern int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket);
-extern int rgw_remove_user_bucket_info(RGWRados *store, string user_id, rgw_bucket& bucket);
+//extern int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket);
+//extern int rgw_remove_user_bucket_info(RGWRados *store, string user_id, rgw_bucket& bucket);
/*
* remove the different indexes
- */
+ */
extern int rgw_remove_key_index(RGWRados *store, RGWAccessKey& access_key);
extern int rgw_remove_uid_index(RGWRados *store, string& uid);
extern int rgw_remove_email_index(RGWRados *store, string& email);
extern int rgw_remove_swift_name_index(RGWRados *store, string& swift_name);
+
+/*
+ * An RGWUser class along with supporting classes created
+ * to support the creation of an RESTful administrative API
+ */
+
+extern void rgw_perm_to_str(uint32_t mask, char *buf, int len);
+extern uint32_t rgw_str_to_perm(const char *str);
+
+enum ObjectKeyType {
+ KEY_TYPE_SWIFT,
+ KEY_TYPE_S3,
+ KEY_TYPE_UNDEFINED
+};
+
+enum RGWKeyPoolOp {
+ GENERATE_KEY,
+ MODIFY_KEY
+};
+
+enum RGWUserId {
+ RGW_USER_ID,
+ RGW_SWIFT_USERNAME,
+ RGW_USER_EMAIL,
+ RGW_ACCESS_KEY,
+};
+
+struct RGWUserAdminOpState {
+ // user attributes
+ RGWUserInfo info;
+ std::string user_id;
+ std::string user_email;
+ std::string display_name;
+ uint32_t max_buckets;
+ __u8 suspended;
+ std::string caps;
+
+ // subuser attributes
+ std::string subuser;
+ uint32_t perm_mask;
+
+ // key_attributes
+ std::string id; // access key
+ std::string key; // secret key
+ int32_t key_type;
+
+ // operation attributes
+ bool existing_user;
+ bool existing_key;
+ bool existing_subuser;
+ bool existing_email;
+ bool subuser_specified;
+ bool gen_secret;
+ bool gen_access;
+ bool gen_subuser;
+ bool id_specified;
+ bool key_specified;
+ bool type_specified;
+ bool purge_data;
+ bool purge_keys;
+ bool display_name_specified;
+ bool user_email_specified;
+ bool max_buckets_specified;
+ bool perm_specified;
+ bool caps_specified;
+ bool suspension_op;
+ bool key_op;
+
+ // req parameters
+ bool populated;
+ bool initialized;
+ bool key_params_checked;
+ bool subuser_params_checked;
+ bool user_params_checked;
+
+ void set_access_key(std::string& access_key) {
+ if (access_key.empty())
+ return;
+
+ id = access_key;
+ id_specified = true;
+ gen_access = false;
+ key_op = true;
+ }
+ void set_secret_key(std::string& secret_key) {
+ if (secret_key.empty())
+ return;
+
+ key = secret_key;
+ key_specified = true;
+ gen_secret = false;
+ key_op = true;
+ }
+ void set_user_id(std::string& id) {
+ if (id.empty())
+ return;
+
+ user_id = id;
+ }
+ void set_user_email(std::string& email) {
+ if (email.empty())
+ return;
+
+ user_email = email;
+ user_email_specified = true;
+ }
+ void set_display_name(std::string& name) {
+ if (name.empty())
+ return;
+
+ display_name = name;
+ display_name_specified = true;
+ }
+ void set_subuser(std::string& _subuser) {
+ if (_subuser.empty())
+ return;
+
+ size_t pos = _subuser.find(":");
+
+ if (pos != string::npos) {
+ user_id = _subuser.substr(0, pos);
+ subuser = _subuser.substr(pos+1);
+ } else {
+ subuser = _subuser;
+ }
+
+ subuser_specified = true;
+ gen_access = true;
+ }
+ void set_caps(std::string& _caps) {
+ if (_caps.empty())
+ return;
+
+ caps = _caps;
+ caps_specified = true;
+ }
+ void set_perm(uint32_t perm) {
+ perm_mask = perm;
+ perm_specified = true;
+ }
+ void set_key_type(int32_t type) {
+ key_type = type;
+ type_specified = true;
+ }
+ void set_suspension(__u8 is_suspended) {
+ suspended = is_suspended;
+ suspension_op = true;
+ }
+ void set_user_info(RGWUserInfo& user_info) {
+ user_id = user_info.user_id;
+ info = user_info;
+ }
+ void set_max_buckets(uint32_t mb) {
+ max_buckets = mb;
+ max_buckets_specified = true;
+ }
+ void set_gen_access() {
+ gen_access = true;
+ key_op = true;
+ }
+ void set_gen_secret() {
+ gen_secret = true;
+ key_op = true;
+ }
+ void set_generate_key() {
+ if (id.empty())
+ gen_access = true;
+ if (key.empty())
+ gen_secret = true;
+ key_op = true;
+ }
+ void clear_generate_key() {
+ gen_access = false;
+ gen_secret = false;
+ }
+ void set_purge_keys() {
+ purge_keys = true;
+ key_op = true;
+ }
+
+ bool is_populated() { return populated; };
+ bool is_initialized() { return initialized; };
+ bool has_existing_user() { return existing_user; };
+ bool has_existing_key() { return existing_key; };
+ bool has_existing_subuser() { return existing_subuser; };
+ bool has_existing_email() { return existing_email; };
+ bool has_subuser() { return subuser_specified; };
+ bool has_key_op() { return key_op; };
+ bool has_caps_op() { return caps_specified; };
+ bool has_suspension_op() { return suspension_op; };
+ bool has_subuser_perm() { return perm_specified; };
+ bool will_gen_access() { return gen_access; };
+ bool will_gen_secret() { return gen_secret; };
+ bool will_gen_subuser() { return gen_subuser; };
+ bool will_purge_keys() { return purge_keys; };
+ bool will_purge_data() { return purge_data; };
+ bool will_generate_subuser() { return gen_subuser; };
+ void set_populated() { populated = true; };
+ void clear_populated() { populated = false; };
+ void set_initialized() { initialized = true; };
+ void set_existing_user(bool flag) { existing_user = flag; };
+ void set_existing_key(bool flag) { existing_key = flag; };
+ void set_existing_subuser(bool flag) { existing_subuser = flag; };
+ void set_existing_email(bool flag) { existing_email = flag; };
+ void set_purge_data(bool flag) { purge_data = flag; };
+ void set_generate_subuser(bool flag) { gen_subuser = flag; };
+ __u8 get_suspension_status() { return suspended; };
+ int32_t get_key_type() {return key_type; };
+ uint32_t get_subuser_perm() { return perm_mask; };
+ uint32_t get_max_buckets() { return max_buckets; };
+
+ std::string get_user_id() { return user_id; };
+ std::string get_subuser() { return subuser; };
+ std::string get_access_key() { return id; };
+ std::string get_secret_key() { return key; };
+ std::string get_caps() { return caps; };
+ std::string get_user_email() { return user_email; };
+ std::string get_display_name() { return display_name; };
+
+ RGWUserInfo& get_user_info() { return info; };
+
+ map<std::string, RGWAccessKey> *get_swift_keys() { return &info.swift_keys; };
+ map<std::string, RGWAccessKey> *get_access_keys() { return &info.access_keys; };
+ map<std::string, RGWSubUser> *get_subusers() { return &info.subusers; };
+
+ RGWUserCaps *get_caps_obj() { return &info.caps; };
+
+ std::string build_default_swift_kid() {
+ if (user_id.empty() || subuser.empty())
+ return "";
+
+ std::string kid = user_id;
+ kid.append(":");
+ kid.append(subuser);
+
+ return kid;
+ }
+
+ std::string generate_subuser() {
+ if (user_id.empty())
+ return "";
+
+ std::string generated_subuser = user_id;
+ std::string rand_suffix;
+
+ int sub_buf_size = RAND_SUBUSER_LEN + 1;
+ char sub_buf[RAND_SUBUSER_LEN + 1];
+
+ if (gen_rand_alphanumeric_upper(g_ceph_context, sub_buf, sub_buf_size) < 0)
+ return "";
+
+ rand_suffix = sub_buf;
+ if (rand_suffix.empty())
+ return "";
+
+ generated_subuser.append(rand_suffix);
+ subuser = generated_subuser;
+
+ return generated_subuser;
+ }
+
+ RGWUserAdminOpState()
+ {
+ user_id = RGW_USER_ANON_ID;
+ display_name = "";
+ user_email = "";
+ id = "";
+ key = "";
+
+ max_buckets = RGW_DEFAULT_MAX_BUCKETS;
+ key_type = -1;
+ perm_mask = 0;
+ suspended = 0;
+
+ existing_user = false;
+ existing_key = false;
+ existing_subuser = false;
+ existing_email = false;
+ subuser_specified = false;
+ caps_specified = false;
+ purge_keys = false;
+ gen_secret = false;
+ gen_access = false;
+ gen_subuser = false;
+ id_specified = false;
+ key_specified = false;
+ type_specified = false;
+ purge_data = false;
+ purge_keys = false;
+ display_name_specified = false;
+ user_email_specified = false;
+ max_buckets_specified = false;
+ perm_specified = false;
+ suspension_op = false;
+ key_op = false;
+ populated = false;
+ initialized = false;
+ }
+};
+
+class RGWUser;
+
+class RGWAccessKeyPool
+{
+ RGWUser *user;
+
+ std::map<std::string, int, ltstr_nocase> key_type_map;
+ std::string user_id;
+ RGWRados *store;
+
+ map<std::string, RGWAccessKey> *swift_keys;
+ map<std::string, RGWAccessKey> *access_keys;
+
+ // we don't want to allow keys for the anonymous user or a null user
+ bool keys_allowed;
+
+private:
+ int create_key(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int generate_key(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int modify_key(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ int check_key_owner(RGWUserAdminOpState& op_state);
+ bool check_existing_key(RGWUserAdminOpState& op_state);
+ int check_op(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ /* API Contract Fulfilment */
+ int execute_add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+public:
+ RGWAccessKeyPool(RGWUser* usr);
+ ~RGWAccessKeyPool();
+
+ int init(RGWUserAdminOpState& op_state);
+
+ /* API Contracted Methods */
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ friend class RGWUser;
+ friend class RGWSubUserPool;
+};
+
+class RGWSubUserPool
+{
+ RGWUser *user;
+
+ string user_id;
+ RGWRados *store;
+ bool subusers_allowed;
+
+ map<string, RGWSubUser> *subuser_map;
+
+private:
+ int check_op(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ /* API Contract Fulfillment */
+ int execute_add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int modify(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+public:
+ RGWSubUserPool(RGWUser *user);
+ ~RGWSubUserPool();
+
+ bool exists(std::string subuser);
+ int init(RGWUserAdminOpState& op_state);
+
+ /* API contracted methods */
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int modify(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ friend class RGWUser;
+};
+
+class RGWUserCapPool
+{
+ RGWUserCaps *caps;
+ bool caps_allowed;
+ RGWUser *user;
+
+private:
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg, bool defer_save);
+
+public:
+ RGWUserCapPool(RGWUser *user);
+ ~RGWUserCapPool();
+
+ int init(RGWUserAdminOpState& op_state);
+
+ /* API contracted methods */
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ friend class RGWUser;
+};
+
+class RGWUser
+{
+
+private:
+ RGWUserInfo old_info;
+ RGWRados *store;
+
+ string user_id;
+ bool info_stored;
+
+ void set_populated() { info_stored = true; };
+ void clear_populated() { info_stored = false; };
+ bool is_populated() { return info_stored; };
+
+ int check_op(RGWUserAdminOpState& req, std::string *err_msg);
+ int update(RGWUserAdminOpState& op_state, std::string *err_msg);
+
+ void clear_members();
+ void init_default();
+
+ /* API Contract Fulfillment */
+ int execute_add(RGWUserAdminOpState& op_state, std::string *err_msg);
+ int execute_remove(RGWUserAdminOpState& op_state, std::string *err_msg);
+ int execute_modify(RGWUserAdminOpState& op_state, std::string *err_msg);
+
+public:
+ RGWUser();
+ ~RGWUser();
+
+ int init(RGWRados *storage, RGWUserAdminOpState& op_state);
+
+ int init_storage(RGWRados *storage);
+ int init(RGWUserAdminOpState& op_state);
+ int init_members(RGWUserAdminOpState& op_state);
+
+ RGWRados *get_store() { return store; };
+
+ /* API Contracted Members */
+ RGWUserCapPool caps;
+ RGWAccessKeyPool keys;
+ RGWSubUserPool subusers;
+
+ /* API Contracted Methods */
+ int add(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+ int remove(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ /* remove an already populated RGWUser */
+ int remove(std::string *err_msg = NULL);
+
+ int modify(RGWUserAdminOpState& op_state, std::string *err_msg = NULL);
+
+ /* retrieve info from an existing user in the RGW system */
+ int info(RGWUserAdminOpState& op_state, RGWUserInfo& fetched_info, std::string *err_msg = NULL);
+
+ /* info from an already populated RGWUser */
+ int info (RGWUserInfo& fetched_info, std::string *err_msg = NULL);
+
+ friend class RGWAccessKeyPool;
+ friend class RGWSubUserPool;
+ friend class RGWUserCapPool;
+};
+
+/* Wrapers for admin API functionality */
+
+class RGWUserAdminOp_User
+{
+public:
+ static int info(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int create(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int modify(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int remove(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+};
+
+class RGWUserAdminOp_Subuser
+{
+public:
+ static int create(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int modify(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int remove(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+};
+
+class RGWUserAdminOp_Key
+{
+public:
+ static int create(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int remove(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+};
+
+class RGWUserAdminOp_Caps
+{
+public:
+ static int add(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+
+ static int remove(RGWRados *store,
+ RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher);
+};
+
#endif