X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Frgw%2Frgw_common.cc;fp=src%2Fceph%2Fsrc%2Frgw%2Frgw_common.cc;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=d10577ef455cb19900b9b6aabcfb019254901ef6;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/rgw/rgw_common.cc b/src/ceph/src/rgw/rgw_common.cc deleted file mode 100644 index d10577e..0000000 --- a/src/ceph/src/rgw/rgw_common.cc +++ /dev/null @@ -1,1904 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include -#include -#include -#include -#include -#include -#include - -#include "json_spirit/json_spirit.h" -#include "common/ceph_json.h" - -#include "rgw_op.h" -#include "rgw_common.h" -#include "rgw_acl.h" -#include "rgw_string.h" -#include "rgw_rados.h" -#include "rgw_http_errors.h" - -#include "common/ceph_crypto.h" -#include "common/armor.h" -#include "common/errno.h" -#include "common/Clock.h" -#include "common/Formatter.h" -#include "common/perf_counters.h" -#include "common/strtol.h" -#include "include/str_list.h" -#include "auth/Crypto.h" -#include "rgw_crypt_sanitize.h" - -#include - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rgw - -using boost::none; -using boost::optional; - -using rgw::IAM::ARN; -using rgw::IAM::Effect; -using rgw::IAM::op_to_perm; -using rgw::IAM::Policy; - -PerfCounters *perfcounter = NULL; - -const uint32_t RGWBucketInfo::NUM_SHARDS_BLIND_BUCKET(UINT32_MAX); - -rgw_http_errors rgw_http_s3_errors({ - { 0, {200, "" }}, - { STATUS_CREATED, {201, "Created" }}, - { STATUS_ACCEPTED, {202, "Accepted" }}, - { STATUS_NO_CONTENT, {204, "NoContent" }}, - { STATUS_PARTIAL_CONTENT, {206, "" }}, - { ERR_PERMANENT_REDIRECT, {301, "PermanentRedirect" }}, - { ERR_WEBSITE_REDIRECT, {301, "WebsiteRedirect" }}, - { STATUS_REDIRECT, {303, "" }}, - { ERR_NOT_MODIFIED, {304, "NotModified" }}, - { EINVAL, {400, "InvalidArgument" }}, - { ERR_INVALID_REQUEST, {400, "InvalidRequest" }}, - { ERR_INVALID_DIGEST, {400, "InvalidDigest" }}, - { ERR_BAD_DIGEST, {400, "BadDigest" }}, - { ERR_INVALID_LOCATION_CONSTRAINT, {400, "InvalidLocationConstraint" }}, - { ERR_ZONEGROUP_DEFAULT_PLACEMENT_MISCONFIGURATION, {400, "ZonegroupDefaultPlacementMisconfiguration" }}, - { ERR_INVALID_BUCKET_NAME, {400, "InvalidBucketName" }}, - { ERR_INVALID_OBJECT_NAME, {400, "InvalidObjectName" }}, - { ERR_UNRESOLVABLE_EMAIL, {400, "UnresolvableGrantByEmailAddress" }}, - { ERR_INVALID_PART, {400, "InvalidPart" }}, - { ERR_INVALID_PART_ORDER, {400, "InvalidPartOrder" }}, - { ERR_REQUEST_TIMEOUT, {400, "RequestTimeout" }}, - { ERR_TOO_LARGE, {400, "EntityTooLarge" }}, - { ERR_TOO_SMALL, {400, "EntityTooSmall" }}, - { ERR_TOO_MANY_BUCKETS, {400, "TooManyBuckets" }}, - { ERR_MALFORMED_XML, {400, "MalformedXML" }}, - { ERR_AMZ_CONTENT_SHA256_MISMATCH, {400, "XAmzContentSHA256Mismatch" }}, - { ERR_INVALID_TAG, {400, "InvalidTag"}}, - { ERR_MALFORMED_ACL_ERROR, {400, "MalformedACLError" }}, - { ERR_INVALID_ENCRYPTION_ALGORITHM, {400, "InvalidEncryptionAlgorithmError" }}, - { ERR_LENGTH_REQUIRED, {411, "MissingContentLength" }}, - { EACCES, {403, "AccessDenied" }}, - { EPERM, {403, "AccessDenied" }}, - { ERR_SIGNATURE_NO_MATCH, {403, "SignatureDoesNotMatch" }}, - { ERR_INVALID_ACCESS_KEY, {403, "InvalidAccessKeyId" }}, - { ERR_USER_SUSPENDED, {403, "UserSuspended" }}, - { ERR_REQUEST_TIME_SKEWED, {403, "RequestTimeTooSkewed" }}, - { ERR_QUOTA_EXCEEDED, {403, "QuotaExceeded" }}, - { ENOENT, {404, "NoSuchKey" }}, - { ERR_NO_SUCH_BUCKET, {404, "NoSuchBucket" }}, - { ERR_NO_SUCH_WEBSITE_CONFIGURATION, {404, "NoSuchWebsiteConfiguration" }}, - { ERR_NO_SUCH_UPLOAD, {404, "NoSuchUpload" }}, - { ERR_NOT_FOUND, {404, "Not Found"}}, - { ERR_NO_SUCH_LC, {404, "NoSuchLifecycleConfiguration"}}, - { ERR_NO_SUCH_BUCKET_POLICY, {404, "NoSuchBucketPolicy"}}, - { ERR_NO_SUCH_USER, {404, "NoSuchUser"}}, - { ERR_NO_SUCH_SUBUSER, {404, "NoSuchSubUser"}}, - { ERR_METHOD_NOT_ALLOWED, {405, "MethodNotAllowed" }}, - { ETIMEDOUT, {408, "RequestTimeout" }}, - { EEXIST, {409, "BucketAlreadyExists" }}, - { ERR_USER_EXIST, {409, "UserAlreadyExists" }}, - { ERR_EMAIL_EXIST, {409, "EmailExists" }}, - { ERR_KEY_EXIST, {409, "KeyExists"}}, - { ERR_TAG_CONFLICT, {409, "OperationAborted"}}, - { ERR_INVALID_SECRET_KEY, {400, "InvalidSecretKey"}}, - { ERR_INVALID_KEY_TYPE, {400, "InvalidKeyType"}}, - { ERR_INVALID_CAP, {400, "InvalidCapability"}}, - { ERR_INVALID_TENANT_NAME, {400, "InvalidTenantName" }}, - { ENOTEMPTY, {409, "BucketNotEmpty" }}, - { ERR_PRECONDITION_FAILED, {412, "PreconditionFailed" }}, - { ERANGE, {416, "InvalidRange" }}, - { ERR_UNPROCESSABLE_ENTITY, {422, "UnprocessableEntity" }}, - { ERR_LOCKED, {423, "Locked" }}, - { ERR_INTERNAL_ERROR, {500, "InternalError" }}, - { ERR_NOT_IMPLEMENTED, {501, "NotImplemented" }}, - { ERR_SERVICE_UNAVAILABLE, {503, "ServiceUnavailable"}}, - { ERR_ZERO_IN_URL, {400, "InvalidRequest" }}, -}); - -rgw_http_errors rgw_http_swift_errors({ - { EACCES, {403, "AccessDenied" }}, - { EPERM, {401, "AccessDenied" }}, - { ENAMETOOLONG, {400, "Metadata name too long" }}, - { ERR_USER_SUSPENDED, {401, "UserSuspended" }}, - { ERR_INVALID_UTF8, {412, "Invalid UTF8" }}, - { ERR_BAD_URL, {412, "Bad URL" }}, - { ERR_NOT_SLO_MANIFEST, {400, "Not an SLO manifest" }}, - { ERR_QUOTA_EXCEEDED, {413, "QuotaExceeded" }}, - { ENOTEMPTY, {409, "There was a conflict when trying " - "to complete your request." }}, - /* FIXME(rzarzynski): we need to find a way to apply Swift's error handling - * procedures also for ERR_ZERO_IN_URL. This make a problem as the validation - * is performed very early, even before setting the req_state::proto_flags. */ - { ERR_ZERO_IN_URL, {412, "Invalid UTF8 or contains NULL"}}, -}); - -int rgw_perf_start(CephContext *cct) -{ - PerfCountersBuilder plb(cct, cct->_conf->name.to_str(), l_rgw_first, l_rgw_last); - - plb.add_u64_counter(l_rgw_req, "req", "Requests"); - plb.add_u64_counter(l_rgw_failed_req, "failed_req", "Aborted requests"); - - plb.add_u64_counter(l_rgw_get, "get", "Gets"); - plb.add_u64_counter(l_rgw_get_b, "get_b", "Size of gets"); - plb.add_time_avg(l_rgw_get_lat, "get_initial_lat", "Get latency"); - plb.add_u64_counter(l_rgw_put, "put", "Puts"); - plb.add_u64_counter(l_rgw_put_b, "put_b", "Size of puts"); - plb.add_time_avg(l_rgw_put_lat, "put_initial_lat", "Put latency"); - - plb.add_u64(l_rgw_qlen, "qlen", "Queue length"); - plb.add_u64(l_rgw_qactive, "qactive", "Active requests queue"); - - plb.add_u64_counter(l_rgw_cache_hit, "cache_hit", "Cache hits"); - plb.add_u64_counter(l_rgw_cache_miss, "cache_miss", "Cache miss"); - - plb.add_u64_counter(l_rgw_keystone_token_cache_hit, "keystone_token_cache_hit", "Keystone token cache hits"); - plb.add_u64_counter(l_rgw_keystone_token_cache_miss, "keystone_token_cache_miss", "Keystone token cache miss"); - - perfcounter = plb.create_perf_counters(); - cct->get_perfcounters_collection()->add(perfcounter); - return 0; -} - -void rgw_perf_stop(CephContext *cct) -{ - assert(perfcounter); - cct->get_perfcounters_collection()->remove(perfcounter); - delete perfcounter; -} - -using namespace ceph::crypto; - -rgw_err:: -rgw_err() -{ - clear(); -} - -void rgw_err:: -clear() -{ - http_ret = 200; - ret = 0; - err_code.clear(); -} - -bool rgw_err:: -is_clear() const -{ - return (http_ret == 200); -} - -bool rgw_err:: -is_err() const -{ - return !(http_ret >= 200 && http_ret <= 399); -} - -// The requestURI transferred from the frontend can be abs_path or absoluteURI -// If it is absoluteURI, we should adjust it to abs_path for the following -// S3 authorization and some other processes depending on the requestURI -// The absoluteURI can start with "http://", "https://", "ws://" or "wss://" -static string get_abs_path(const string& request_uri) { - const static string ABS_PREFIXS[] = {"http://", "https://", "ws://", "wss://"}; - bool isAbs = false; - for (int i = 0; i < 4; ++i) { - if (boost::algorithm::starts_with(request_uri, ABS_PREFIXS[i])) { - isAbs = true; - break; - } - } - if (!isAbs) { // it is not a valid absolute uri - return request_uri; - } - size_t beg_pos = request_uri.find("://") + 3; - size_t len = request_uri.size(); - beg_pos = request_uri.find('/', beg_pos); - if (beg_pos == string::npos) return request_uri; - return request_uri.substr(beg_pos, len - beg_pos); -} - -req_info::req_info(CephContext *cct, const class RGWEnv *env) : env(env) { - method = env->get("REQUEST_METHOD", ""); - script_uri = env->get("SCRIPT_URI", cct->_conf->rgw_script_uri.c_str()); - request_uri = env->get("REQUEST_URI", cct->_conf->rgw_request_uri.c_str()); - if (request_uri[0] != '/') { - request_uri = get_abs_path(request_uri); - } - auto pos = request_uri.find('?'); - if (pos != string::npos) { - request_params = request_uri.substr(pos + 1); - request_uri = request_uri.substr(0, pos); - } else { - request_params = env->get("QUERY_STRING", ""); - } - host = env->get("HTTP_HOST", ""); - - // strip off any trailing :port from host (added by CrossFTP and maybe others) - size_t colon_offset = host.find_last_of(':'); - if (colon_offset != string::npos) { - bool all_digits = true; - for (unsigned i = colon_offset + 1; i < host.size(); ++i) { - if (!isdigit(host[i])) { - all_digits = false; - break; - } - } - if (all_digits) { - host.resize(colon_offset); - } - } -} - -void req_info::rebuild_from(req_info& src) -{ - method = src.method; - script_uri = src.script_uri; - args = src.args; - if (src.effective_uri.empty()) { - request_uri = src.request_uri; - } else { - request_uri = src.effective_uri; - } - effective_uri.clear(); - host = src.host; - - x_meta_map = src.x_meta_map; - x_meta_map.erase("x-amz-date"); -} - - -req_state::req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u) - : cct(_cct), cio(NULL), op(OP_UNKNOWN), user(u), has_acl_header(false), - info(_cct, e) -{ - enable_ops_log = e->conf.enable_ops_log; - enable_usage_log = e->conf.enable_usage_log; - defer_to_bucket_acls = e->conf.defer_to_bucket_acls; - content_started = false; - format = 0; - formatter = NULL; - expect_cont = false; - - obj_size = 0; - prot_flags = 0; - - system_request = false; - - time = ceph_clock_now(); - perm_mask = 0; - bucket_instance_shard_id = -1; - content_length = 0; - bucket_exists = false; - has_bad_meta = false; - length = NULL; - local_source = false; - - obj_ctx = NULL; -} - -req_state::~req_state() { - delete formatter; -} - -bool search_err(rgw_http_errors& errs, int err_no, bool is_website_redirect, int& http_ret, string& code) -{ - auto r = errs.find(err_no); - if (r != errs.end()) { - if (! is_website_redirect) - http_ret = r->second.first; - code = r->second.second; - return true; - } - return false; -} - -void set_req_state_err(struct rgw_err& err, /* out */ - int err_no, /* in */ - const int prot_flags) /* in */ -{ - if (err_no < 0) - err_no = -err_no; - - err.ret = -err_no; - bool is_website_redirect = false; - - if (prot_flags & RGW_REST_SWIFT) { - if (search_err(rgw_http_swift_errors, err_no, is_website_redirect, err.http_ret, err.err_code)) - return; - } - - //Default to searching in s3 errors - is_website_redirect |= (prot_flags & RGW_REST_WEBSITE) - && err_no == ERR_WEBSITE_REDIRECT && err.is_clear(); - if (search_err(rgw_http_s3_errors, err_no, is_website_redirect, err.http_ret, err.err_code)) - return; - dout(0) << "WARNING: set_req_state_err err_no=" << err_no - << " resorting to 500" << dendl; - - err.http_ret = 500; - err.err_code = "UnknownError"; -} - -void set_req_state_err(struct req_state* s, int err_no, const string& err_msg) -{ - if (s) { - set_req_state_err(s, err_no); - if (s->prot_flags & RGW_REST_SWIFT && !err_msg.empty()) { - /* TODO(rzarzynski): there never ever should be a check like this one. - * It's here only for the sake of the patch's backportability. Further - * commits will move the logic to a per-RGWHandler replacement of - * the end_header() function. Alternativaly, we might consider making - * that just for the dump(). Please take a look on @cbodley's comments - * in PR #10690 (https://github.com/ceph/ceph/pull/10690). */ - s->err.err_code = err_msg; - } else { - s->err.message = err_msg; - } - } -} - -void set_req_state_err(struct req_state* s, int err_no) -{ - if (s) { - set_req_state_err(s->err, err_no, s->prot_flags); - } -} - -void dump(struct req_state* s) -{ - if (s->format != RGW_FORMAT_HTML) - s->formatter->open_object_section("Error"); - if (!s->err.err_code.empty()) - s->formatter->dump_string("Code", s->err.err_code); - if (!s->err.message.empty()) - s->formatter->dump_string("Message", s->err.message); - if (!s->bucket_name.empty()) // TODO: connect to expose_bucket - s->formatter->dump_string("BucketName", s->bucket_name); - if (!s->trans_id.empty()) // TODO: connect to expose_bucket or another toggle - s->formatter->dump_string("RequestId", s->trans_id); - s->formatter->dump_string("HostId", s->host_id); - if (s->format != RGW_FORMAT_HTML) - s->formatter->close_section(); -} - -struct str_len { - const char *str; - int len; -}; - -#define STR_LEN_ENTRY(s) { s, sizeof(s) - 1 } - -struct str_len meta_prefixes[] = { STR_LEN_ENTRY("HTTP_X_AMZ"), - STR_LEN_ENTRY("HTTP_X_GOOG"), - STR_LEN_ENTRY("HTTP_X_DHO"), - STR_LEN_ENTRY("HTTP_X_RGW"), - STR_LEN_ENTRY("HTTP_X_OBJECT"), - STR_LEN_ENTRY("HTTP_X_CONTAINER"), - STR_LEN_ENTRY("HTTP_X_ACCOUNT"), - {NULL, 0} }; - - -void req_info::init_meta_info(bool *found_bad_meta) -{ - x_meta_map.clear(); - - for (const auto& kv: env->get_map()) { - const char *prefix; - const string& header_name = kv.first; - const string& val = kv.second; - for (int prefix_num = 0; (prefix = meta_prefixes[prefix_num].str) != NULL; prefix_num++) { - int len = meta_prefixes[prefix_num].len; - const char *p = header_name.c_str(); - if (strncmp(p, prefix, len) == 0) { - dout(10) << "meta>> " << p << dendl; - const char *name = p+len; /* skip the prefix */ - int name_len = header_name.size() - len; - - if (found_bad_meta && strncmp(name, "_META_", name_len) == 0) - *found_bad_meta = true; - - char name_low[meta_prefixes[0].len + name_len + 1]; - snprintf(name_low, meta_prefixes[0].len - 5 + name_len + 1, "%s%s", meta_prefixes[0].str + 5 /* skip HTTP_ */, name); // normalize meta prefix - int j; - for (j = 0; name_low[j]; j++) { - if (name_low[j] != '_') - name_low[j] = tolower(name_low[j]); - else - name_low[j] = '-'; - } - name_low[j] = 0; - - auto it = x_meta_map.find(name_low); - if (it != x_meta_map.end()) { - string old = it->second; - boost::algorithm::trim_right(old); - old.append(","); - old.append(val); - x_meta_map[name_low] = old; - } else { - x_meta_map[name_low] = val; - } - } - } - } - for (const auto& kv: x_meta_map) { - dout(10) << "x>> " << kv.first << ":" << rgw::crypt_sanitize::x_meta_map{kv.first, kv.second} << dendl; - } -} - -std::ostream& operator<<(std::ostream& oss, const rgw_err &err) -{ - oss << "rgw_err(http_ret=" << err.http_ret << ", err_code='" << err.err_code << "') "; - return oss; -} - -string rgw_string_unquote(const string& s) -{ - if (s[0] != '"' || s.size() < 2) - return s; - - int len; - for (len = s.size(); len > 2; --len) { - if (s[len - 1] != ' ') - break; - } - - if (s[len-1] != '"') - return s; - - return s.substr(1, len - 2); -} - -static bool check_str_end(const char *s) -{ - if (!s) - return false; - - while (*s) { - if (!isspace(*s)) - return false; - s++; - } - return true; -} - -static bool check_gmt_end(const char *s) -{ - if (!s || !*s) - return false; - - while (isspace(*s)) { - ++s; - } - - /* check for correct timezone */ - if ((strncmp(s, "GMT", 3) != 0) && - (strncmp(s, "UTC", 3) != 0)) { - return false; - } - - return true; -} - -static bool parse_rfc850(const char *s, struct tm *t) -{ - memset(t, 0, sizeof(*t)); - return check_gmt_end(strptime(s, "%A, %d-%b-%y %H:%M:%S ", t)); -} - -static bool parse_asctime(const char *s, struct tm *t) -{ - memset(t, 0, sizeof(*t)); - return check_str_end(strptime(s, "%a %b %d %H:%M:%S %Y", t)); -} - -static bool parse_rfc1123(const char *s, struct tm *t) -{ - memset(t, 0, sizeof(*t)); - return check_gmt_end(strptime(s, "%a, %d %b %Y %H:%M:%S ", t)); -} - -static bool parse_rfc1123_alt(const char *s, struct tm *t) -{ - memset(t, 0, sizeof(*t)); - return check_str_end(strptime(s, "%a, %d %b %Y %H:%M:%S %z", t)); -} - -bool parse_rfc2616(const char *s, struct tm *t) -{ - return parse_rfc850(s, t) || parse_asctime(s, t) || parse_rfc1123(s, t) || parse_rfc1123_alt(s,t); -} - -bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_format) -{ - memset(t, 0, sizeof(*t)); - const char *p; - - if (!s) - s = ""; - - if (extended_format) { - p = strptime(s, "%Y-%m-%dT%T", t); - if (!p) { - p = strptime(s, "%Y-%m-%d %T", t); - } - } else { - p = strptime(s, "%Y%m%dT%H%M%S", t); - } - if (!p) { - dout(0) << "parse_iso8601 failed" << dendl; - return false; - } - const boost::string_view str = rgw_trim_whitespace(boost::string_view(p)); - int len = str.size(); - - if (len == 0 || (len == 1 && str[0] == 'Z')) - return true; - - if (str[0] != '.' || - str[len - 1] != 'Z') - return false; - - uint32_t ms; - boost::string_view nsstr = str.substr(1, len - 2); - int r = stringtoul(nsstr.to_string(), &ms); - if (r < 0) - return false; - - if (!pns) { - return true; - } - - if (nsstr.size() > 9) { - nsstr = nsstr.substr(0, 9); - } - - uint64_t mul_table[] = { 0, - 100000000LL, - 10000000LL, - 1000000LL, - 100000LL, - 10000LL, - 1000LL, - 100LL, - 10LL, - 1 }; - - - *pns = ms * mul_table[nsstr.size()]; - - return true; -} - -int parse_key_value(string& in_str, const char *delim, string& key, string& val) -{ - if (delim == NULL) - return -EINVAL; - - auto pos = in_str.find(delim); - if (pos == string::npos) - return -EINVAL; - - key = rgw_trim_whitespace(in_str.substr(0, pos)); - val = rgw_trim_whitespace(in_str.substr(pos + 1)); - - return 0; -} - -int parse_key_value(string& in_str, string& key, string& val) -{ - return parse_key_value(in_str, "=", key,val); -} - -boost::optional> -parse_key_value(const boost::string_view& in_str, - const boost::string_view& delim) -{ - const size_t pos = in_str.find(delim); - if (pos == boost::string_view::npos) { - return boost::none; - } - - const auto key = rgw_trim_whitespace(in_str.substr(0, pos)); - const auto val = rgw_trim_whitespace(in_str.substr(pos + 1)); - - return std::make_pair(key, val); -} - -boost::optional> -parse_key_value(const boost::string_view& in_str) -{ - return parse_key_value(in_str, "="); -} - -int parse_time(const char *time_str, real_time *time) -{ - struct tm tm; - uint32_t ns = 0; - - if (!parse_rfc2616(time_str, &tm) && !parse_iso8601(time_str, &tm, &ns)) { - return -EINVAL; - } - - time_t sec = internal_timegm(&tm); - *time = utime_t(sec, ns).to_real_time(); - - return 0; -} - -#define TIME_BUF_SIZE 128 - -void rgw_to_iso8601(const real_time& t, char *dest, int buf_size) -{ - utime_t ut(t); - - char buf[TIME_BUF_SIZE]; - struct tm result; - time_t epoch = ut.sec(); - struct tm *tmp = gmtime_r(&epoch, &result); - if (tmp == NULL) - return; - - if (strftime(buf, sizeof(buf), "%Y-%m-%dT%T", tmp) == 0) - return; - - snprintf(dest, buf_size, "%s.%03dZ", buf, (int)(ut.usec() / 1000)); -} - -void rgw_to_iso8601(const real_time& t, string *dest) -{ - char buf[TIME_BUF_SIZE]; - rgw_to_iso8601(t, buf, sizeof(buf)); - *dest = buf; -} - - -string rgw_to_asctime(const utime_t& t) -{ - stringstream s; - t.asctime(s); - return s.str(); -} - -/* - * calculate the sha1 value of a given msg and key - */ -void calc_hmac_sha1(const char *key, int key_len, - const char *msg, int msg_len, char *dest) -/* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */ -{ - HMACSHA1 hmac((const unsigned char *)key, key_len); - hmac.Update((const unsigned char *)msg, msg_len); - hmac.Final((unsigned char *)dest); -} - -/* - * calculate the sha256 value of a given msg and key - */ -void calc_hmac_sha256(const char *key, int key_len, - const char *msg, int msg_len, char *dest) -{ - char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; - - HMACSHA256 hmac((const unsigned char *)key, key_len); - hmac.Update((const unsigned char *)msg, msg_len); - hmac.Final((unsigned char *)hash_sha256); - - memcpy(dest, hash_sha256, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE); -} - -using ceph::crypto::SHA256; - -/* - * calculate the sha256 hash value of a given msg - */ -sha256_digest_t calc_hash_sha256(const boost::string_view& msg) -{ - std::array hash; - - SHA256 hasher; - hasher.Update(reinterpret_cast(msg.data()), msg.size()); - hasher.Final(hash.data()); - - return hash; -} - -SHA256* calc_hash_sha256_open_stream() -{ - return new SHA256; -} - -void calc_hash_sha256_update_stream(SHA256 *hash, const char *msg, int len) -{ - hash->Update((const unsigned char *)msg, len); -} - -string calc_hash_sha256_close_stream(SHA256 **phash) -{ - SHA256 *hash = *phash; - if (!hash) { - hash = calc_hash_sha256_open_stream(); - } - char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; - - hash->Final((unsigned char *)hash_sha256); - - char hex_str[(CEPH_CRYPTO_SHA256_DIGESTSIZE * 2) + 1]; - buf_to_hex((unsigned char *)hash_sha256, CEPH_CRYPTO_SHA256_DIGESTSIZE, hex_str); - - delete hash; - *phash = NULL; - - return std::string(hex_str); -} - -std::string calc_hash_sha256_restart_stream(SHA256 **phash) -{ - const auto hash = calc_hash_sha256_close_stream(phash); - *phash = calc_hash_sha256_open_stream(); - - return hash; -} - -int gen_rand_base64(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */ -{ - char buf[size]; - char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */ - int ret; - - ret = get_random_bytes(buf, sizeof(buf)); - if (ret < 0) { - lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl; - return ret; - } - - ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)], - (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4); - if (ret < 0) { - lderr(cct) << "ceph_armor failed" << dendl; - return ret; - } - tmp_dest[ret] = '\0'; - memcpy(dest, tmp_dest, size); - dest[size-1] = '\0'; - - return 0; -} - -static const char alphanum_upper_table[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -int gen_rand_alphanumeric_upper(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */ -{ - int ret = get_random_bytes(dest, size); - if (ret < 0) { - lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl; - return ret; - } - - int i; - for (i=0; i= 0) { - string& name = nv.get_name(); - string& val = nv.get_val(); - - append(name, val); - } - - pos = fpos + 1; - } - - return 0; -} - -void RGWHTTPArgs::append(const string& name, const string& val) -{ - if (name.compare(0, sizeof(RGW_SYS_PARAM_PREFIX) - 1, RGW_SYS_PARAM_PREFIX) == 0) { - sys_val_map[name] = val; - } else { - val_map[name] = val; - } - - if ((name.compare("acl") == 0) || - (name.compare("cors") == 0) || - (name.compare("location") == 0) || - (name.compare("logging") == 0) || - (name.compare("usage") == 0) || - (name.compare("lifecycle") == 0) || - (name.compare("delete") == 0) || - (name.compare("uploads") == 0) || - (name.compare("partNumber") == 0) || - (name.compare("uploadId") == 0) || - (name.compare("versionId") == 0) || - (name.compare("start-date") == 0) || - (name.compare("end-date") == 0) || - (name.compare("versions") == 0) || - (name.compare("versioning") == 0) || - (name.compare("website") == 0) || - (name.compare("requestPayment") == 0) || - (name.compare("torrent") == 0) || - (name.compare("tagging") == 0)) { - sub_resources[name] = val; - } else if (name[0] == 'r') { // root of all evil - if ((name.compare("response-content-type") == 0) || - (name.compare("response-content-language") == 0) || - (name.compare("response-expires") == 0) || - (name.compare("response-cache-control") == 0) || - (name.compare("response-content-disposition") == 0) || - (name.compare("response-content-encoding") == 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("quota") == 0) || - (name.compare("object") == 0)) { - - if (!admin_subresource_added) { - sub_resources[name] = ""; - admin_subresource_added = true; - } - } -} - -const string& RGWHTTPArgs::get(const string& name, bool *exists) const -{ - auto iter = val_map.find(name); - bool e = (iter != std::end(val_map)); - if (exists) - *exists = e; - if (e) - return iter->second; - return empty_str; -} - -boost::optional -RGWHTTPArgs::get_optional(const std::string& name) const -{ - bool exists; - const std::string& value = get(name, &exists); - if (exists) { - return value; - } else { - return boost::none; - } -} - -int RGWHTTPArgs::get_bool(const string& name, bool *val, bool *exists) -{ - map::iterator iter; - iter = val_map.find(name); - bool e = (iter != val_map.end()); - if (exists) - *exists = e; - - if (e) { - const char *s = iter->second.c_str(); - - if (strcasecmp(s, "false") == 0) { - *val = false; - } else if (strcasecmp(s, "true") == 0) { - *val = true; - } else { - return -EINVAL; - } - } - - return 0; -} - -int RGWHTTPArgs::get_bool(const char *name, bool *val, bool *exists) -{ - string s(name); - return get_bool(s, val, exists); -} - -void RGWHTTPArgs::get_bool(const char *name, bool *val, bool def_val) -{ - bool exists = false; - if ((get_bool(name, val, &exists) < 0) || - !exists) { - *val = def_val; - } -} - -string RGWHTTPArgs::sys_get(const string& name, bool * const exists) const -{ - const auto iter = sys_val_map.find(name); - const bool e = (iter != sys_val_map.end()); - - if (exists) { - *exists = e; - } - - return e ? iter->second : string(); -} - -bool verify_user_permission(struct req_state * const s, - RGWAccessControlPolicy * const user_acl, - const int perm) -{ - /* S3 doesn't support account ACLs. */ - if (!user_acl) - return true; - - if ((perm & (int)s->perm_mask) != perm) - return false; - - return user_acl->verify_permission(*s->auth.identity, perm, perm); -} - -bool verify_user_permission(struct req_state * const s, - const int perm) -{ - return verify_user_permission(s, s->user_acl.get(), perm); -} - -bool verify_requester_payer_permission(struct req_state *s) -{ - if (!s->bucket_info.requester_pays) - return true; - - if (s->auth.identity->is_owner_of(s->bucket_info.owner)) - return true; - - if (s->auth.identity->is_anonymous()) { - return false; - } - - const char *request_payer = s->info.env->get("HTTP_X_AMZ_REQUEST_PAYER"); - if (!request_payer) { - bool exists; - request_payer = s->info.args.get("x-amz-request-payer", &exists).c_str(); - if (!exists) { - return false; - } - } - - if (strcasecmp(request_payer, "requester") == 0) { - return true; - } - - return false; -} - -bool verify_bucket_permission(struct req_state * const s, - const rgw_bucket& bucket, - RGWAccessControlPolicy * const user_acl, - RGWAccessControlPolicy * const bucket_acl, - const optional& bucket_policy, - const uint64_t op) -{ - if (!verify_requester_payer_permission(s)) - return false; - - if (bucket_policy) { - auto r = bucket_policy->eval(s->env, *s->auth.identity, op, ARN(bucket)); - if (r == Effect::Allow) - // It looks like S3 ACLs only GRANT permissions rather than - // denying them, so this should be safe. - return true; - else if (r == Effect::Deny) - return false; - } - - const auto perm = op_to_perm(op); - - return verify_bucket_permission_no_policy(s, user_acl, bucket_acl, perm); -} - -bool verify_bucket_permission_no_policy(struct req_state * const s, - RGWAccessControlPolicy * const user_acl, - RGWAccessControlPolicy * const bucket_acl, - const int perm) -{ - if (!bucket_acl) - return false; - - if ((perm & (int)s->perm_mask) != perm) - return false; - - if (bucket_acl->verify_permission(*s->auth.identity, perm, perm, - s->info.env->get("HTTP_REFERER"))) - return true; - - if (!user_acl) - return false; - - return user_acl->verify_permission(*s->auth.identity, perm, perm); -} - -bool verify_bucket_permission_no_policy(struct req_state * const s, const int perm) -{ - if (!verify_requester_payer_permission(s)) - return false; - - return verify_bucket_permission_no_policy(s, - s->user_acl.get(), - s->bucket_acl.get(), - perm); -} - -bool verify_bucket_permission(struct req_state * const s, const uint64_t op) -{ - return verify_bucket_permission(s, - s->bucket, - s->user_acl.get(), - s->bucket_acl.get(), - s->iam_policy, - op); -} - -static inline bool check_deferred_bucket_perms(struct req_state * const s, - const rgw_bucket& bucket, - RGWAccessControlPolicy * const user_acl, - RGWAccessControlPolicy * const bucket_acl, - const optional& bucket_policy, - const uint8_t deferred_check, - const uint64_t op) -{ - return (s->defer_to_bucket_acls == deferred_check \ - && verify_bucket_permission(s, bucket, user_acl, bucket_acl, bucket_policy, op)); -} - -static inline bool check_deferred_bucket_only_acl(struct req_state * const s, - RGWAccessControlPolicy * const user_acl, - RGWAccessControlPolicy * const bucket_acl, - const uint8_t deferred_check, - const int perm) -{ - return (s->defer_to_bucket_acls == deferred_check \ - && verify_bucket_permission_no_policy(s, user_acl, bucket_acl, perm)); -} - -bool verify_object_permission(struct req_state * const s, - const rgw_obj& obj, - RGWAccessControlPolicy * const user_acl, - RGWAccessControlPolicy * const bucket_acl, - RGWAccessControlPolicy * const object_acl, - const optional& bucket_policy, - const uint64_t op) -{ - if (!verify_requester_payer_permission(s)) - return false; - - if (bucket_policy) { - auto r = bucket_policy->eval(s->env, *s->auth.identity, op, ARN(obj)); - if (r == Effect::Allow) - // It looks like S3 ACLs only GRANT permissions rather than - // denying them, so this should be safe. - return true; - else if (r == Effect::Deny) - return false; - } - - const auto perm = op_to_perm(op); - - if (check_deferred_bucket_perms(s, obj.bucket, user_acl, bucket_acl, bucket_policy, - RGW_DEFER_TO_BUCKET_ACLS_RECURSE, op) || - check_deferred_bucket_perms(s, obj.bucket, user_acl, bucket_acl, bucket_policy, - RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, rgw::IAM::s3All)) { - return true; - } - - if (!object_acl) { - return false; - } - - bool ret = object_acl->verify_permission(*s->auth.identity, s->perm_mask, perm); - if (ret) { - return true; - } - - if (!s->cct->_conf->rgw_enforce_swift_acls) - return ret; - - if ((perm & (int)s->perm_mask) != perm) - return false; - - int swift_perm = 0; - if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP)) - swift_perm |= RGW_PERM_READ_OBJS; - if (perm & RGW_PERM_WRITE) - swift_perm |= RGW_PERM_WRITE_OBJS; - - if (!swift_perm) - return false; - - /* we already verified the user mask above, so we pass swift_perm as the mask here, - otherwise the mask might not cover the swift permissions bits */ - if (bucket_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm, - s->info.env->get("HTTP_REFERER"))) - return true; - - if (!user_acl) - return false; - - return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm); -} - -bool verify_object_permission_no_policy(struct req_state * const s, - RGWAccessControlPolicy * const user_acl, - RGWAccessControlPolicy * const bucket_acl, - RGWAccessControlPolicy * const object_acl, - const int perm) -{ - if (check_deferred_bucket_only_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_RECURSE, perm) || - check_deferred_bucket_only_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, RGW_PERM_FULL_CONTROL)) { - return true; - } - - if (!object_acl) { - return false; - } - - bool ret = object_acl->verify_permission(*s->auth.identity, s->perm_mask, perm); - if (ret) { - return true; - } - - if (!s->cct->_conf->rgw_enforce_swift_acls) - return ret; - - if ((perm & (int)s->perm_mask) != perm) - return false; - - int swift_perm = 0; - if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP)) - swift_perm |= RGW_PERM_READ_OBJS; - if (perm & RGW_PERM_WRITE) - swift_perm |= RGW_PERM_WRITE_OBJS; - - if (!swift_perm) - return false; - - /* we already verified the user mask above, so we pass swift_perm as the mask here, - otherwise the mask might not cover the swift permissions bits */ - if (bucket_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm, - s->info.env->get("HTTP_REFERER"))) - return true; - - if (!user_acl) - return false; - - return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm); -} - -bool verify_object_permission_no_policy(struct req_state *s, int perm) -{ - if (!verify_requester_payer_permission(s)) - return false; - - return verify_object_permission_no_policy(s, - s->user_acl.get(), - s->bucket_acl.get(), - s->object_acl.get(), - perm); -} - -bool verify_object_permission(struct req_state *s, uint64_t op) -{ - return verify_object_permission(s, - rgw_obj(s->bucket, s->object), - s->user_acl.get(), - s->bucket_acl.get(), - s->object_acl.get(), - s->iam_policy, - op); -} - -class HexTable -{ - char table[256]; - -public: - HexTable() { - memset(table, -1, sizeof(table)); - int i; - for (i = '0'; i<='9'; i++) - table[i] = i - '0'; - for (i = 'A'; i<='F'; i++) - table[i] = i - 'A' + 0xa; - for (i = 'a'; i<='f'; i++) - table[i] = i - 'a' + 0xa; - } - - char to_num(char c) { - return table[(int)c]; - } -}; - -static char hex_to_num(char c) -{ - static HexTable hex_table; - return hex_table.to_num(c); -} - -std::string url_decode(const boost::string_view& src_str, bool in_query) -{ - std::string dest_str; - dest_str.reserve(src_str.length() + 1); - - for (auto src = std::begin(src_str); src != std::end(src_str); ++src) { - if (*src != '%') { - if (!in_query || *src != '+') { - if (*src == '?') { - in_query = true; - } - dest_str.push_back(*src); - } else { - dest_str.push_back(' '); - } - } else { - /* 3 == strlen("%%XX") */ - if (std::distance(src, std::end(src_str)) < 3) { - break; - } - - src++; - const char c1 = hex_to_num(*src++); - const char c2 = hex_to_num(*src); - if (c1 < 0 || c2 < 0) { - return std::string(); - } else { - dest_str.push_back(c1 << 4 | c2); - } - } - } - - return dest_str; -} - -void rgw_uri_escape_char(char c, string& dst) -{ - char buf[16]; - snprintf(buf, sizeof(buf), "%%%.2X", (int)(unsigned char)c); - dst.append(buf); -} - -static bool char_needs_url_encoding(char c) -{ - if (c <= 0x20 || c >= 0x7f) - return true; - - switch (c) { - case 0x22: - case 0x23: - case 0x25: - case 0x26: - case 0x2B: - case 0x2C: - case 0x2F: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3E: - case 0x3D: - case 0x3F: - case 0x40: - case 0x5B: - case 0x5D: - case 0x5C: - case 0x5E: - case 0x60: - case 0x7B: - case 0x7D: - return true; - } - return false; -} - -void url_encode(const string& src, string& dst) -{ - const char *p = src.c_str(); - for (unsigned i = 0; i < src.size(); i++, p++) { - if (char_needs_url_encoding(*p)) { - rgw_uri_escape_char(*p, dst); - continue; - } - - dst.append(p, 1); - } -} - -std::string url_encode(const std::string& src) -{ - std::string dst; - url_encode(src, dst); - - return dst; -} - -string rgw_trim_whitespace(const string& src) -{ - if (src.empty()) { - return string(); - } - - int start = 0; - for (; start != (int)src.size(); start++) { - if (!isspace(src[start])) - break; - } - - int end = src.size() - 1; - if (end < start) { - return string(); - } - - for (; end > start; end--) { - if (!isspace(src[end])) - break; - } - - return src.substr(start, end - start + 1); -} - -boost::string_view rgw_trim_whitespace(const boost::string_view& src) -{ - boost::string_view res = src; - - while (res.size() > 0 && std::isspace(res.front())) { - res.remove_prefix(1); - } - while (res.size() > 0 && std::isspace(res.back())) { - res.remove_suffix(1); - } - return res; -} - -string rgw_trim_quotes(const string& val) -{ - string s = rgw_trim_whitespace(val); - if (s.size() < 2) - return s; - - int start = 0; - int end = s.size() - 1; - int quotes_count = 0; - - if (s[start] == '"') { - start++; - quotes_count++; - } - if (s[end] == '"') { - end--; - quotes_count++; - } - if (quotes_count == 2) { - return s.substr(start, end - start + 1); - } - return s; -} - -struct rgw_name_to_flag { - const char *type_name; - uint32_t flag; -}; - -static int parse_list_of_flags(struct rgw_name_to_flag *mapping, - const string& str, uint32_t *perm) -{ - list strs; - get_str_list(str, strs); - list::iterator iter; - uint32_t v = 0; - for (iter = strs.begin(); iter != strs.end(); ++iter) { - string& s = *iter; - for (int i = 0; mapping[i].type_name; i++) { - if (s.compare(mapping[i].type_name) == 0) - v |= mapping[i].flag; - } - } - - *perm = v; - return 0; -} - -static struct rgw_name_to_flag cap_names[] = { {"*", RGW_CAP_ALL}, - {"read", RGW_CAP_READ}, - {"write", RGW_CAP_WRITE}, - {NULL, 0} }; - -int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm) -{ - return parse_list_of_flags(cap_names, str, perm); -} - -int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm) -{ - int pos = cap.find('='); - if (pos >= 0) { - type = rgw_trim_whitespace(cap.substr(0, pos)); - } - - if (!is_valid_cap_type(type)) - return -ERR_INVALID_CAP; - - string cap_perm; - uint32_t perm = 0; - if (pos < (int)cap.size() - 1) { - cap_perm = cap.substr(pos + 1); - int r = RGWUserCaps::parse_cap_perm(cap_perm, &perm); - if (r < 0) - return r; - } - - *pperm = perm; - - return 0; -} - -int RGWUserCaps::add_cap(const string& cap) -{ - uint32_t perm; - string type; - - int r = get_cap(cap, type, &perm); - if (r < 0) - return r; - - caps[type] |= perm; - - return 0; -} - -int RGWUserCaps::remove_cap(const string& cap) -{ - uint32_t perm; - string type; - - int r = get_cap(cap, type, &perm); - if (r < 0) - return r; - - map::iterator iter = caps.find(type); - if (iter == caps.end()) - return 0; - - uint32_t& old_perm = iter->second; - old_perm &= ~perm; - if (!old_perm) - caps.erase(iter); - - return 0; -} - -int RGWUserCaps::add_from_string(const string& str) -{ - int start = 0; - do { - auto end = str.find(';', start); - if (end == string::npos) - end = str.size(); - - int r = add_cap(str.substr(start, end - start)); - if (r < 0) - return r; - - start = end + 1; - } while (start < (int)str.size()); - - return 0; -} - -int RGWUserCaps::remove_from_string(const string& str) -{ - int start = 0; - do { - auto end = str.find(';', start); - if (end == string::npos) - end = str.size(); - - int r = remove_cap(str.substr(start, end - start)); - if (r < 0) - return r; - - start = end + 1; - } while (start < (int)str.size()); - - return 0; -} - -void RGWUserCaps::dump(Formatter *f) const -{ - dump(f, "caps"); -} - -void RGWUserCaps::dump(Formatter *f, const char *name) const -{ - f->open_array_section(name); - map::const_iterator iter; - for (iter = caps.begin(); iter != caps.end(); ++iter) - { - f->open_object_section("cap"); - f->dump_string("type", iter->first); - uint32_t perm = iter->second; - string perm_str; - for (int i=0; cap_names[i].type_name; i++) { - if ((perm & cap_names[i].flag) == cap_names[i].flag) { - if (perm_str.size()) - perm_str.append(", "); - - perm_str.append(cap_names[i].type_name); - perm &= ~cap_names[i].flag; - } - } - if (perm_str.empty()) - perm_str = ""; - - f->dump_string("perm", perm_str); - f->close_section(); - } - - f->close_section(); -} - -struct RGWUserCap { - string type; - uint32_t perm; - - void decode_json(JSONObj *obj) { - JSONDecoder::decode_json("type", type, obj); - string perm_str; - JSONDecoder::decode_json("perm", perm_str, obj); - if (RGWUserCaps::parse_cap_perm(perm_str, &perm) < 0) { - throw JSONDecoder::err("failed to parse permissions"); - } - } -}; - -void RGWUserCaps::decode_json(JSONObj *obj) -{ - list caps_list; - decode_json_obj(caps_list, obj); - - list::iterator iter; - for (iter = caps_list.begin(); iter != caps_list.end(); ++iter) { - RGWUserCap& cap = *iter; - caps[cap.type] = cap.perm; - } -} - -int RGWUserCaps::check_cap(const string& cap, uint32_t perm) -{ - map::iterator iter = caps.find(cap); - - if ((iter == caps.end()) || - (iter->second & perm) != perm) { - return -EPERM; - } - - return 0; -} - -bool RGWUserCaps::is_valid_cap_type(const string& tp) -{ - static const char *cap_type[] = { "user", - "users", - "buckets", - "metadata", - "usage", - "zone", - "bilog", - "mdlog", - "datalog", - "opstate" }; - - for (unsigned int i = 0; i < sizeof(cap_type) / sizeof(char *); ++i) { - if (tp.compare(cap_type[i]) == 0) { - return true; - } - } - - return false; -} - -static ssize_t unescape_str(const string& s, ssize_t ofs, char esc_char, char special_char, string *dest) -{ - const char *src = s.c_str(); - char dest_buf[s.size() + 1]; - char *destp = dest_buf; - bool esc = false; - - dest_buf[0] = '\0'; - - for (size_t i = ofs; i < s.size(); i++) { - char c = src[i]; - if (!esc && c == esc_char) { - esc = true; - continue; - } - if (!esc && c == special_char) { - *destp = '\0'; - *dest = dest_buf; - return (ssize_t)i + 1; - } - *destp++ = c; - esc = false; - } - *destp = '\0'; - *dest = dest_buf; - return string::npos; -} - -static void escape_str(const string& s, char esc_char, char special_char, string *dest) -{ - const char *src = s.c_str(); - char dest_buf[s.size() * 2 + 1]; - char *destp = dest_buf; - - for (size_t i = 0; i < s.size(); i++) { - char c = src[i]; - if (c == esc_char || c == special_char) { - *destp++ = esc_char; - } - *destp++ = c; - } - *destp++ = '\0'; - *dest = dest_buf; -} - -void rgw_pool::from_str(const string& s) -{ - size_t pos = unescape_str(s, 0, '\\', ':', &name); - if (pos != string::npos) { - pos = unescape_str(s, pos, '\\', ':', &ns); - /* ignore return; if pos != string::npos it means that we had a colon - * in the middle of ns that wasn't escaped, we're going to stop there - */ - } -} - -string rgw_pool::to_str() const -{ - string esc_name; - escape_str(name, '\\', ':', &esc_name); - if (ns.empty()) { - return esc_name; - } - string esc_ns; - escape_str(ns, '\\', ':', &esc_ns); - return esc_name + ":" + esc_ns; -} - -void rgw_raw_obj::decode_from_rgw_obj(bufferlist::iterator& bl) -{ - rgw_obj old_obj; - ::decode(old_obj, bl); - - get_obj_bucket_and_oid_loc(old_obj, oid, loc); - pool = old_obj.get_explicit_data_pool(); -} - -std::string rgw_bucket::get_key(char tenant_delim, char id_delim) const -{ - static constexpr size_t shard_len{12}; // ":4294967295\0" - const size_t max_len = tenant.size() + sizeof(tenant_delim) + - name.size() + sizeof(id_delim) + bucket_id.size() + shard_len; - - std::string key; - key.reserve(max_len); - if (!tenant.empty() && tenant_delim) { - key.append(tenant); - key.append(1, tenant_delim); - } - key.append(name); - if (!bucket_id.empty() && id_delim) { - key.append(1, id_delim); - key.append(bucket_id); - } - return key; -} - -std::string rgw_bucket_shard::get_key(char tenant_delim, char id_delim, - char shard_delim) const -{ - auto key = bucket.get_key(tenant_delim, id_delim); - if (shard_id >= 0 && shard_delim) { - key.append(1, shard_delim); - key.append(std::to_string(shard_id)); - } - return key; -} - -static struct rgw_name_to_flag op_type_mapping[] = { {"*", RGW_OP_TYPE_ALL}, - {"read", RGW_OP_TYPE_READ}, - {"write", RGW_OP_TYPE_WRITE}, - {"delete", RGW_OP_TYPE_DELETE}, - {NULL, 0} }; - - -int rgw_parse_op_type_list(const string& str, uint32_t *perm) -{ - return parse_list_of_flags(op_type_mapping, str, perm); -} - -bool match_policy(boost::string_view pattern, boost::string_view input, - uint32_t flag) -{ - const uint32_t flag2 = flag & (MATCH_POLICY_ACTION|MATCH_POLICY_ARN) ? - MATCH_CASE_INSENSITIVE : 0; - - const auto npos = boost::string_view::npos; - boost::string_view::size_type last_pos_input = 0, last_pos_pattern = 0; - while (true) { - auto cur_pos_input = input.find(":", last_pos_input); - auto cur_pos_pattern = pattern.find(":", last_pos_pattern); - - auto substr_input = input.substr(last_pos_input, cur_pos_input); - auto substr_pattern = pattern.substr(last_pos_pattern, cur_pos_pattern); - - if (!match_wildcards(substr_pattern, substr_input, flag2)) - return false; - - if (cur_pos_pattern == npos) - return cur_pos_input == npos; - if (cur_pos_input == npos) - return false; - - last_pos_pattern = cur_pos_pattern + 1; - last_pos_input = cur_pos_input + 1; - } -}