Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_common.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <errno.h>
5 #include <vector>
6 #include <algorithm>
7 #include <string>
8 #include <boost/tokenizer.hpp>
9 #include <boost/algorithm/string.hpp>
10 #include <boost/utility/string_view.hpp>
11
12 #include "json_spirit/json_spirit.h"
13 #include "common/ceph_json.h"
14
15 #include "rgw_op.h"
16 #include "rgw_common.h"
17 #include "rgw_acl.h"
18 #include "rgw_string.h"
19 #include "rgw_rados.h"
20 #include "rgw_http_errors.h"
21
22 #include "common/ceph_crypto.h"
23 #include "common/armor.h"
24 #include "common/errno.h"
25 #include "common/Clock.h"
26 #include "common/Formatter.h"
27 #include "common/perf_counters.h"
28 #include "common/strtol.h"
29 #include "include/str_list.h"
30 #include "auth/Crypto.h"
31 #include "rgw_crypt_sanitize.h"
32
33 #include <sstream>
34
35 #define dout_context g_ceph_context
36 #define dout_subsys ceph_subsys_rgw
37
38 using boost::none;
39 using boost::optional;
40
41 using rgw::IAM::ARN;
42 using rgw::IAM::Effect;
43 using rgw::IAM::op_to_perm;
44 using rgw::IAM::Policy;
45
46 PerfCounters *perfcounter = NULL;
47
48 const uint32_t RGWBucketInfo::NUM_SHARDS_BLIND_BUCKET(UINT32_MAX);
49
50 rgw_http_errors rgw_http_s3_errors({
51     { 0, {200, "" }},
52     { STATUS_CREATED, {201, "Created" }},
53     { STATUS_ACCEPTED, {202, "Accepted" }},
54     { STATUS_NO_CONTENT, {204, "NoContent" }},
55     { STATUS_PARTIAL_CONTENT, {206, "" }},
56     { ERR_PERMANENT_REDIRECT, {301, "PermanentRedirect" }},
57     { ERR_WEBSITE_REDIRECT, {301, "WebsiteRedirect" }},
58     { STATUS_REDIRECT, {303, "" }},
59     { ERR_NOT_MODIFIED, {304, "NotModified" }},
60     { EINVAL, {400, "InvalidArgument" }},
61     { ERR_INVALID_REQUEST, {400, "InvalidRequest" }},
62     { ERR_INVALID_DIGEST, {400, "InvalidDigest" }},
63     { ERR_BAD_DIGEST, {400, "BadDigest" }},
64     { ERR_INVALID_LOCATION_CONSTRAINT, {400, "InvalidLocationConstraint" }},
65     { ERR_ZONEGROUP_DEFAULT_PLACEMENT_MISCONFIGURATION, {400, "ZonegroupDefaultPlacementMisconfiguration" }},
66     { ERR_INVALID_BUCKET_NAME, {400, "InvalidBucketName" }},
67     { ERR_INVALID_OBJECT_NAME, {400, "InvalidObjectName" }},
68     { ERR_UNRESOLVABLE_EMAIL, {400, "UnresolvableGrantByEmailAddress" }},
69     { ERR_INVALID_PART, {400, "InvalidPart" }},
70     { ERR_INVALID_PART_ORDER, {400, "InvalidPartOrder" }},
71     { ERR_REQUEST_TIMEOUT, {400, "RequestTimeout" }},
72     { ERR_TOO_LARGE, {400, "EntityTooLarge" }},
73     { ERR_TOO_SMALL, {400, "EntityTooSmall" }},
74     { ERR_TOO_MANY_BUCKETS, {400, "TooManyBuckets" }},
75     { ERR_MALFORMED_XML, {400, "MalformedXML" }},
76     { ERR_AMZ_CONTENT_SHA256_MISMATCH, {400, "XAmzContentSHA256Mismatch" }},
77     { ERR_INVALID_TAG, {400, "InvalidTag"}},
78     { ERR_MALFORMED_ACL_ERROR, {400, "MalformedACLError" }},
79     { ERR_INVALID_ENCRYPTION_ALGORITHM, {400, "InvalidEncryptionAlgorithmError" }},
80     { ERR_LENGTH_REQUIRED, {411, "MissingContentLength" }},
81     { EACCES, {403, "AccessDenied" }},
82     { EPERM, {403, "AccessDenied" }},
83     { ERR_SIGNATURE_NO_MATCH, {403, "SignatureDoesNotMatch" }},
84     { ERR_INVALID_ACCESS_KEY, {403, "InvalidAccessKeyId" }},
85     { ERR_USER_SUSPENDED, {403, "UserSuspended" }},
86     { ERR_REQUEST_TIME_SKEWED, {403, "RequestTimeTooSkewed" }},
87     { ERR_QUOTA_EXCEEDED, {403, "QuotaExceeded" }},
88     { ENOENT, {404, "NoSuchKey" }},
89     { ERR_NO_SUCH_BUCKET, {404, "NoSuchBucket" }},
90     { ERR_NO_SUCH_WEBSITE_CONFIGURATION, {404, "NoSuchWebsiteConfiguration" }},
91     { ERR_NO_SUCH_UPLOAD, {404, "NoSuchUpload" }},
92     { ERR_NOT_FOUND, {404, "Not Found"}},
93     { ERR_NO_SUCH_LC, {404, "NoSuchLifecycleConfiguration"}},
94     { ERR_NO_SUCH_BUCKET_POLICY, {404, "NoSuchBucketPolicy"}},
95     { ERR_NO_SUCH_USER, {404, "NoSuchUser"}},
96     { ERR_NO_SUCH_SUBUSER, {404, "NoSuchSubUser"}},
97     { ERR_METHOD_NOT_ALLOWED, {405, "MethodNotAllowed" }},
98     { ETIMEDOUT, {408, "RequestTimeout" }},
99     { EEXIST, {409, "BucketAlreadyExists" }},
100     { ERR_USER_EXIST, {409, "UserAlreadyExists" }},
101     { ERR_EMAIL_EXIST, {409, "EmailExists" }},
102     { ERR_KEY_EXIST, {409, "KeyExists"}},
103     { ERR_TAG_CONFLICT, {409, "OperationAborted"}},
104     { ERR_INVALID_SECRET_KEY, {400, "InvalidSecretKey"}},
105     { ERR_INVALID_KEY_TYPE, {400, "InvalidKeyType"}},
106     { ERR_INVALID_CAP, {400, "InvalidCapability"}},
107     { ERR_INVALID_TENANT_NAME, {400, "InvalidTenantName" }},
108     { ENOTEMPTY, {409, "BucketNotEmpty" }},
109     { ERR_PRECONDITION_FAILED, {412, "PreconditionFailed" }},
110     { ERANGE, {416, "InvalidRange" }},
111     { ERR_UNPROCESSABLE_ENTITY, {422, "UnprocessableEntity" }},
112     { ERR_LOCKED, {423, "Locked" }},
113     { ERR_INTERNAL_ERROR, {500, "InternalError" }},
114     { ERR_NOT_IMPLEMENTED, {501, "NotImplemented" }},
115     { ERR_SERVICE_UNAVAILABLE, {503, "ServiceUnavailable"}},
116     { ERR_ZERO_IN_URL, {400, "InvalidRequest" }},
117 });
118
119 rgw_http_errors rgw_http_swift_errors({
120     { EACCES, {403, "AccessDenied" }},
121     { EPERM, {401, "AccessDenied" }},
122     { ENAMETOOLONG, {400, "Metadata name too long" }},
123     { ERR_USER_SUSPENDED, {401, "UserSuspended" }},
124     { ERR_INVALID_UTF8, {412, "Invalid UTF8" }},
125     { ERR_BAD_URL, {412, "Bad URL" }},
126     { ERR_NOT_SLO_MANIFEST, {400, "Not an SLO manifest" }},
127     { ERR_QUOTA_EXCEEDED, {413, "QuotaExceeded" }},
128     { ENOTEMPTY, {409, "There was a conflict when trying "
129                        "to complete your request." }},
130     /* FIXME(rzarzynski): we need to find a way to apply Swift's error handling
131      * procedures also for ERR_ZERO_IN_URL. This make a problem as the validation
132      * is performed very early, even before setting the req_state::proto_flags. */
133     { ERR_ZERO_IN_URL, {412, "Invalid UTF8 or contains NULL"}},
134 });
135
136 int rgw_perf_start(CephContext *cct)
137 {
138   PerfCountersBuilder plb(cct, cct->_conf->name.to_str(), l_rgw_first, l_rgw_last);
139
140   plb.add_u64_counter(l_rgw_req, "req", "Requests");
141   plb.add_u64_counter(l_rgw_failed_req, "failed_req", "Aborted requests");
142
143   plb.add_u64_counter(l_rgw_get, "get", "Gets");
144   plb.add_u64_counter(l_rgw_get_b, "get_b", "Size of gets");
145   plb.add_time_avg(l_rgw_get_lat, "get_initial_lat", "Get latency");
146   plb.add_u64_counter(l_rgw_put, "put", "Puts");
147   plb.add_u64_counter(l_rgw_put_b, "put_b", "Size of puts");
148   plb.add_time_avg(l_rgw_put_lat, "put_initial_lat", "Put latency");
149
150   plb.add_u64(l_rgw_qlen, "qlen", "Queue length");
151   plb.add_u64(l_rgw_qactive, "qactive", "Active requests queue");
152
153   plb.add_u64_counter(l_rgw_cache_hit, "cache_hit", "Cache hits");
154   plb.add_u64_counter(l_rgw_cache_miss, "cache_miss", "Cache miss");
155
156   plb.add_u64_counter(l_rgw_keystone_token_cache_hit, "keystone_token_cache_hit", "Keystone token cache hits");
157   plb.add_u64_counter(l_rgw_keystone_token_cache_miss, "keystone_token_cache_miss", "Keystone token cache miss");
158
159   perfcounter = plb.create_perf_counters();
160   cct->get_perfcounters_collection()->add(perfcounter);
161   return 0;
162 }
163
164 void rgw_perf_stop(CephContext *cct)
165 {
166   assert(perfcounter);
167   cct->get_perfcounters_collection()->remove(perfcounter);
168   delete perfcounter;
169 }
170
171 using namespace ceph::crypto;
172
173 rgw_err::
174 rgw_err()
175 {
176   clear();
177 }
178
179 void rgw_err::
180 clear()
181 {
182   http_ret = 200;
183   ret = 0;
184   err_code.clear();
185 }
186
187 bool rgw_err::
188 is_clear() const
189 {
190   return (http_ret == 200);
191 }
192
193 bool rgw_err::
194 is_err() const
195 {
196   return !(http_ret >= 200 && http_ret <= 399);
197 }
198
199 // The requestURI transferred from the frontend can be abs_path or absoluteURI
200 // If it is absoluteURI, we should adjust it to abs_path for the following 
201 // S3 authorization and some other processes depending on the requestURI
202 // The absoluteURI can start with "http://", "https://", "ws://" or "wss://"
203 static string get_abs_path(const string& request_uri) {
204   const static string ABS_PREFIXS[] = {"http://", "https://", "ws://", "wss://"};
205   bool isAbs = false;
206   for (int i = 0; i < 4; ++i) {
207     if (boost::algorithm::starts_with(request_uri, ABS_PREFIXS[i])) {
208       isAbs = true;
209       break;
210     } 
211   }
212   if (!isAbs) {  // it is not a valid absolute uri
213     return request_uri;
214   }
215   size_t beg_pos = request_uri.find("://") + 3;
216   size_t len = request_uri.size();
217   beg_pos = request_uri.find('/', beg_pos);
218   if (beg_pos == string::npos) return request_uri;
219   return request_uri.substr(beg_pos, len - beg_pos);
220 }
221
222 req_info::req_info(CephContext *cct, const class RGWEnv *env) : env(env) {
223   method = env->get("REQUEST_METHOD", "");
224   script_uri = env->get("SCRIPT_URI", cct->_conf->rgw_script_uri.c_str());
225   request_uri = env->get("REQUEST_URI", cct->_conf->rgw_request_uri.c_str());
226   if (request_uri[0] != '/') {
227     request_uri = get_abs_path(request_uri);
228   }
229   auto pos = request_uri.find('?');
230   if (pos != string::npos) {
231     request_params = request_uri.substr(pos + 1);
232     request_uri = request_uri.substr(0, pos);
233   } else {
234     request_params = env->get("QUERY_STRING", "");
235   }
236   host = env->get("HTTP_HOST", "");
237
238   // strip off any trailing :port from host (added by CrossFTP and maybe others)
239   size_t colon_offset = host.find_last_of(':');
240   if (colon_offset != string::npos) {
241     bool all_digits = true;
242     for (unsigned i = colon_offset + 1; i < host.size(); ++i) {
243       if (!isdigit(host[i])) {
244         all_digits = false;
245         break;
246       }
247     }
248     if (all_digits) {
249       host.resize(colon_offset);
250     }
251   }
252 }
253
254 void req_info::rebuild_from(req_info& src)
255 {
256   method = src.method;
257   script_uri = src.script_uri;
258   args = src.args;
259   if (src.effective_uri.empty()) {
260     request_uri = src.request_uri;
261   } else {
262     request_uri = src.effective_uri;
263   }
264   effective_uri.clear();
265   host = src.host;
266
267   x_meta_map = src.x_meta_map;
268   x_meta_map.erase("x-amz-date");
269 }
270
271
272 req_state::req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u)
273   : cct(_cct), cio(NULL), op(OP_UNKNOWN), user(u), has_acl_header(false),
274     info(_cct, e)
275 {
276   enable_ops_log = e->conf.enable_ops_log;
277   enable_usage_log = e->conf.enable_usage_log;
278   defer_to_bucket_acls = e->conf.defer_to_bucket_acls;
279   content_started = false;
280   format = 0;
281   formatter = NULL;
282   expect_cont = false;
283
284   obj_size = 0;
285   prot_flags = 0;
286
287   system_request = false;
288
289   time = ceph_clock_now();
290   perm_mask = 0;
291   bucket_instance_shard_id = -1;
292   content_length = 0;
293   bucket_exists = false;
294   has_bad_meta = false;
295   length = NULL;
296   local_source = false;
297
298   obj_ctx = NULL;
299 }
300
301 req_state::~req_state() {
302   delete formatter;
303 }
304
305 bool search_err(rgw_http_errors& errs, int err_no, bool is_website_redirect, int& http_ret, string& code)
306 {
307   auto r = errs.find(err_no);
308   if (r != errs.end()) {
309     if (! is_website_redirect)
310       http_ret = r->second.first;
311      code = r->second.second;
312      return true;
313   }
314   return false;
315 }
316
317 void set_req_state_err(struct rgw_err& err,     /* out */
318                         int err_no,             /* in  */
319                         const int prot_flags)   /* in  */
320 {
321   if (err_no < 0)
322     err_no = -err_no;
323
324   err.ret = -err_no;
325   bool is_website_redirect = false;
326
327   if (prot_flags & RGW_REST_SWIFT) {
328     if (search_err(rgw_http_swift_errors, err_no, is_website_redirect, err.http_ret, err.err_code))
329       return;
330   }
331
332   //Default to searching in s3 errors
333   is_website_redirect |= (prot_flags & RGW_REST_WEBSITE)
334                 && err_no == ERR_WEBSITE_REDIRECT && err.is_clear();
335   if (search_err(rgw_http_s3_errors, err_no, is_website_redirect, err.http_ret, err.err_code))
336       return;
337   dout(0) << "WARNING: set_req_state_err err_no=" << err_no
338         << " resorting to 500" << dendl;
339
340   err.http_ret = 500;
341   err.err_code = "UnknownError";
342 }
343
344 void set_req_state_err(struct req_state* s, int err_no, const string& err_msg)
345 {
346   if (s) {
347     set_req_state_err(s, err_no);
348     if (s->prot_flags & RGW_REST_SWIFT && !err_msg.empty()) {
349       /* TODO(rzarzynski): there never ever should be a check like this one.
350        * It's here only for the sake of the patch's backportability. Further
351        * commits will move the logic to a per-RGWHandler replacement of
352        * the end_header() function. Alternativaly, we might consider making
353        * that just for the dump(). Please take a look on @cbodley's comments
354        * in PR #10690 (https://github.com/ceph/ceph/pull/10690). */
355       s->err.err_code = err_msg;
356     } else {
357       s->err.message = err_msg;
358     }
359   }
360 }
361
362 void set_req_state_err(struct req_state* s, int err_no)
363 {
364   if (s) {
365     set_req_state_err(s->err, err_no, s->prot_flags);
366   }
367 }
368
369 void dump(struct req_state* s)
370 {
371   if (s->format != RGW_FORMAT_HTML)
372     s->formatter->open_object_section("Error");
373   if (!s->err.err_code.empty())
374     s->formatter->dump_string("Code", s->err.err_code);
375   if (!s->err.message.empty())
376     s->formatter->dump_string("Message", s->err.message);
377   if (!s->bucket_name.empty())  // TODO: connect to expose_bucket
378     s->formatter->dump_string("BucketName", s->bucket_name);
379   if (!s->trans_id.empty())     // TODO: connect to expose_bucket or another toggle
380     s->formatter->dump_string("RequestId", s->trans_id);
381   s->formatter->dump_string("HostId", s->host_id);
382   if (s->format != RGW_FORMAT_HTML)
383     s->formatter->close_section();
384 }
385
386 struct str_len {
387   const char *str;
388   int len;
389 };
390
391 #define STR_LEN_ENTRY(s) { s, sizeof(s) - 1 }
392
393 struct str_len meta_prefixes[] = { STR_LEN_ENTRY("HTTP_X_AMZ"),
394                                    STR_LEN_ENTRY("HTTP_X_GOOG"),
395                                    STR_LEN_ENTRY("HTTP_X_DHO"),
396                                    STR_LEN_ENTRY("HTTP_X_RGW"),
397                                    STR_LEN_ENTRY("HTTP_X_OBJECT"),
398                                    STR_LEN_ENTRY("HTTP_X_CONTAINER"),
399                                    STR_LEN_ENTRY("HTTP_X_ACCOUNT"),
400                                    {NULL, 0} };
401
402
403 void req_info::init_meta_info(bool *found_bad_meta)
404 {
405   x_meta_map.clear();
406
407   for (const auto& kv: env->get_map()) {
408     const char *prefix;
409     const string& header_name = kv.first;
410     const string& val = kv.second;
411     for (int prefix_num = 0; (prefix = meta_prefixes[prefix_num].str) != NULL; prefix_num++) {
412       int len = meta_prefixes[prefix_num].len;
413       const char *p = header_name.c_str();
414       if (strncmp(p, prefix, len) == 0) {
415         dout(10) << "meta>> " << p << dendl;
416         const char *name = p+len; /* skip the prefix */
417         int name_len = header_name.size() - len;
418
419         if (found_bad_meta && strncmp(name, "_META_", name_len) == 0)
420           *found_bad_meta = true;
421
422         char name_low[meta_prefixes[0].len + name_len + 1];
423         snprintf(name_low, meta_prefixes[0].len - 5 + name_len + 1, "%s%s", meta_prefixes[0].str + 5 /* skip HTTP_ */, name); // normalize meta prefix
424         int j;
425         for (j = 0; name_low[j]; j++) {
426           if (name_low[j] != '_')
427             name_low[j] = tolower(name_low[j]);
428           else
429             name_low[j] = '-';
430         }
431         name_low[j] = 0;
432
433         auto it = x_meta_map.find(name_low);
434         if (it != x_meta_map.end()) {
435           string old = it->second;
436           boost::algorithm::trim_right(old);
437           old.append(",");
438           old.append(val);
439           x_meta_map[name_low] = old;
440         } else {
441           x_meta_map[name_low] = val;
442         }
443       }
444     }
445   }
446   for (const auto& kv: x_meta_map) {
447     dout(10) << "x>> " << kv.first << ":" << rgw::crypt_sanitize::x_meta_map{kv.first, kv.second} << dendl;
448   }
449 }
450
451 std::ostream& operator<<(std::ostream& oss, const rgw_err &err)
452 {
453   oss << "rgw_err(http_ret=" << err.http_ret << ", err_code='" << err.err_code << "') ";
454   return oss;
455 }
456
457 string rgw_string_unquote(const string& s)
458 {
459   if (s[0] != '"' || s.size() < 2)
460     return s;
461
462   int len;
463   for (len = s.size(); len > 2; --len) {
464     if (s[len - 1] != ' ')
465       break;
466   }
467
468   if (s[len-1] != '"')
469     return s;
470
471   return s.substr(1, len - 2);
472 }
473
474 static bool check_str_end(const char *s)
475 {
476   if (!s)
477     return false;
478
479   while (*s) {
480     if (!isspace(*s))
481       return false;
482     s++;
483   }
484   return true;
485 }
486
487 static bool check_gmt_end(const char *s)
488 {
489   if (!s || !*s)
490     return false;
491
492   while (isspace(*s)) {
493     ++s;
494   }
495
496   /* check for correct timezone */
497   if ((strncmp(s, "GMT", 3) != 0) &&
498       (strncmp(s, "UTC", 3) != 0)) {
499     return false;
500   }
501
502   return true;
503 }
504
505 static bool parse_rfc850(const char *s, struct tm *t)
506 {
507   memset(t, 0, sizeof(*t));
508   return check_gmt_end(strptime(s, "%A, %d-%b-%y %H:%M:%S ", t));
509 }
510
511 static bool parse_asctime(const char *s, struct tm *t)
512 {
513   memset(t, 0, sizeof(*t));
514   return check_str_end(strptime(s, "%a %b %d %H:%M:%S %Y", t));
515 }
516
517 static bool parse_rfc1123(const char *s, struct tm *t)
518 {
519   memset(t, 0, sizeof(*t));
520   return check_gmt_end(strptime(s, "%a, %d %b %Y %H:%M:%S ", t));
521 }
522
523 static bool parse_rfc1123_alt(const char *s, struct tm *t)
524 {
525   memset(t, 0, sizeof(*t));
526   return check_str_end(strptime(s, "%a, %d %b %Y %H:%M:%S %z", t));
527 }
528
529 bool parse_rfc2616(const char *s, struct tm *t)
530 {
531   return parse_rfc850(s, t) || parse_asctime(s, t) || parse_rfc1123(s, t) || parse_rfc1123_alt(s,t);
532 }
533
534 bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_format)
535 {
536   memset(t, 0, sizeof(*t));
537   const char *p;
538
539   if (!s)
540     s = "";
541
542   if (extended_format) {
543     p = strptime(s, "%Y-%m-%dT%T", t);
544     if (!p) {
545       p = strptime(s, "%Y-%m-%d %T", t);
546     }
547   } else {
548     p = strptime(s, "%Y%m%dT%H%M%S", t);
549   }
550   if (!p) {
551     dout(0) << "parse_iso8601 failed" << dendl;
552     return false;
553   }
554   const boost::string_view str = rgw_trim_whitespace(boost::string_view(p));
555   int len = str.size();
556
557   if (len == 0 || (len == 1 && str[0] == 'Z'))
558     return true;
559
560   if (str[0] != '.' ||
561       str[len - 1] != 'Z')
562     return false;
563
564   uint32_t ms;
565   boost::string_view nsstr = str.substr(1,  len - 2);
566   int r = stringtoul(nsstr.to_string(), &ms);
567   if (r < 0)
568     return false;
569
570   if (!pns) {
571     return true;
572   }
573
574   if (nsstr.size() > 9) {
575     nsstr = nsstr.substr(0, 9);
576   }
577
578   uint64_t mul_table[] = { 0,
579     100000000LL,
580     10000000LL,
581     1000000LL,
582     100000LL,
583     10000LL,
584     1000LL,
585     100LL,
586     10LL,
587     1 };
588
589
590   *pns = ms * mul_table[nsstr.size()];
591
592   return true;
593 }
594
595 int parse_key_value(string& in_str, const char *delim, string& key, string& val)
596 {
597   if (delim == NULL)
598     return -EINVAL;
599
600   auto pos = in_str.find(delim);
601   if (pos == string::npos)
602     return -EINVAL;
603
604   key = rgw_trim_whitespace(in_str.substr(0, pos));
605   val = rgw_trim_whitespace(in_str.substr(pos + 1));
606
607   return 0;
608 }
609
610 int parse_key_value(string& in_str, string& key, string& val)
611 {
612   return parse_key_value(in_str, "=", key,val);
613 }
614
615 boost::optional<std::pair<boost::string_view, boost::string_view>>
616 parse_key_value(const boost::string_view& in_str,
617                 const boost::string_view& delim)
618 {
619   const size_t pos = in_str.find(delim);
620   if (pos == boost::string_view::npos) {
621     return boost::none;
622   }
623
624   const auto key = rgw_trim_whitespace(in_str.substr(0, pos));
625   const auto val = rgw_trim_whitespace(in_str.substr(pos + 1));
626
627   return std::make_pair(key, val);
628 }
629
630 boost::optional<std::pair<boost::string_view, boost::string_view>>
631 parse_key_value(const boost::string_view& in_str)
632 {
633   return parse_key_value(in_str, "=");
634 }
635
636 int parse_time(const char *time_str, real_time *time)
637 {
638   struct tm tm;
639   uint32_t ns = 0;
640
641   if (!parse_rfc2616(time_str, &tm) && !parse_iso8601(time_str, &tm, &ns)) {
642     return -EINVAL;
643   }
644
645   time_t sec = internal_timegm(&tm);
646   *time = utime_t(sec, ns).to_real_time();
647
648   return 0;
649 }
650
651 #define TIME_BUF_SIZE 128
652
653 void rgw_to_iso8601(const real_time& t, char *dest, int buf_size)
654 {
655   utime_t ut(t);
656
657   char buf[TIME_BUF_SIZE];
658   struct tm result;
659   time_t epoch = ut.sec();
660   struct tm *tmp = gmtime_r(&epoch, &result);
661   if (tmp == NULL)
662     return;
663
664   if (strftime(buf, sizeof(buf), "%Y-%m-%dT%T", tmp) == 0)
665     return;
666
667   snprintf(dest, buf_size, "%s.%03dZ", buf, (int)(ut.usec() / 1000));
668 }
669
670 void rgw_to_iso8601(const real_time& t, string *dest)
671 {
672   char buf[TIME_BUF_SIZE];
673   rgw_to_iso8601(t, buf, sizeof(buf));
674   *dest = buf;
675 }
676
677
678 string rgw_to_asctime(const utime_t& t)
679 {
680   stringstream s;
681   t.asctime(s);
682   return s.str();
683 }
684
685 /*
686  * calculate the sha1 value of a given msg and key
687  */
688 void calc_hmac_sha1(const char *key, int key_len,
689                     const char *msg, int msg_len, char *dest)
690 /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */
691 {
692   HMACSHA1 hmac((const unsigned char *)key, key_len);
693   hmac.Update((const unsigned char *)msg, msg_len);
694   hmac.Final((unsigned char *)dest);
695 }
696
697 /*
698  * calculate the sha256 value of a given msg and key
699  */
700 void calc_hmac_sha256(const char *key, int key_len,
701                       const char *msg, int msg_len, char *dest)
702 {
703   char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
704
705   HMACSHA256 hmac((const unsigned char *)key, key_len);
706   hmac.Update((const unsigned char *)msg, msg_len);
707   hmac.Final((unsigned char *)hash_sha256);
708
709   memcpy(dest, hash_sha256, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE);
710 }
711
712 using ceph::crypto::SHA256;
713
714 /*
715  * calculate the sha256 hash value of a given msg
716  */
717 sha256_digest_t calc_hash_sha256(const boost::string_view& msg)
718 {
719   std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE> hash;
720
721   SHA256 hasher;
722   hasher.Update(reinterpret_cast<const unsigned char*>(msg.data()), msg.size());
723   hasher.Final(hash.data());
724
725   return hash;
726 }
727
728 SHA256* calc_hash_sha256_open_stream()
729 {
730   return new SHA256;
731 }
732
733 void calc_hash_sha256_update_stream(SHA256 *hash, const char *msg, int len)
734 {
735   hash->Update((const unsigned char *)msg, len);
736 }
737
738 string calc_hash_sha256_close_stream(SHA256 **phash)
739 {
740   SHA256 *hash = *phash;
741   if (!hash) {
742     hash = calc_hash_sha256_open_stream();
743   }
744   char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
745
746   hash->Final((unsigned char *)hash_sha256);
747
748   char hex_str[(CEPH_CRYPTO_SHA256_DIGESTSIZE * 2) + 1];
749   buf_to_hex((unsigned char *)hash_sha256, CEPH_CRYPTO_SHA256_DIGESTSIZE, hex_str);
750
751   delete hash;
752   *phash = NULL;
753   
754   return std::string(hex_str);
755 }
756
757 std::string calc_hash_sha256_restart_stream(SHA256 **phash)
758 {
759   const auto hash = calc_hash_sha256_close_stream(phash);
760   *phash = calc_hash_sha256_open_stream();
761
762   return hash;
763 }
764
765 int gen_rand_base64(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
766 {
767   char buf[size];
768   char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */
769   int ret;
770
771   ret = get_random_bytes(buf, sizeof(buf));
772   if (ret < 0) {
773     lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
774     return ret;
775   }
776
777   ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)],
778                    (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4);
779   if (ret < 0) {
780     lderr(cct) << "ceph_armor failed" << dendl;
781     return ret;
782   }
783   tmp_dest[ret] = '\0';
784   memcpy(dest, tmp_dest, size);
785   dest[size-1] = '\0';
786
787   return 0;
788 }
789
790 static const char alphanum_upper_table[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
791
792 int gen_rand_alphanumeric_upper(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
793 {
794   int ret = get_random_bytes(dest, size);
795   if (ret < 0) {
796     lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
797     return ret;
798   }
799
800   int i;
801   for (i=0; i<size - 1; i++) {
802     int pos = (unsigned)dest[i];
803     dest[i] = alphanum_upper_table[pos % (sizeof(alphanum_upper_table) - 1)];
804   }
805   dest[i] = '\0';
806
807   return 0;
808 }
809
810 static const char alphanum_lower_table[]="0123456789abcdefghijklmnopqrstuvwxyz";
811
812 int gen_rand_alphanumeric_lower(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
813 {
814   int ret = get_random_bytes(dest, size);
815   if (ret < 0) {
816     lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
817     return ret;
818   }
819
820   int i;
821   for (i=0; i<size - 1; i++) {
822     int pos = (unsigned)dest[i];
823     dest[i] = alphanum_lower_table[pos % (sizeof(alphanum_lower_table) - 1)];
824   }
825   dest[i] = '\0';
826
827   return 0;
828 }
829
830 int gen_rand_alphanumeric_lower(CephContext *cct, string *str, int length)
831 {
832   char buf[length + 1];
833   int ret = gen_rand_alphanumeric_lower(cct, buf, sizeof(buf));
834   if (ret < 0) {
835     return ret;
836   }
837   *str = buf;
838   return 0;
839 }
840
841 // this is basically a modified base64 charset, url friendly
842 static const char alphanum_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
843
844 int gen_rand_alphanumeric(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
845 {
846   int ret = get_random_bytes(dest, size);
847   if (ret < 0) {
848     lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
849     return ret;
850   }
851
852   int i;
853   for (i=0; i<size - 1; i++) {
854     int pos = (unsigned)dest[i];
855     dest[i] = alphanum_table[pos & 63];
856   }
857   dest[i] = '\0';
858
859   return 0;
860 }
861
862 static const char alphanum_no_underscore_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.";
863
864 int gen_rand_alphanumeric_no_underscore(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
865 {
866   int ret = get_random_bytes(dest, size);
867   if (ret < 0) {
868     lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
869     return ret;
870   }
871
872   int i;
873   for (i=0; i<size - 1; i++) {
874     int pos = (unsigned)dest[i];
875     dest[i] = alphanum_no_underscore_table[pos & 63];
876   }
877   dest[i] = '\0';
878
879   return 0;
880 }
881
882 static const char alphanum_plain_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
883
884 int gen_rand_alphanumeric_plain(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
885 {
886   int ret = get_random_bytes(dest, size);
887   if (ret < 0) {
888     lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
889     return ret;
890   }
891
892   int i;
893   for (i=0; i<size - 1; i++) {
894     int pos = (unsigned)dest[i];
895     dest[i] = alphanum_plain_table[pos % (sizeof(alphanum_plain_table) - 1)];
896   }
897   dest[i] = '\0';
898
899   return 0;
900 }
901
902 int NameVal::parse()
903 {
904   auto delim_pos = str.find('=');
905   int ret = 0;
906
907   if (delim_pos == string::npos) {
908     name = str;
909     val = "";
910     ret = 1;
911   } else {
912     name = str.substr(0, delim_pos);
913     val = str.substr(delim_pos + 1);
914   }
915
916   return ret; 
917 }
918
919 int RGWHTTPArgs::parse()
920 {
921   int pos = 0;
922   bool end = false;
923
924   if (str.empty())
925     return 0;
926
927   if (str[pos] == '?')
928     pos++;
929
930   while (!end) {
931     int fpos = str.find('&', pos);
932     if (fpos  < pos) {
933        end = true;
934        fpos = str.size(); 
935     }
936     std::string nameval = url_decode(str.substr(pos, fpos - pos), true);
937     NameVal nv(std::move(nameval));
938     int ret = nv.parse();
939     if (ret >= 0) {
940       string& name = nv.get_name();
941       string& val = nv.get_val();
942
943       append(name, val);
944     }
945
946     pos = fpos + 1;  
947   }
948
949   return 0;
950 }
951
952 void RGWHTTPArgs::append(const string& name, const string& val)
953 {
954   if (name.compare(0, sizeof(RGW_SYS_PARAM_PREFIX) - 1, RGW_SYS_PARAM_PREFIX) == 0) {
955     sys_val_map[name] = val;
956   } else {
957     val_map[name] = val;
958   }
959
960   if ((name.compare("acl") == 0) ||
961       (name.compare("cors") == 0) ||
962       (name.compare("location") == 0) ||
963       (name.compare("logging") == 0) ||
964       (name.compare("usage") == 0) ||
965       (name.compare("lifecycle") == 0) ||
966       (name.compare("delete") == 0) ||
967       (name.compare("uploads") == 0) ||
968       (name.compare("partNumber") == 0) ||
969       (name.compare("uploadId") == 0) ||
970       (name.compare("versionId") == 0) ||
971       (name.compare("start-date") == 0) ||
972       (name.compare("end-date") == 0) ||
973       (name.compare("versions") == 0) ||
974       (name.compare("versioning") == 0) ||
975       (name.compare("website") == 0) ||
976       (name.compare("requestPayment") == 0) ||
977       (name.compare("torrent") == 0) ||
978       (name.compare("tagging") == 0)) {
979     sub_resources[name] = val;
980   } else if (name[0] == 'r') { // root of all evil
981     if ((name.compare("response-content-type") == 0) ||
982         (name.compare("response-content-language") == 0) ||
983         (name.compare("response-expires") == 0) ||
984         (name.compare("response-cache-control") == 0) ||
985         (name.compare("response-content-disposition") == 0) ||
986         (name.compare("response-content-encoding") == 0)) {
987       sub_resources[name] = val;
988       has_resp_modifier = true;
989     }
990   } else if  ((name.compare("subuser") == 0) ||
991               (name.compare("key") == 0) ||
992               (name.compare("caps") == 0) ||
993               (name.compare("index") == 0) ||
994               (name.compare("policy") == 0) ||
995               (name.compare("quota") == 0) ||
996               (name.compare("object") == 0)) {
997
998     if (!admin_subresource_added) {
999       sub_resources[name] = "";
1000       admin_subresource_added = true;
1001     }
1002   }
1003 }
1004
1005 const string& RGWHTTPArgs::get(const string& name, bool *exists) const
1006 {
1007   auto iter = val_map.find(name);
1008   bool e = (iter != std::end(val_map));
1009   if (exists)
1010     *exists = e;
1011   if (e)
1012     return iter->second;
1013   return empty_str;
1014 }
1015
1016 boost::optional<const std::string&>
1017 RGWHTTPArgs::get_optional(const std::string& name) const
1018 {
1019   bool exists;
1020   const std::string& value = get(name, &exists);
1021   if (exists) {
1022     return value;
1023   } else {
1024     return boost::none;
1025   }
1026 }
1027
1028 int RGWHTTPArgs::get_bool(const string& name, bool *val, bool *exists)
1029 {
1030   map<string, string>::iterator iter;
1031   iter = val_map.find(name);
1032   bool e = (iter != val_map.end());
1033   if (exists)
1034     *exists = e;
1035
1036   if (e) {
1037     const char *s = iter->second.c_str();
1038
1039     if (strcasecmp(s, "false") == 0) {
1040       *val = false;
1041     } else if (strcasecmp(s, "true") == 0) {
1042       *val = true;
1043     } else {
1044       return -EINVAL;
1045     }
1046   }
1047
1048   return 0;
1049 }
1050
1051 int RGWHTTPArgs::get_bool(const char *name, bool *val, bool *exists)
1052 {
1053   string s(name);
1054   return get_bool(s, val, exists);
1055 }
1056
1057 void RGWHTTPArgs::get_bool(const char *name, bool *val, bool def_val)
1058 {
1059   bool exists = false;
1060   if ((get_bool(name, val, &exists) < 0) ||
1061       !exists) {
1062     *val = def_val;
1063   }
1064 }
1065
1066 string RGWHTTPArgs::sys_get(const string& name, bool * const exists) const
1067 {
1068   const auto iter = sys_val_map.find(name);
1069   const bool e = (iter != sys_val_map.end());
1070
1071   if (exists) {
1072     *exists = e;
1073   }
1074
1075   return e ? iter->second : string();
1076 }
1077
1078 bool verify_user_permission(struct req_state * const s,
1079                             RGWAccessControlPolicy * const user_acl,
1080                             const int perm)
1081 {
1082   /* S3 doesn't support account ACLs. */
1083   if (!user_acl)
1084     return true;
1085
1086   if ((perm & (int)s->perm_mask) != perm)
1087     return false;
1088
1089   return user_acl->verify_permission(*s->auth.identity, perm, perm);
1090 }
1091
1092 bool verify_user_permission(struct req_state * const s,
1093                             const int perm)
1094 {
1095   return verify_user_permission(s, s->user_acl.get(), perm);
1096 }
1097
1098 bool verify_requester_payer_permission(struct req_state *s)
1099 {
1100   if (!s->bucket_info.requester_pays)
1101     return true;
1102
1103   if (s->auth.identity->is_owner_of(s->bucket_info.owner))
1104     return true;
1105   
1106   if (s->auth.identity->is_anonymous()) {
1107     return false;
1108   }
1109
1110   const char *request_payer = s->info.env->get("HTTP_X_AMZ_REQUEST_PAYER");
1111   if (!request_payer) {
1112     bool exists;
1113     request_payer = s->info.args.get("x-amz-request-payer", &exists).c_str();
1114     if (!exists) {
1115       return false;
1116     }
1117   }
1118
1119   if (strcasecmp(request_payer, "requester") == 0) {
1120     return true;
1121   }
1122
1123   return false;
1124 }
1125
1126 bool verify_bucket_permission(struct req_state * const s,
1127                               const rgw_bucket& bucket,
1128                               RGWAccessControlPolicy * const user_acl,
1129                               RGWAccessControlPolicy * const bucket_acl,
1130                               const optional<Policy>& bucket_policy,
1131                               const uint64_t op)
1132 {
1133   if (!verify_requester_payer_permission(s))
1134     return false;
1135
1136   if (bucket_policy) {
1137     auto r = bucket_policy->eval(s->env, *s->auth.identity, op, ARN(bucket));
1138     if (r == Effect::Allow)
1139       // It looks like S3 ACLs only GRANT permissions rather than
1140       // denying them, so this should be safe.
1141       return true;
1142     else if (r == Effect::Deny)
1143       return false;
1144   }
1145
1146   const auto perm = op_to_perm(op);
1147
1148   return verify_bucket_permission_no_policy(s, user_acl, bucket_acl, perm);
1149 }
1150
1151 bool verify_bucket_permission_no_policy(struct req_state * const s,
1152                                         RGWAccessControlPolicy * const user_acl,
1153                                         RGWAccessControlPolicy * const bucket_acl,
1154                                         const int perm)
1155 {
1156   if (!bucket_acl)
1157     return false;
1158
1159   if ((perm & (int)s->perm_mask) != perm)
1160     return false;
1161
1162   if (bucket_acl->verify_permission(*s->auth.identity, perm, perm,
1163                                     s->info.env->get("HTTP_REFERER")))
1164     return true;
1165
1166   if (!user_acl)
1167     return false;
1168
1169   return user_acl->verify_permission(*s->auth.identity, perm, perm);
1170 }
1171
1172 bool verify_bucket_permission_no_policy(struct req_state * const s, const int perm)
1173 {
1174   if (!verify_requester_payer_permission(s))
1175     return false;
1176
1177   return verify_bucket_permission_no_policy(s,
1178                                             s->user_acl.get(),
1179                                             s->bucket_acl.get(),
1180                                             perm);
1181 }
1182
1183 bool verify_bucket_permission(struct req_state * const s, const uint64_t op)
1184 {
1185   return verify_bucket_permission(s,
1186                                   s->bucket,
1187                                   s->user_acl.get(),
1188                                   s->bucket_acl.get(),
1189                                   s->iam_policy,
1190                                   op);
1191 }
1192
1193 static inline bool check_deferred_bucket_perms(struct req_state * const s,
1194                                                const rgw_bucket& bucket,
1195                                                RGWAccessControlPolicy * const user_acl,
1196                                                RGWAccessControlPolicy * const bucket_acl,
1197                                                const optional<Policy>& bucket_policy,
1198                                                const uint8_t deferred_check,
1199                                                const uint64_t op)
1200 {
1201   return (s->defer_to_bucket_acls == deferred_check \
1202           && verify_bucket_permission(s, bucket, user_acl, bucket_acl, bucket_policy, op));
1203 }
1204
1205 static inline bool check_deferred_bucket_only_acl(struct req_state * const s,
1206                                                   RGWAccessControlPolicy * const user_acl,
1207                                                   RGWAccessControlPolicy * const bucket_acl,
1208                                                   const uint8_t deferred_check,
1209                                                   const int perm)
1210 {
1211   return (s->defer_to_bucket_acls == deferred_check \
1212           && verify_bucket_permission_no_policy(s, user_acl, bucket_acl, perm));
1213 }
1214
1215 bool verify_object_permission(struct req_state * const s,
1216                               const rgw_obj& obj,
1217                               RGWAccessControlPolicy * const user_acl,
1218                               RGWAccessControlPolicy * const bucket_acl,
1219                               RGWAccessControlPolicy * const object_acl,
1220                               const optional<Policy>& bucket_policy,
1221                               const uint64_t op)
1222 {
1223   if (!verify_requester_payer_permission(s))
1224     return false;
1225
1226   if (bucket_policy) {
1227     auto r = bucket_policy->eval(s->env, *s->auth.identity, op, ARN(obj));
1228     if (r == Effect::Allow)
1229       // It looks like S3 ACLs only GRANT permissions rather than
1230       // denying them, so this should be safe.
1231       return true;
1232     else if (r == Effect::Deny)
1233       return false;
1234   }
1235
1236   const auto perm = op_to_perm(op);
1237
1238   if (check_deferred_bucket_perms(s, obj.bucket, user_acl, bucket_acl, bucket_policy,
1239                                   RGW_DEFER_TO_BUCKET_ACLS_RECURSE, op) ||
1240       check_deferred_bucket_perms(s, obj.bucket, user_acl, bucket_acl, bucket_policy,
1241                                   RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, rgw::IAM::s3All)) {
1242     return true;
1243   }
1244
1245   if (!object_acl) {
1246     return false;
1247   }
1248
1249   bool ret = object_acl->verify_permission(*s->auth.identity, s->perm_mask, perm);
1250   if (ret) {
1251     return true;
1252   }
1253
1254   if (!s->cct->_conf->rgw_enforce_swift_acls)
1255     return ret;
1256
1257   if ((perm & (int)s->perm_mask) != perm)
1258     return false;
1259
1260   int swift_perm = 0;
1261   if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP))
1262     swift_perm |= RGW_PERM_READ_OBJS;
1263   if (perm & RGW_PERM_WRITE)
1264     swift_perm |= RGW_PERM_WRITE_OBJS;
1265
1266   if (!swift_perm)
1267     return false;
1268
1269   /* we already verified the user mask above, so we pass swift_perm as the mask here,
1270      otherwise the mask might not cover the swift permissions bits */
1271   if (bucket_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm,
1272                                     s->info.env->get("HTTP_REFERER")))
1273     return true;
1274
1275   if (!user_acl)
1276     return false;
1277
1278   return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm);
1279 }
1280
1281 bool verify_object_permission_no_policy(struct req_state * const s,
1282                                         RGWAccessControlPolicy * const user_acl,
1283                                         RGWAccessControlPolicy * const bucket_acl,
1284                                         RGWAccessControlPolicy * const object_acl,
1285                                         const int perm)
1286 {
1287   if (check_deferred_bucket_only_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_RECURSE, perm) ||
1288       check_deferred_bucket_only_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, RGW_PERM_FULL_CONTROL)) {
1289     return true;
1290   }
1291
1292   if (!object_acl) {
1293     return false;
1294   }
1295
1296   bool ret = object_acl->verify_permission(*s->auth.identity, s->perm_mask, perm);
1297   if (ret) {
1298     return true;
1299   }
1300
1301   if (!s->cct->_conf->rgw_enforce_swift_acls)
1302     return ret;
1303
1304   if ((perm & (int)s->perm_mask) != perm)
1305     return false;
1306
1307   int swift_perm = 0;
1308   if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP))
1309     swift_perm |= RGW_PERM_READ_OBJS;
1310   if (perm & RGW_PERM_WRITE)
1311     swift_perm |= RGW_PERM_WRITE_OBJS;
1312
1313   if (!swift_perm)
1314     return false;
1315
1316   /* we already verified the user mask above, so we pass swift_perm as the mask here,
1317      otherwise the mask might not cover the swift permissions bits */
1318   if (bucket_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm,
1319                                     s->info.env->get("HTTP_REFERER")))
1320     return true;
1321
1322   if (!user_acl)
1323     return false;
1324
1325   return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm);
1326 }
1327
1328 bool verify_object_permission_no_policy(struct req_state *s, int perm)
1329 {
1330   if (!verify_requester_payer_permission(s))
1331     return false;
1332
1333   return verify_object_permission_no_policy(s,
1334                                             s->user_acl.get(),
1335                                             s->bucket_acl.get(),
1336                                             s->object_acl.get(),
1337                                             perm);
1338 }
1339
1340 bool verify_object_permission(struct req_state *s, uint64_t op)
1341 {
1342   return verify_object_permission(s,
1343                                   rgw_obj(s->bucket, s->object),
1344                                   s->user_acl.get(),
1345                                   s->bucket_acl.get(),
1346                                   s->object_acl.get(),
1347                                   s->iam_policy,
1348                                   op);
1349 }
1350
1351 class HexTable
1352 {
1353   char table[256];
1354
1355 public:
1356   HexTable() {
1357     memset(table, -1, sizeof(table));
1358     int i;
1359     for (i = '0'; i<='9'; i++)
1360       table[i] = i - '0';
1361     for (i = 'A'; i<='F'; i++)
1362       table[i] = i - 'A' + 0xa;
1363     for (i = 'a'; i<='f'; i++)
1364       table[i] = i - 'a' + 0xa;
1365   }
1366
1367   char to_num(char c) {
1368     return table[(int)c];
1369   }
1370 };
1371
1372 static char hex_to_num(char c)
1373 {
1374   static HexTable hex_table;
1375   return hex_table.to_num(c);
1376 }
1377
1378 std::string url_decode(const boost::string_view& src_str, bool in_query)
1379 {
1380   std::string dest_str;
1381   dest_str.reserve(src_str.length() + 1);
1382
1383   for (auto src = std::begin(src_str); src != std::end(src_str); ++src) {
1384     if (*src != '%') {
1385       if (!in_query || *src != '+') {
1386         if (*src == '?') {
1387           in_query = true;
1388         }
1389         dest_str.push_back(*src);
1390       } else {
1391         dest_str.push_back(' ');
1392       }
1393     } else {
1394       /* 3 == strlen("%%XX") */
1395       if (std::distance(src, std::end(src_str)) < 3) {
1396         break;
1397       }
1398
1399       src++;
1400       const char c1 = hex_to_num(*src++);
1401       const char c2 = hex_to_num(*src);
1402       if (c1 < 0 || c2 < 0) {
1403         return std::string();
1404       } else {
1405         dest_str.push_back(c1 << 4 | c2);
1406       }
1407     }
1408   }
1409
1410   return dest_str;
1411 }
1412
1413 void rgw_uri_escape_char(char c, string& dst)
1414 {
1415   char buf[16];
1416   snprintf(buf, sizeof(buf), "%%%.2X", (int)(unsigned char)c);
1417   dst.append(buf);
1418 }
1419
1420 static bool char_needs_url_encoding(char c)
1421 {
1422   if (c <= 0x20 || c >= 0x7f)
1423     return true;
1424
1425   switch (c) {
1426     case 0x22:
1427     case 0x23:
1428     case 0x25:
1429     case 0x26:
1430     case 0x2B:
1431     case 0x2C:
1432     case 0x2F:
1433     case 0x3A:
1434     case 0x3B:
1435     case 0x3C:
1436     case 0x3E:
1437     case 0x3D:
1438     case 0x3F:
1439     case 0x40:
1440     case 0x5B:
1441     case 0x5D:
1442     case 0x5C:
1443     case 0x5E:
1444     case 0x60:
1445     case 0x7B:
1446     case 0x7D:
1447       return true;
1448   }
1449   return false;
1450 }
1451
1452 void url_encode(const string& src, string& dst)
1453 {
1454   const char *p = src.c_str();
1455   for (unsigned i = 0; i < src.size(); i++, p++) {
1456     if (char_needs_url_encoding(*p)) {
1457       rgw_uri_escape_char(*p, dst);
1458       continue;
1459     }
1460
1461     dst.append(p, 1);
1462   }
1463 }
1464
1465 std::string url_encode(const std::string& src)
1466 {
1467   std::string dst;
1468   url_encode(src, dst);
1469
1470   return dst;
1471 }
1472
1473 string rgw_trim_whitespace(const string& src)
1474 {
1475   if (src.empty()) {
1476     return string();
1477   }
1478
1479   int start = 0;
1480   for (; start != (int)src.size(); start++) {
1481     if (!isspace(src[start]))
1482       break;
1483   }
1484
1485   int end = src.size() - 1;
1486   if (end < start) {
1487     return string();
1488   }
1489
1490   for (; end > start; end--) {
1491     if (!isspace(src[end]))
1492       break;
1493   }
1494
1495   return src.substr(start, end - start + 1);
1496 }
1497
1498 boost::string_view rgw_trim_whitespace(const boost::string_view& src)
1499 {
1500   boost::string_view res = src;
1501
1502   while (res.size() > 0 && std::isspace(res.front())) {
1503     res.remove_prefix(1);
1504   }
1505   while (res.size() > 0 && std::isspace(res.back())) {
1506     res.remove_suffix(1);
1507   }
1508   return res;
1509 }
1510
1511 string rgw_trim_quotes(const string& val)
1512 {
1513   string s = rgw_trim_whitespace(val);
1514   if (s.size() < 2)
1515     return s;
1516
1517   int start = 0;
1518   int end = s.size() - 1;
1519   int quotes_count = 0;
1520
1521   if (s[start] == '"') {
1522     start++;
1523     quotes_count++;
1524   }
1525   if (s[end] == '"') {
1526     end--;
1527     quotes_count++;
1528   }
1529   if (quotes_count == 2) {
1530     return s.substr(start, end - start + 1);
1531   }
1532   return s;
1533 }
1534
1535 struct rgw_name_to_flag {
1536   const char *type_name;
1537   uint32_t flag;
1538 };
1539
1540 static int parse_list_of_flags(struct rgw_name_to_flag *mapping,
1541                                const string& str, uint32_t *perm)
1542 {
1543   list<string> strs;
1544   get_str_list(str, strs);
1545   list<string>::iterator iter;
1546   uint32_t v = 0;
1547   for (iter = strs.begin(); iter != strs.end(); ++iter) {
1548     string& s = *iter;
1549     for (int i = 0; mapping[i].type_name; i++) {
1550       if (s.compare(mapping[i].type_name) == 0)
1551         v |= mapping[i].flag;
1552     }
1553   }
1554
1555   *perm = v;
1556   return 0;
1557 }
1558
1559 static struct rgw_name_to_flag cap_names[] = { {"*",     RGW_CAP_ALL},
1560                   {"read",  RGW_CAP_READ},
1561                   {"write", RGW_CAP_WRITE},
1562                   {NULL, 0} };
1563
1564 int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm)
1565 {
1566   return parse_list_of_flags(cap_names, str, perm);
1567 }
1568
1569 int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm)
1570 {
1571   int pos = cap.find('=');
1572   if (pos >= 0) {
1573     type = rgw_trim_whitespace(cap.substr(0, pos));
1574   }
1575
1576   if (!is_valid_cap_type(type))
1577     return -ERR_INVALID_CAP;
1578
1579   string cap_perm;
1580   uint32_t perm = 0;
1581   if (pos < (int)cap.size() - 1) {
1582     cap_perm = cap.substr(pos + 1);
1583     int r = RGWUserCaps::parse_cap_perm(cap_perm, &perm);
1584     if (r < 0)
1585       return r;
1586   }
1587
1588   *pperm = perm;
1589
1590   return 0;
1591 }
1592
1593 int RGWUserCaps::add_cap(const string& cap)
1594 {
1595   uint32_t perm;
1596   string type;
1597
1598   int r = get_cap(cap, type, &perm);
1599   if (r < 0)
1600     return r;
1601
1602   caps[type] |= perm;
1603
1604   return 0;
1605 }
1606
1607 int RGWUserCaps::remove_cap(const string& cap)
1608 {
1609   uint32_t perm;
1610   string type;
1611
1612   int r = get_cap(cap, type, &perm);
1613   if (r < 0)
1614     return r;
1615
1616   map<string, uint32_t>::iterator iter = caps.find(type);
1617   if (iter == caps.end())
1618     return 0;
1619
1620   uint32_t& old_perm = iter->second;
1621   old_perm &= ~perm;
1622   if (!old_perm)
1623     caps.erase(iter);
1624
1625   return 0;
1626 }
1627
1628 int RGWUserCaps::add_from_string(const string& str)
1629 {
1630   int start = 0;
1631   do {
1632     auto end = str.find(';', start);
1633     if (end == string::npos)
1634       end = str.size();
1635
1636     int r = add_cap(str.substr(start, end - start));
1637     if (r < 0)
1638       return r;
1639
1640     start = end + 1;
1641   } while (start < (int)str.size());
1642
1643   return 0;
1644 }
1645
1646 int RGWUserCaps::remove_from_string(const string& str)
1647 {
1648   int start = 0;
1649   do {
1650     auto end = str.find(';', start);
1651     if (end == string::npos)
1652       end = str.size();
1653
1654     int r = remove_cap(str.substr(start, end - start));
1655     if (r < 0)
1656       return r;
1657
1658     start = end + 1;
1659   } while (start < (int)str.size());
1660
1661   return 0;
1662 }
1663
1664 void RGWUserCaps::dump(Formatter *f) const
1665 {
1666   dump(f, "caps");
1667 }
1668
1669 void RGWUserCaps::dump(Formatter *f, const char *name) const
1670 {
1671   f->open_array_section(name);
1672   map<string, uint32_t>::const_iterator iter;
1673   for (iter = caps.begin(); iter != caps.end(); ++iter)
1674   {
1675     f->open_object_section("cap");
1676     f->dump_string("type", iter->first);
1677     uint32_t perm = iter->second;
1678     string perm_str;
1679     for (int i=0; cap_names[i].type_name; i++) {
1680       if ((perm & cap_names[i].flag) == cap_names[i].flag) {
1681         if (perm_str.size())
1682           perm_str.append(", ");
1683
1684         perm_str.append(cap_names[i].type_name);
1685         perm &= ~cap_names[i].flag;
1686       }
1687     }
1688     if (perm_str.empty())
1689       perm_str = "<none>";
1690
1691     f->dump_string("perm", perm_str);
1692     f->close_section();
1693   }
1694
1695   f->close_section();
1696 }
1697
1698 struct RGWUserCap {
1699   string type;
1700   uint32_t perm;
1701
1702   void decode_json(JSONObj *obj) {
1703     JSONDecoder::decode_json("type", type, obj);
1704     string perm_str;
1705     JSONDecoder::decode_json("perm", perm_str, obj);
1706     if (RGWUserCaps::parse_cap_perm(perm_str, &perm) < 0) {
1707       throw JSONDecoder::err("failed to parse permissions");
1708     }
1709   }
1710 };
1711
1712 void RGWUserCaps::decode_json(JSONObj *obj)
1713 {
1714   list<RGWUserCap> caps_list;
1715   decode_json_obj(caps_list, obj);
1716
1717   list<RGWUserCap>::iterator iter;
1718   for (iter = caps_list.begin(); iter != caps_list.end(); ++iter) {
1719     RGWUserCap& cap = *iter;
1720     caps[cap.type] = cap.perm;
1721   }
1722 }
1723
1724 int RGWUserCaps::check_cap(const string& cap, uint32_t perm)
1725 {
1726   map<string, uint32_t>::iterator iter = caps.find(cap);
1727
1728   if ((iter == caps.end()) ||
1729       (iter->second & perm) != perm) {
1730     return -EPERM;
1731   }
1732
1733   return 0;
1734 }
1735
1736 bool RGWUserCaps::is_valid_cap_type(const string& tp)
1737 {
1738   static const char *cap_type[] = { "user",
1739                                     "users",
1740                                     "buckets",
1741                                     "metadata",
1742                                     "usage",
1743                                     "zone",
1744                                     "bilog",
1745                                     "mdlog",
1746                                     "datalog",
1747                                     "opstate" };
1748
1749   for (unsigned int i = 0; i < sizeof(cap_type) / sizeof(char *); ++i) {
1750     if (tp.compare(cap_type[i]) == 0) {
1751       return true;
1752     }
1753   }
1754
1755   return false;
1756 }
1757
1758 static ssize_t unescape_str(const string& s, ssize_t ofs, char esc_char, char special_char, string *dest)
1759 {
1760   const char *src = s.c_str();
1761   char dest_buf[s.size() + 1];
1762   char *destp = dest_buf;
1763   bool esc = false;
1764
1765   dest_buf[0] = '\0';
1766
1767   for (size_t i = ofs; i < s.size(); i++) {
1768     char c = src[i];
1769     if (!esc && c == esc_char) {
1770       esc = true;
1771       continue;
1772     }
1773     if (!esc && c == special_char) {
1774       *destp = '\0';
1775       *dest = dest_buf;
1776       return (ssize_t)i + 1;
1777     }
1778     *destp++ = c;
1779     esc = false;
1780   }
1781   *destp = '\0';
1782   *dest = dest_buf;
1783   return string::npos;
1784 }
1785
1786 static void escape_str(const string& s, char esc_char, char special_char, string *dest)
1787 {
1788   const char *src = s.c_str();
1789   char dest_buf[s.size() * 2 + 1];
1790   char *destp = dest_buf;
1791
1792   for (size_t i = 0; i < s.size(); i++) {
1793     char c = src[i];
1794     if (c == esc_char || c == special_char) {
1795       *destp++ = esc_char;
1796     }
1797     *destp++ = c;
1798   }
1799   *destp++ = '\0';
1800   *dest = dest_buf;
1801 }
1802
1803 void rgw_pool::from_str(const string& s)
1804 {
1805   size_t pos = unescape_str(s, 0, '\\', ':', &name);
1806   if (pos != string::npos) {
1807     pos = unescape_str(s, pos, '\\', ':', &ns);
1808     /* ignore return; if pos != string::npos it means that we had a colon
1809      * in the middle of ns that wasn't escaped, we're going to stop there
1810      */
1811   }
1812 }
1813
1814 string rgw_pool::to_str() const
1815 {
1816   string esc_name;
1817   escape_str(name, '\\', ':', &esc_name);
1818   if (ns.empty()) {
1819     return esc_name;
1820   }
1821   string esc_ns;
1822   escape_str(ns, '\\', ':', &esc_ns);
1823   return esc_name + ":" + esc_ns;
1824 }
1825
1826 void rgw_raw_obj::decode_from_rgw_obj(bufferlist::iterator& bl)
1827 {
1828   rgw_obj old_obj;
1829   ::decode(old_obj, bl);
1830
1831   get_obj_bucket_and_oid_loc(old_obj, oid, loc);
1832   pool = old_obj.get_explicit_data_pool();
1833 }
1834
1835 std::string rgw_bucket::get_key(char tenant_delim, char id_delim) const
1836 {
1837   static constexpr size_t shard_len{12}; // ":4294967295\0"
1838   const size_t max_len = tenant.size() + sizeof(tenant_delim) +
1839       name.size() + sizeof(id_delim) + bucket_id.size() + shard_len;
1840
1841   std::string key;
1842   key.reserve(max_len);
1843   if (!tenant.empty() && tenant_delim) {
1844     key.append(tenant);
1845     key.append(1, tenant_delim);
1846   }
1847   key.append(name);
1848   if (!bucket_id.empty() && id_delim) {
1849     key.append(1, id_delim);
1850     key.append(bucket_id);
1851   }
1852   return key;
1853 }
1854
1855 std::string rgw_bucket_shard::get_key(char tenant_delim, char id_delim,
1856                                       char shard_delim) const
1857 {
1858   auto key = bucket.get_key(tenant_delim, id_delim);
1859   if (shard_id >= 0 && shard_delim) {
1860     key.append(1, shard_delim);
1861     key.append(std::to_string(shard_id));
1862   }
1863   return key;
1864 }
1865
1866 static struct rgw_name_to_flag op_type_mapping[] = { {"*",  RGW_OP_TYPE_ALL},
1867                   {"read",  RGW_OP_TYPE_READ},
1868                   {"write", RGW_OP_TYPE_WRITE},
1869                   {"delete", RGW_OP_TYPE_DELETE},
1870                   {NULL, 0} };
1871
1872
1873 int rgw_parse_op_type_list(const string& str, uint32_t *perm)
1874 {
1875   return parse_list_of_flags(op_type_mapping, str, perm);
1876 }
1877
1878 bool match_policy(boost::string_view pattern, boost::string_view input,
1879                   uint32_t flag)
1880 {
1881   const uint32_t flag2 = flag & (MATCH_POLICY_ACTION|MATCH_POLICY_ARN) ?
1882       MATCH_CASE_INSENSITIVE : 0;
1883
1884   const auto npos = boost::string_view::npos;
1885   boost::string_view::size_type last_pos_input = 0, last_pos_pattern = 0;
1886   while (true) {
1887     auto cur_pos_input = input.find(":", last_pos_input);
1888     auto cur_pos_pattern = pattern.find(":", last_pos_pattern);
1889
1890     auto substr_input = input.substr(last_pos_input, cur_pos_input);
1891     auto substr_pattern = pattern.substr(last_pos_pattern, cur_pos_pattern);
1892
1893     if (!match_wildcards(substr_pattern, substr_input, flag2))
1894       return false;
1895
1896     if (cur_pos_pattern == npos)
1897       return cur_pos_input == npos;
1898     if (cur_pos_input == npos)
1899       return false;
1900
1901     last_pos_pattern = cur_pos_pattern + 1;
1902     last_pos_input = cur_pos_input + 1;
1903   }
1904 }