]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_common.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / rgw / rgw_common.cc
CommitLineData
7c673cae
FG
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
11#include "json_spirit/json_spirit.h"
12#include "common/ceph_json.h"
13
14#include "rgw_common.h"
15#include "rgw_acl.h"
16#include "rgw_string.h"
17#include "rgw_rados.h"
18
19#include "common/ceph_crypto.h"
20#include "common/armor.h"
21#include "common/errno.h"
22#include "common/Clock.h"
23#include "common/Formatter.h"
24#include "common/perf_counters.h"
25#include "common/strtol.h"
26#include "include/str_list.h"
27#include "auth/Crypto.h"
28#include "rgw_crypt_sanitize.h"
29
30#include <sstream>
31
32#define dout_context g_ceph_context
33#define dout_subsys ceph_subsys_rgw
34
35#define POLICY_ACTION 0x01
36#define POLICY_RESOURCE 0x02
37#define POLICY_ARN 0x04
38#define POLICY_STRING 0x08
39
40PerfCounters *perfcounter = NULL;
41
42const uint32_t RGWBucketInfo::NUM_SHARDS_BLIND_BUCKET(UINT32_MAX);
43
44int rgw_perf_start(CephContext *cct)
45{
46 PerfCountersBuilder plb(cct, cct->_conf->name.to_str(), l_rgw_first, l_rgw_last);
47
48 plb.add_u64_counter(l_rgw_req, "req", "Requests");
49 plb.add_u64_counter(l_rgw_failed_req, "failed_req", "Aborted requests");
50
51 plb.add_u64_counter(l_rgw_get, "get", "Gets");
52 plb.add_u64_counter(l_rgw_get_b, "get_b", "Size of gets");
53 plb.add_time_avg(l_rgw_get_lat, "get_initial_lat", "Get latency");
54 plb.add_u64_counter(l_rgw_put, "put", "Puts");
55 plb.add_u64_counter(l_rgw_put_b, "put_b", "Size of puts");
56 plb.add_time_avg(l_rgw_put_lat, "put_initial_lat", "Put latency");
57
58 plb.add_u64(l_rgw_qlen, "qlen", "Queue length");
59 plb.add_u64(l_rgw_qactive, "qactive", "Active requests queue");
60
61 plb.add_u64_counter(l_rgw_cache_hit, "cache_hit", "Cache hits");
62 plb.add_u64_counter(l_rgw_cache_miss, "cache_miss", "Cache miss");
63
64 plb.add_u64_counter(l_rgw_keystone_token_cache_hit, "keystone_token_cache_hit", "Keystone token cache hits");
65 plb.add_u64_counter(l_rgw_keystone_token_cache_miss, "keystone_token_cache_miss", "Keystone token cache miss");
66
67 perfcounter = plb.create_perf_counters();
68 cct->get_perfcounters_collection()->add(perfcounter);
69 return 0;
70}
71
72void rgw_perf_stop(CephContext *cct)
73{
74 assert(perfcounter);
75 cct->get_perfcounters_collection()->remove(perfcounter);
76 delete perfcounter;
77}
78
79using namespace ceph::crypto;
80
81rgw_err::
82rgw_err()
83{
84 clear();
85}
86
87rgw_err::
88rgw_err(int http, const std::string& s3)
89 : http_ret(http), ret(0), s3_code(s3)
90{
91}
92
93void rgw_err::
94clear()
95{
96 http_ret = 200;
97 ret = 0;
98 s3_code.clear();
99}
100
101bool rgw_err::
102is_clear() const
103{
104 return (http_ret == 200);
105}
106
107bool rgw_err::
108is_err() const
109{
110 return !(http_ret >= 200 && http_ret <= 399);
111}
112
113// The requestURI transferred from the frontend can be abs_path or absoluteURI
114// If it is absoluteURI, we should adjust it to abs_path for the following
115// S3 authorization and some other processes depending on the requestURI
116// The absoluteURI can start with "http://", "https://", "ws://" or "wss://"
117static string get_abs_path(const string& request_uri) {
118 const static string ABS_PREFIXS[] = {"http://", "https://", "ws://", "wss://"};
119 bool isAbs = false;
120 for (int i = 0; i < 4; ++i) {
121 if (boost::algorithm::starts_with(request_uri, ABS_PREFIXS[i])) {
122 isAbs = true;
123 break;
124 }
125 }
126 if (!isAbs) { // it is not a valid absolute uri
127 return request_uri;
128 }
129 size_t beg_pos = request_uri.find("://") + 3;
130 size_t len = request_uri.size();
131 beg_pos = request_uri.find('/', beg_pos);
132 if (beg_pos == string::npos) return request_uri;
133 return request_uri.substr(beg_pos, len - beg_pos);
134}
135
136req_info::req_info(CephContext *cct, class RGWEnv *e) : env(e) {
137 method = env->get("REQUEST_METHOD", "");
138 script_uri = env->get("SCRIPT_URI", cct->_conf->rgw_script_uri.c_str());
139 request_uri = env->get("REQUEST_URI", cct->_conf->rgw_request_uri.c_str());
140 if (request_uri[0] != '/') {
141 request_uri = get_abs_path(request_uri);
142 }
143 int pos = request_uri.find('?');
144 if (pos >= 0) {
145 request_params = request_uri.substr(pos + 1);
146 request_uri = request_uri.substr(0, pos);
147 } else {
148 request_params = env->get("QUERY_STRING", "");
149 }
150 host = env->get("HTTP_HOST", "");
151
152 // strip off any trailing :port from host (added by CrossFTP and maybe others)
153 size_t colon_offset = host.find_last_of(':');
154 if (colon_offset != string::npos) {
155 bool all_digits = true;
156 for (unsigned i = colon_offset + 1; i < host.size(); ++i) {
157 if (!isdigit(host[i])) {
158 all_digits = false;
159 break;
160 }
161 }
162 if (all_digits) {
163 host.resize(colon_offset);
164 }
165 }
166}
167
168void req_info::rebuild_from(req_info& src)
169{
170 method = src.method;
171 script_uri = src.script_uri;
172 args = src.args;
173 if (src.effective_uri.empty()) {
174 request_uri = src.request_uri;
175 } else {
176 request_uri = src.effective_uri;
177 }
178 effective_uri.clear();
179 host = src.host;
180
181 x_meta_map = src.x_meta_map;
182 x_meta_map.erase("x-amz-date");
183}
184
185
186req_state::req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u)
187 : cct(_cct), cio(NULL), op(OP_UNKNOWN), user(u), has_acl_header(false),
188 info(_cct, e)
189{
190 enable_ops_log = e->conf.enable_ops_log;
191 enable_usage_log = e->conf.enable_usage_log;
192 defer_to_bucket_acls = e->conf.defer_to_bucket_acls;
193 content_started = false;
194 format = 0;
195 formatter = NULL;
196 bucket_acl = NULL;
197 object_acl = NULL;
198 expect_cont = false;
199 aws4_auth_needs_complete = false;
200 aws4_auth_streaming_mode = false;
201
202 header_ended = false;
203 obj_size = 0;
204 prot_flags = 0;
205
206 system_request = false;
207
208 time = ceph_clock_now();
209 perm_mask = 0;
210 bucket_instance_shard_id = -1;
211 content_length = 0;
212 bucket_exists = false;
213 has_bad_meta = false;
214 length = NULL;
215 http_auth = NULL;
216 local_source = false;
217
218 obj_ctx = NULL;
219}
220
221req_state::~req_state() {
222 delete formatter;
223 delete bucket_acl;
224 delete object_acl;
225}
226
227struct str_len {
228 const char *str;
229 int len;
230};
231
232#define STR_LEN_ENTRY(s) { s, sizeof(s) - 1 }
233
234struct str_len meta_prefixes[] = { STR_LEN_ENTRY("HTTP_X_AMZ"),
235 STR_LEN_ENTRY("HTTP_X_GOOG"),
236 STR_LEN_ENTRY("HTTP_X_DHO"),
237 STR_LEN_ENTRY("HTTP_X_RGW"),
238 STR_LEN_ENTRY("HTTP_X_OBJECT"),
239 STR_LEN_ENTRY("HTTP_X_CONTAINER"),
240 STR_LEN_ENTRY("HTTP_X_ACCOUNT"),
241 {NULL, 0} };
242
243
244void req_info::init_meta_info(bool *found_bad_meta)
245{
246 x_meta_map.clear();
247
248 map<string, string, ltstr_nocase>& m = env->get_map();
249 map<string, string, ltstr_nocase>::iterator iter;
250 for (iter = m.begin(); iter != m.end(); ++iter) {
251 const char *prefix;
252 const string& header_name = iter->first;
253 const string& val = iter->second;
254 for (int prefix_num = 0; (prefix = meta_prefixes[prefix_num].str) != NULL; prefix_num++) {
255 int len = meta_prefixes[prefix_num].len;
256 const char *p = header_name.c_str();
257 if (strncmp(p, prefix, len) == 0) {
258 dout(10) << "meta>> " << p << dendl;
259 const char *name = p+len; /* skip the prefix */
260 int name_len = header_name.size() - len;
261
262 if (found_bad_meta && strncmp(name, "_META_", name_len) == 0)
263 *found_bad_meta = true;
264
265 char name_low[meta_prefixes[0].len + name_len + 1];
266 snprintf(name_low, meta_prefixes[0].len - 5 + name_len + 1, "%s%s", meta_prefixes[0].str + 5 /* skip HTTP_ */, name); // normalize meta prefix
267 int j;
268 for (j = 0; name_low[j]; j++) {
269 if (name_low[j] != '_')
270 name_low[j] = tolower(name_low[j]);
271 else
272 name_low[j] = '-';
273 }
274 name_low[j] = 0;
275
276 map<string, string>::iterator iter;
277 iter = x_meta_map.find(name_low);
278 if (iter != x_meta_map.end()) {
279 string old = iter->second;
280 int pos = old.find_last_not_of(" \t"); /* get rid of any whitespaces after the value */
281 old = old.substr(0, pos + 1);
282 old.append(",");
283 old.append(val);
284 x_meta_map[name_low] = old;
285 } else {
286 x_meta_map[name_low] = val;
287 }
288 }
289 }
290 }
291 for (iter = x_meta_map.begin(); iter != x_meta_map.end(); ++iter) {
292 dout(10) << "x>> " << iter->first << ":" << rgw::crypt_sanitize::x_meta_map{iter->first, iter->second} << dendl;
293 }
294}
295
296std::ostream& operator<<(std::ostream& oss, const rgw_err &err)
297{
298 oss << "rgw_err(http_ret=" << err.http_ret << ", s3='" << err.s3_code << "') ";
299 return oss;
300}
301
302string rgw_string_unquote(const string& s)
303{
304 if (s[0] != '"' || s.size() < 2)
305 return s;
306
307 int len;
308 for (len = s.size(); len > 2; --len) {
309 if (s[len - 1] != ' ')
310 break;
311 }
312
313 if (s[len-1] != '"')
314 return s;
315
316 return s.substr(1, len - 2);
317}
318
319static void trim_whitespace(const string& src, string& dst)
320{
321 const char *spacestr = " \t\n\r\f\v";
322 int start = src.find_first_not_of(spacestr);
323 if (start < 0)
324 return;
325
326 int end = src.find_last_not_of(spacestr);
327 dst = src.substr(start, end - start + 1);
328}
329
330static bool check_str_end(const char *s)
331{
332 if (!s)
333 return false;
334
335 while (*s) {
336 if (!isspace(*s))
337 return false;
338 s++;
339 }
340 return true;
341}
342
343static bool check_gmt_end(const char *s)
344{
345 if (!s || !*s)
346 return false;
347
348 while (isspace(*s)) {
349 ++s;
350 }
351
352 /* check for correct timezone */
353 if ((strncmp(s, "GMT", 3) != 0) &&
354 (strncmp(s, "UTC", 3) != 0)) {
355 return false;
356 }
357
358 return true;
359}
360
361static bool parse_rfc850(const char *s, struct tm *t)
362{
363 memset(t, 0, sizeof(*t));
364 return check_gmt_end(strptime(s, "%A, %d-%b-%y %H:%M:%S ", t));
365}
366
367static bool parse_asctime(const char *s, struct tm *t)
368{
369 memset(t, 0, sizeof(*t));
370 return check_str_end(strptime(s, "%a %b %d %H:%M:%S %Y", t));
371}
372
373static bool parse_rfc1123(const char *s, struct tm *t)
374{
375 memset(t, 0, sizeof(*t));
376 return check_gmt_end(strptime(s, "%a, %d %b %Y %H:%M:%S ", t));
377}
378
379static bool parse_rfc1123_alt(const char *s, struct tm *t)
380{
381 memset(t, 0, sizeof(*t));
382 return check_str_end(strptime(s, "%a, %d %b %Y %H:%M:%S %z", t));
383}
384
385bool parse_rfc2616(const char *s, struct tm *t)
386{
387 return parse_rfc850(s, t) || parse_asctime(s, t) || parse_rfc1123(s, t) || parse_rfc1123_alt(s,t);
388}
389
390bool parse_iso8601(const char *s, struct tm *t, uint32_t *pns, bool extended_format)
391{
392 memset(t, 0, sizeof(*t));
393 const char *p;
394
395 if (!s)
396 s = "";
397
398 if (extended_format) {
399 p = strptime(s, "%Y-%m-%dT%T", t);
400 if (!p) {
401 p = strptime(s, "%Y-%m-%d %T", t);
402 }
403 } else {
404 p = strptime(s, "%Y%m%dT%H%M%S", t);
405 }
406 if (!p) {
407 dout(0) << "parse_iso8601 failed" << dendl;
408 return false;
409 }
410 string str;
411 trim_whitespace(p, str);
412 int len = str.size();
413
414 if (len == 1 && str[0] == 'Z')
415 return true;
416
417 if (str[0] != '.' ||
418 str[len - 1] != 'Z')
419 return false;
420
421 uint32_t ms;
422 string nsstr = str.substr(1, len - 2);
423 int r = stringtoul(nsstr, &ms);
424 if (r < 0)
425 return false;
426
427 if (!pns) {
428 return true;
429 }
430
431 if (nsstr.size() > 9) {
432 nsstr = nsstr.substr(0, 9);
433 }
434
435 uint64_t mul_table[] = { 0,
436 100000000LL,
437 10000000LL,
438 1000000LL,
439 100000LL,
440 10000LL,
441 1000LL,
442 100LL,
443 10LL,
444 1 };
445
446
447 *pns = ms * mul_table[nsstr.size()];
448
449 return true;
450}
451
452int parse_key_value(string& in_str, const char *delim, string& key, string& val)
453{
454 if (delim == NULL)
455 return -EINVAL;
456
457 int pos = in_str.find(delim);
458 if (pos < 0)
459 return -EINVAL;
460
461 trim_whitespace(in_str.substr(0, pos), key);
462 pos++;
463
464 trim_whitespace(in_str.substr(pos), val);
465
466 return 0;
467}
468
469int parse_key_value(string& in_str, string& key, string& val)
470{
471 return parse_key_value(in_str, "=", key,val);
472}
473
474int parse_time(const char *time_str, real_time *time)
475{
476 struct tm tm;
477 uint32_t ns = 0;
478
479 if (!parse_rfc2616(time_str, &tm) && !parse_iso8601(time_str, &tm, &ns)) {
480 return -EINVAL;
481 }
482
483 time_t sec = internal_timegm(&tm);
484 *time = utime_t(sec, ns).to_real_time();
485
486 return 0;
487}
488
489#define TIME_BUF_SIZE 128
490
491void rgw_to_iso8601(const real_time& t, char *dest, int buf_size)
492{
493 utime_t ut(t);
494
495 char buf[TIME_BUF_SIZE];
496 struct tm result;
497 time_t epoch = ut.sec();
498 struct tm *tmp = gmtime_r(&epoch, &result);
499 if (tmp == NULL)
500 return;
501
502 if (strftime(buf, sizeof(buf), "%Y-%m-%dT%T", tmp) == 0)
503 return;
504
505 snprintf(dest, buf_size, "%s.%03dZ", buf, (int)(ut.usec() / 1000));
506}
507
508void rgw_to_iso8601(const real_time& t, string *dest)
509{
510 char buf[TIME_BUF_SIZE];
511 rgw_to_iso8601(t, buf, sizeof(buf));
512 *dest = buf;
513}
514
515/*
516 * calculate the sha1 value of a given msg and key
517 */
518void calc_hmac_sha1(const char *key, int key_len,
519 const char *msg, int msg_len, char *dest)
520/* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */
521{
522 HMACSHA1 hmac((const unsigned char *)key, key_len);
523 hmac.Update((const unsigned char *)msg, msg_len);
524 hmac.Final((unsigned char *)dest);
525}
526
527/*
528 * calculate the sha256 value of a given msg and key
529 */
530void calc_hmac_sha256(const char *key, int key_len,
531 const char *msg, int msg_len, char *dest)
532{
533 char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
534
535 HMACSHA256 hmac((const unsigned char *)key, key_len);
536 hmac.Update((const unsigned char *)msg, msg_len);
537 hmac.Final((unsigned char *)hash_sha256);
538
539 memcpy(dest, hash_sha256, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE);
540}
541
542/*
543 * calculate the sha256 hash value of a given msg
544 */
545void calc_hash_sha256(const char *msg, int len, string& dest)
546{
547 char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
548
549 SHA256 hash;
550 hash.Update((const unsigned char *)msg, len);
551 hash.Final((unsigned char *)hash_sha256);
552
553 char hex_str[(CEPH_CRYPTO_SHA256_DIGESTSIZE * 2) + 1];
554 buf_to_hex((unsigned char *)hash_sha256, CEPH_CRYPTO_SHA256_DIGESTSIZE, hex_str);
555
556 dest = std::string(hex_str);
557}
558
559using ceph::crypto::SHA256;
560
561SHA256* calc_hash_sha256_open_stream()
562{
563 return new SHA256;
564}
565
566void calc_hash_sha256_update_stream(SHA256 *hash, const char *msg, int len)
567{
568 hash->Update((const unsigned char *)msg, len);
569}
570
571string calc_hash_sha256_close_stream(SHA256 **phash)
572{
573 SHA256 *hash = *phash;
574 if (!hash) {
575 hash = calc_hash_sha256_open_stream();
576 }
577 char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
578
579 hash->Final((unsigned char *)hash_sha256);
580
581 char hex_str[(CEPH_CRYPTO_SHA256_DIGESTSIZE * 2) + 1];
582 buf_to_hex((unsigned char *)hash_sha256, CEPH_CRYPTO_SHA256_DIGESTSIZE, hex_str);
583
584 delete hash;
585 *phash = NULL;
586
587 return std::string(hex_str);
588}
589
590int gen_rand_base64(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
591{
592 char buf[size];
593 char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */
594 int ret;
595
596 ret = get_random_bytes(buf, sizeof(buf));
597 if (ret < 0) {
598 lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
599 return ret;
600 }
601
602 ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)],
603 (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4);
604 if (ret < 0) {
605 lderr(cct) << "ceph_armor failed" << dendl;
606 return ret;
607 }
608 tmp_dest[ret] = '\0';
609 memcpy(dest, tmp_dest, size);
610 dest[size-1] = '\0';
611
612 return 0;
613}
614
615static const char alphanum_upper_table[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
616
617int gen_rand_alphanumeric_upper(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
618{
619 int ret = get_random_bytes(dest, size);
620 if (ret < 0) {
621 lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
622 return ret;
623 }
624
625 int i;
626 for (i=0; i<size - 1; i++) {
627 int pos = (unsigned)dest[i];
628 dest[i] = alphanum_upper_table[pos % (sizeof(alphanum_upper_table) - 1)];
629 }
630 dest[i] = '\0';
631
632 return 0;
633}
634
635static const char alphanum_lower_table[]="0123456789abcdefghijklmnopqrstuvwxyz";
636
637int gen_rand_alphanumeric_lower(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
638{
639 int ret = get_random_bytes(dest, size);
640 if (ret < 0) {
641 lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
642 return ret;
643 }
644
645 int i;
646 for (i=0; i<size - 1; i++) {
647 int pos = (unsigned)dest[i];
648 dest[i] = alphanum_lower_table[pos % (sizeof(alphanum_lower_table) - 1)];
649 }
650 dest[i] = '\0';
651
652 return 0;
653}
654
655int gen_rand_alphanumeric_lower(CephContext *cct, string *str, int length)
656{
657 char buf[length + 1];
658 int ret = gen_rand_alphanumeric_lower(cct, buf, sizeof(buf));
659 if (ret < 0) {
660 return ret;
661 }
662 *str = buf;
663 return 0;
664}
665
666// this is basically a modified base64 charset, url friendly
667static const char alphanum_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
668
669int gen_rand_alphanumeric(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
670{
671 int ret = get_random_bytes(dest, size);
672 if (ret < 0) {
673 lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
674 return ret;
675 }
676
677 int i;
678 for (i=0; i<size - 1; i++) {
679 int pos = (unsigned)dest[i];
680 dest[i] = alphanum_table[pos & 63];
681 }
682 dest[i] = '\0';
683
684 return 0;
685}
686
687static const char alphanum_no_underscore_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.";
688
689int gen_rand_alphanumeric_no_underscore(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
690{
691 int ret = get_random_bytes(dest, size);
692 if (ret < 0) {
693 lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
694 return ret;
695 }
696
697 int i;
698 for (i=0; i<size - 1; i++) {
699 int pos = (unsigned)dest[i];
700 dest[i] = alphanum_no_underscore_table[pos & 63];
701 }
702 dest[i] = '\0';
703
704 return 0;
705}
706
707static const char alphanum_plain_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
708
709int gen_rand_alphanumeric_plain(CephContext *cct, char *dest, int size) /* size should be the required string size + 1 */
710{
711 int ret = get_random_bytes(dest, size);
712 if (ret < 0) {
713 lderr(cct) << "cannot get random bytes: " << cpp_strerror(-ret) << dendl;
714 return ret;
715 }
716
717 int i;
718 for (i=0; i<size - 1; i++) {
719 int pos = (unsigned)dest[i];
720 dest[i] = alphanum_plain_table[pos % (sizeof(alphanum_plain_table) - 1)];
721 }
722 dest[i] = '\0';
723
724 return 0;
725}
726
727int NameVal::parse()
728{
729 int delim_pos = str.find('=');
730 int ret = 0;
731
732 if (delim_pos < 0) {
733 name = str;
734 val = "";
735 ret = 1;
736 } else {
737 name = str.substr(0, delim_pos);
738 val = str.substr(delim_pos + 1);
739 }
740
741 return ret;
742}
743
744int RGWHTTPArgs::parse()
745{
746 int pos = 0;
747 bool end = false;
748
749 if (str.empty())
750 return 0;
751
752 if (str[pos] == '?')
753 pos++;
754
755 while (!end) {
756 int fpos = str.find('&', pos);
757 if (fpos < pos) {
758 end = true;
759 fpos = str.size();
760 }
761 string substr, nameval;
762 substr = str.substr(pos, fpos - pos);
763 url_decode(substr, nameval, true);
764 NameVal nv(nameval);
765 int ret = nv.parse();
766 if (ret >= 0) {
767 string& name = nv.get_name();
768 string& val = nv.get_val();
769
770 append(name, val);
771 }
772
773 pos = fpos + 1;
774 }
775
776 return 0;
777}
778
779void RGWHTTPArgs::append(const string& name, const string& val)
780{
781 if (name.compare(0, sizeof(RGW_SYS_PARAM_PREFIX) - 1, RGW_SYS_PARAM_PREFIX) == 0) {
782 sys_val_map[name] = val;
783 } else {
784 val_map[name] = val;
785 }
786
787 if ((name.compare("acl") == 0) ||
788 (name.compare("cors") == 0) ||
789 (name.compare("location") == 0) ||
790 (name.compare("logging") == 0) ||
791 (name.compare("usage") == 0) ||
792 (name.compare("lifecycle") == 0) ||
793 (name.compare("delete") == 0) ||
794 (name.compare("uploads") == 0) ||
795 (name.compare("partNumber") == 0) ||
796 (name.compare("uploadId") == 0) ||
797 (name.compare("versionId") == 0) ||
798 (name.compare("start-date") == 0) ||
799 (name.compare("end-date") == 0) ||
800 (name.compare("versions") == 0) ||
801 (name.compare("versioning") == 0) ||
802 (name.compare("website") == 0) ||
803 (name.compare("requestPayment") == 0) ||
804 (name.compare("torrent") == 0)) {
805 sub_resources[name] = val;
806 } else if (name[0] == 'r') { // root of all evil
807 if ((name.compare("response-content-type") == 0) ||
808 (name.compare("response-content-language") == 0) ||
809 (name.compare("response-expires") == 0) ||
810 (name.compare("response-cache-control") == 0) ||
811 (name.compare("response-content-disposition") == 0) ||
812 (name.compare("response-content-encoding") == 0)) {
813 sub_resources[name] = val;
814 has_resp_modifier = true;
815 }
816 } else if ((name.compare("subuser") == 0) ||
817 (name.compare("key") == 0) ||
818 (name.compare("caps") == 0) ||
819 (name.compare("index") == 0) ||
820 (name.compare("policy") == 0) ||
821 (name.compare("quota") == 0) ||
822 (name.compare("object") == 0)) {
823
824 if (!admin_subresource_added) {
825 sub_resources[name] = "";
826 admin_subresource_added = true;
827 }
828 }
829}
830
831const string& RGWHTTPArgs::get(const string& name, bool *exists) const
832{
833 auto iter = val_map.find(name);
834 bool e = (iter != std::end(val_map));
835 if (exists)
836 *exists = e;
837 if (e)
838 return iter->second;
839 return empty_str;
840}
841
842int RGWHTTPArgs::get_bool(const string& name, bool *val, bool *exists)
843{
844 map<string, string>::iterator iter;
845 iter = val_map.find(name);
846 bool e = (iter != val_map.end());
847 if (exists)
848 *exists = e;
849
850 if (e) {
851 const char *s = iter->second.c_str();
852
853 if (strcasecmp(s, "false") == 0) {
854 *val = false;
855 } else if (strcasecmp(s, "true") == 0) {
856 *val = true;
857 } else {
858 return -EINVAL;
859 }
860 }
861
862 return 0;
863}
864
865int RGWHTTPArgs::get_bool(const char *name, bool *val, bool *exists)
866{
867 string s(name);
868 return get_bool(s, val, exists);
869}
870
871void RGWHTTPArgs::get_bool(const char *name, bool *val, bool def_val)
872{
873 bool exists = false;
874 if ((get_bool(name, val, &exists) < 0) ||
875 !exists) {
876 *val = def_val;
877 }
878}
879
880string RGWHTTPArgs::sys_get(const string& name, bool * const exists) const
881{
882 const auto iter = sys_val_map.find(name);
883 const bool e = (iter != sys_val_map.end());
884
885 if (exists) {
886 *exists = e;
887 }
888
889 return e ? iter->second : string();
890}
891
892bool verify_user_permission(struct req_state * const s,
893 RGWAccessControlPolicy * const user_acl,
894 const int perm)
895{
896 /* S3 doesn't support account ACLs. */
897 if (!user_acl)
898 return true;
899
900 if ((perm & (int)s->perm_mask) != perm)
901 return false;
902
903 return user_acl->verify_permission(*s->auth.identity, perm, perm);
904}
905
906bool verify_user_permission(struct req_state * const s,
907 const int perm)
908{
909 return verify_user_permission(s, s->user_acl.get(), perm);
910}
911
912bool verify_requester_payer_permission(struct req_state *s)
913{
914 if (!s->bucket_info.requester_pays)
915 return true;
916
917 if (s->auth.identity->is_owner_of(s->bucket_info.owner))
918 return true;
919
920 if (s->auth.identity->is_anonymous()) {
921 return false;
922 }
923
924 const char *request_payer = s->info.env->get("HTTP_X_AMZ_REQUEST_PAYER");
925 if (!request_payer) {
926 bool exists;
927 request_payer = s->info.args.get("x-amz-request-payer", &exists).c_str();
928 if (!exists) {
929 return false;
930 }
931 }
932
933 if (strcasecmp(request_payer, "requester") == 0) {
934 return true;
935 }
936
937 return false;
938}
939
940bool verify_bucket_permission(struct req_state * const s,
941 RGWAccessControlPolicy * const user_acl,
942 RGWAccessControlPolicy * const bucket_acl,
943 const int perm)
944{
945 if (!bucket_acl)
946 return false;
947
948 if ((perm & (int)s->perm_mask) != perm)
949 return false;
950
951 if (!verify_requester_payer_permission(s))
952 return false;
953
954 if (bucket_acl->verify_permission(*s->auth.identity, perm, perm,
955 s->info.env->get("HTTP_REFERER")))
956 return true;
957
958 if (!user_acl)
959 return false;
960
961 return user_acl->verify_permission(*s->auth.identity, perm, perm);
962}
963
964bool verify_bucket_permission(struct req_state * const s, const int perm)
965{
966 return verify_bucket_permission(s,
967 s->user_acl.get(),
968 s->bucket_acl,
969 perm);
970}
971
972static inline bool check_deferred_bucket_acl(struct req_state * const s,
973 RGWAccessControlPolicy * const user_acl,
974 RGWAccessControlPolicy * const bucket_acl,
975 const uint8_t deferred_check,
976 const int perm)
977{
978 return (s->defer_to_bucket_acls == deferred_check \
979 && verify_bucket_permission(s, user_acl, bucket_acl, perm));
980}
981
982bool verify_object_permission(struct req_state * const s,
983 RGWAccessControlPolicy * const user_acl,
984 RGWAccessControlPolicy * const bucket_acl,
985 RGWAccessControlPolicy * const object_acl,
986 const int perm)
987{
988 if (!verify_requester_payer_permission(s))
989 return false;
990
991 if (check_deferred_bucket_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_RECURSE, perm) ||
992 check_deferred_bucket_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, RGW_PERM_FULL_CONTROL)) {
993 return true;
994 }
995
996 if (!object_acl) {
997 return false;
998 }
999
1000 bool ret = object_acl->verify_permission(*s->auth.identity, s->perm_mask, perm);
1001 if (ret) {
1002 return true;
1003 }
1004
1005 if (!s->cct->_conf->rgw_enforce_swift_acls)
1006 return ret;
1007
1008 if ((perm & (int)s->perm_mask) != perm)
1009 return false;
1010
1011 int swift_perm = 0;
1012 if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP))
1013 swift_perm |= RGW_PERM_READ_OBJS;
1014 if (perm & RGW_PERM_WRITE)
1015 swift_perm |= RGW_PERM_WRITE_OBJS;
1016
1017 if (!swift_perm)
1018 return false;
1019
1020 /* we already verified the user mask above, so we pass swift_perm as the mask here,
1021 otherwise the mask might not cover the swift permissions bits */
1022 if (bucket_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm,
1023 s->info.env->get("HTTP_REFERER")))
1024 return true;
1025
1026 if (!user_acl)
1027 return false;
1028
1029 return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm);
1030}
1031
1032bool verify_object_permission(struct req_state *s, int perm)
1033{
1034 return verify_object_permission(s,
1035 s->user_acl.get(),
1036 s->bucket_acl,
1037 s->object_acl,
1038 perm);
1039}
1040
1041class HexTable
1042{
1043 char table[256];
1044
1045public:
1046 HexTable() {
1047 memset(table, -1, sizeof(table));
1048 int i;
1049 for (i = '0'; i<='9'; i++)
1050 table[i] = i - '0';
1051 for (i = 'A'; i<='F'; i++)
1052 table[i] = i - 'A' + 0xa;
1053 for (i = 'a'; i<='f'; i++)
1054 table[i] = i - 'a' + 0xa;
1055 }
1056
1057 char to_num(char c) {
1058 return table[(int)c];
1059 }
1060};
1061
1062static char hex_to_num(char c)
1063{
1064 static HexTable hex_table;
1065 return hex_table.to_num(c);
1066}
1067
1068bool url_decode(const string& src_str, string& dest_str, bool in_query)
1069{
1070 const char *src = src_str.c_str();
1071 char dest[src_str.size() + 1];
1072 int pos = 0;
1073 char c;
1074
1075 while (*src) {
1076 if (*src != '%') {
1077 if (!in_query || *src != '+') {
1078 if (*src == '?') in_query = true;
1079 dest[pos++] = *src++;
1080 } else {
1081 dest[pos++] = ' ';
1082 ++src;
1083 }
1084 } else {
1085 src++;
1086 if (!*src)
1087 break;
1088 char c1 = hex_to_num(*src++);
1089 if (!*src)
1090 break;
1091 c = c1 << 4;
1092 if (c1 < 0)
1093 return false;
1094 c1 = hex_to_num(*src++);
1095 if (c1 < 0)
1096 return false;
1097 c |= c1;
1098 dest[pos++] = c;
1099 }
1100 }
1101 dest[pos] = 0;
1102 dest_str = dest;
1103
1104 return true;
1105}
1106
1107void rgw_uri_escape_char(char c, string& dst)
1108{
1109 char buf[16];
1110 snprintf(buf, sizeof(buf), "%%%.2X", (int)(unsigned char)c);
1111 dst.append(buf);
1112}
1113
1114static bool char_needs_url_encoding(char c)
1115{
1116 if (c <= 0x20 || c >= 0x7f)
1117 return true;
1118
1119 switch (c) {
1120 case 0x22:
1121 case 0x23:
1122 case 0x25:
1123 case 0x26:
1124 case 0x2B:
1125 case 0x2C:
1126 case 0x2F:
1127 case 0x3A:
1128 case 0x3B:
1129 case 0x3C:
1130 case 0x3E:
1131 case 0x3D:
1132 case 0x3F:
1133 case 0x40:
1134 case 0x5B:
1135 case 0x5D:
1136 case 0x5C:
1137 case 0x5E:
1138 case 0x60:
1139 case 0x7B:
1140 case 0x7D:
1141 return true;
1142 }
1143 return false;
1144}
1145
1146void url_encode(const string& src, string& dst)
1147{
1148 const char *p = src.c_str();
1149 for (unsigned i = 0; i < src.size(); i++, p++) {
1150 if (char_needs_url_encoding(*p)) {
1151 rgw_uri_escape_char(*p, dst);
1152 continue;
1153 }
1154
1155 dst.append(p, 1);
1156 }
1157}
1158
1159std::string url_encode(const std::string& src)
1160{
1161 std::string dst;
1162 url_encode(src, dst);
1163
1164 return dst;
1165}
1166
1167string rgw_trim_whitespace(const string& src)
1168{
1169 if (src.empty()) {
1170 return string();
1171 }
1172
1173 int start = 0;
1174 for (; start != (int)src.size(); start++) {
1175 if (!isspace(src[start]))
1176 break;
1177 }
1178
1179 int end = src.size() - 1;
1180 if (end < start) {
1181 return string();
1182 }
1183
1184 for (; end > start; end--) {
1185 if (!isspace(src[end]))
1186 break;
1187 }
1188
1189 return src.substr(start, end - start + 1);
1190}
1191
1192boost::string_ref rgw_trim_whitespace(const boost::string_ref& src)
1193{
1194 boost::string_ref res = src;
1195
1196 while (res.size() > 0 && std::isspace(res.front())) {
1197 res.remove_prefix(1);
1198 }
1199 while (res.size() > 0 && std::isspace(res.back())) {
1200 res.remove_suffix(1);
1201 }
1202 return res;
1203}
1204
1205string rgw_trim_quotes(const string& val)
1206{
1207 string s = rgw_trim_whitespace(val);
1208 if (s.size() < 2)
1209 return s;
1210
1211 int start = 0;
1212 int end = s.size() - 1;
1213 int quotes_count = 0;
1214
1215 if (s[start] == '"') {
1216 start++;
1217 quotes_count++;
1218 }
1219 if (s[end] == '"') {
1220 end--;
1221 quotes_count++;
1222 }
1223 if (quotes_count == 2) {
1224 return s.substr(start, end - start + 1);
1225 }
1226 return s;
1227}
1228
1229struct rgw_name_to_flag {
1230 const char *type_name;
1231 uint32_t flag;
1232};
1233
1234static int parse_list_of_flags(struct rgw_name_to_flag *mapping,
1235 const string& str, uint32_t *perm)
1236{
1237 list<string> strs;
1238 get_str_list(str, strs);
1239 list<string>::iterator iter;
1240 uint32_t v = 0;
1241 for (iter = strs.begin(); iter != strs.end(); ++iter) {
1242 string& s = *iter;
1243 for (int i = 0; mapping[i].type_name; i++) {
1244 if (s.compare(mapping[i].type_name) == 0)
1245 v |= mapping[i].flag;
1246 }
1247 }
1248
1249 *perm = v;
1250 return 0;
1251}
1252
1253static struct rgw_name_to_flag cap_names[] = { {"*", RGW_CAP_ALL},
1254 {"read", RGW_CAP_READ},
1255 {"write", RGW_CAP_WRITE},
1256 {NULL, 0} };
1257
1258int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm)
1259{
1260 return parse_list_of_flags(cap_names, str, perm);
1261}
1262
1263int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm)
1264{
1265 int pos = cap.find('=');
1266 if (pos >= 0) {
1267 trim_whitespace(cap.substr(0, pos), type);
1268 }
1269
1270 if (!is_valid_cap_type(type))
1271 return -ERR_INVALID_CAP;
1272
1273 string cap_perm;
1274 uint32_t perm = 0;
1275 if (pos < (int)cap.size() - 1) {
1276 cap_perm = cap.substr(pos + 1);
1277 int r = RGWUserCaps::parse_cap_perm(cap_perm, &perm);
1278 if (r < 0)
1279 return r;
1280 }
1281
1282 *pperm = perm;
1283
1284 return 0;
1285}
1286
1287int RGWUserCaps::add_cap(const string& cap)
1288{
1289 uint32_t perm;
1290 string type;
1291
1292 int r = get_cap(cap, type, &perm);
1293 if (r < 0)
1294 return r;
1295
1296 caps[type] |= perm;
1297
1298 return 0;
1299}
1300
1301int RGWUserCaps::remove_cap(const string& cap)
1302{
1303 uint32_t perm;
1304 string type;
1305
1306 int r = get_cap(cap, type, &perm);
1307 if (r < 0)
1308 return r;
1309
1310 map<string, uint32_t>::iterator iter = caps.find(type);
1311 if (iter == caps.end())
1312 return 0;
1313
1314 uint32_t& old_perm = iter->second;
1315 old_perm &= ~perm;
1316 if (!old_perm)
1317 caps.erase(iter);
1318
1319 return 0;
1320}
1321
1322int RGWUserCaps::add_from_string(const string& str)
1323{
1324 int start = 0;
1325 do {
1326 int end = str.find(';', start);
1327 if (end < 0)
1328 end = str.size();
1329
1330 int r = add_cap(str.substr(start, end - start));
1331 if (r < 0)
1332 return r;
1333
1334 start = end + 1;
1335 } while (start < (int)str.size());
1336
1337 return 0;
1338}
1339
1340int RGWUserCaps::remove_from_string(const string& str)
1341{
1342 int start = 0;
1343 do {
1344 int end = str.find(';', start);
1345 if (end < 0)
1346 end = str.size();
1347
1348 int r = remove_cap(str.substr(start, end - start));
1349 if (r < 0)
1350 return r;
1351
1352 start = end + 1;
1353 } while (start < (int)str.size());
1354
1355 return 0;
1356}
1357
1358void RGWUserCaps::dump(Formatter *f) const
1359{
1360 dump(f, "caps");
1361}
1362
1363void RGWUserCaps::dump(Formatter *f, const char *name) const
1364{
1365 f->open_array_section(name);
1366 map<string, uint32_t>::const_iterator iter;
1367 for (iter = caps.begin(); iter != caps.end(); ++iter)
1368 {
1369 f->open_object_section("cap");
1370 f->dump_string("type", iter->first);
1371 uint32_t perm = iter->second;
1372 string perm_str;
1373 for (int i=0; cap_names[i].type_name; i++) {
1374 if ((perm & cap_names[i].flag) == cap_names[i].flag) {
1375 if (perm_str.size())
1376 perm_str.append(", ");
1377
1378 perm_str.append(cap_names[i].type_name);
1379 perm &= ~cap_names[i].flag;
1380 }
1381 }
1382 if (perm_str.empty())
1383 perm_str = "<none>";
1384
1385 f->dump_string("perm", perm_str);
1386 f->close_section();
1387 }
1388
1389 f->close_section();
1390}
1391
1392struct RGWUserCap {
1393 string type;
1394 uint32_t perm;
1395
1396 void decode_json(JSONObj *obj) {
1397 JSONDecoder::decode_json("type", type, obj);
1398 string perm_str;
1399 JSONDecoder::decode_json("perm", perm_str, obj);
1400 if (RGWUserCaps::parse_cap_perm(perm_str, &perm) < 0) {
1401 throw JSONDecoder::err("failed to parse permissions");
1402 }
1403 }
1404};
1405
1406void RGWUserCaps::decode_json(JSONObj *obj)
1407{
1408 list<RGWUserCap> caps_list;
1409 decode_json_obj(caps_list, obj);
1410
1411 list<RGWUserCap>::iterator iter;
1412 for (iter = caps_list.begin(); iter != caps_list.end(); ++iter) {
1413 RGWUserCap& cap = *iter;
1414 caps[cap.type] = cap.perm;
1415 }
1416}
1417
1418int RGWUserCaps::check_cap(const string& cap, uint32_t perm)
1419{
1420 map<string, uint32_t>::iterator iter = caps.find(cap);
1421
1422 if ((iter == caps.end()) ||
1423 (iter->second & perm) != perm) {
1424 return -EPERM;
1425 }
1426
1427 return 0;
1428}
1429
1430bool RGWUserCaps::is_valid_cap_type(const string& tp)
1431{
1432 static const char *cap_type[] = { "user",
1433 "users",
1434 "buckets",
1435 "metadata",
1436 "usage",
1437 "zone",
1438 "bilog",
1439 "mdlog",
1440 "datalog",
1441 "opstate" };
1442
1443 for (unsigned int i = 0; i < sizeof(cap_type) / sizeof(char *); ++i) {
1444 if (tp.compare(cap_type[i]) == 0) {
1445 return true;
1446 }
1447 }
1448
1449 return false;
1450}
1451
1452static ssize_t unescape_str(const string& s, ssize_t ofs, char esc_char, char special_char, string *dest)
1453{
1454 const char *src = s.c_str();
1455 char dest_buf[s.size() + 1];
1456 char *destp = dest_buf;
1457 bool esc = false;
1458
1459 dest_buf[0] = '\0';
1460
1461 for (size_t i = ofs; i < s.size(); i++) {
1462 char c = src[i];
1463 if (!esc && c == esc_char) {
1464 esc = true;
1465 continue;
1466 }
1467 if (!esc && c == special_char) {
1468 *destp = '\0';
1469 *dest = dest_buf;
1470 return (ssize_t)i + 1;
1471 }
1472 *destp++ = c;
1473 esc = false;
1474 }
1475 *destp = '\0';
1476 *dest = dest_buf;
1477 return string::npos;
1478}
1479
1480static void escape_str(const string& s, char esc_char, char special_char, string *dest)
1481{
1482 const char *src = s.c_str();
1483 char dest_buf[s.size() * 2 + 1];
1484 char *destp = dest_buf;
1485
1486 for (size_t i = 0; i < s.size(); i++) {
1487 char c = src[i];
1488 if (c == esc_char || c == special_char) {
1489 *destp++ = esc_char;
1490 }
1491 *destp++ = c;
1492 }
1493 *destp++ = '\0';
1494 *dest = dest_buf;
1495}
1496
1497void rgw_pool::from_str(const string& s)
1498{
1499 size_t pos = unescape_str(s, 0, '\\', ':', &name);
1500 if (pos != string::npos) {
1501 pos = unescape_str(s, pos, '\\', ':', &ns);
1502 /* ignore return; if pos != string::npos it means that we had a colon
1503 * in the middle of ns that wasn't escaped, we're going to stop there
1504 */
1505 }
1506}
1507
1508string rgw_pool::to_str() const
1509{
1510 string esc_name;
1511 escape_str(name, '\\', ':', &esc_name);
1512 if (ns.empty()) {
1513 return esc_name;
1514 }
1515 string esc_ns;
1516 escape_str(ns, '\\', ':', &esc_ns);
1517 return esc_name + ":" + esc_ns;
1518}
1519
1520void rgw_raw_obj::decode_from_rgw_obj(bufferlist::iterator& bl)
1521{
1522 rgw_obj old_obj;
1523 ::decode(old_obj, bl);
1524
1525 get_obj_bucket_and_oid_loc(old_obj, oid, loc);
1526 pool = old_obj.get_explicit_data_pool();
1527}
1528
1529std::string rgw_bucket::get_key(char tenant_delim, char id_delim) const
1530{
1531 static constexpr size_t shard_len{12}; // ":4294967295\0"
1532 const size_t max_len = tenant.size() + sizeof(tenant_delim) +
1533 name.size() + sizeof(id_delim) + bucket_id.size() + shard_len;
1534
1535 std::string key;
1536 key.reserve(max_len);
1537 if (!tenant.empty() && tenant_delim) {
1538 key.append(tenant);
1539 key.append(1, tenant_delim);
1540 }
1541 key.append(name);
1542 if (!bucket_id.empty() && id_delim) {
1543 key.append(1, id_delim);
1544 key.append(bucket_id);
1545 }
1546 return key;
1547}
1548
1549std::string rgw_bucket_shard::get_key(char tenant_delim, char id_delim,
1550 char shard_delim) const
1551{
1552 auto key = bucket.get_key(tenant_delim, id_delim);
1553 if (shard_id >= 0 && shard_delim) {
1554 key.append(1, shard_delim);
1555 key.append(std::to_string(shard_id));
1556 }
1557 return key;
1558}
1559
1560static struct rgw_name_to_flag op_type_mapping[] = { {"*", RGW_OP_TYPE_ALL},
1561 {"read", RGW_OP_TYPE_READ},
1562 {"write", RGW_OP_TYPE_WRITE},
1563 {"delete", RGW_OP_TYPE_DELETE},
1564 {NULL, 0} };
1565
1566
1567int rgw_parse_op_type_list(const string& str, uint32_t *perm)
1568{
1569 return parse_list_of_flags(op_type_mapping, str, perm);
1570}
1571
1572static int match_internal(boost::string_ref pattern, boost::string_ref input, int (*function)(const char&, const char&))
1573{
1574 boost::string_ref::iterator it1 = pattern.begin();
1575 boost::string_ref::iterator it2 = input.begin();
1576 while(true) {
1577 if (it1 == pattern.end() && it2 == input.end())
1578 return 1;
1579 if (it1 == pattern.end() || it2 == input.end())
1580 return 0;
1581 if (*it1 == '*' && (it1 + 1) == pattern.end() && it2 != input.end())
1582 return 1;
1583 if (*it1 == '*' && (it1 + 1) == pattern.end() && it2 == input.end())
1584 return 0;
1585 if (function(*it1, *it2) || *it1 == '?') {
1586 ++it1;
1587 ++it2;
1588 continue;
1589 }
1590 if (*it1 == '*') {
1591 if (function(*(it1 + 1), *it2))
1592 ++it1;
1593 else
1594 ++it2;
1595 continue;
1596 }
1597 return 0;
1598 }
1599 return 0;
1600}
1601
1602static int matchcase(const char& c1, const char& c2)
1603{
1604 if (c1 == c2)
1605 return 1;
1606 return 0;
1607}
1608
1609static int matchignorecase(const char& c1, const char& c2)
1610{
1611 if (tolower(c1) == tolower(c2))
1612 return 1;
1613 return 0;
1614}
1615
1616int match(const string& pattern, const string& input, int flag)
1617{
1618 auto last_pos_input = 0, last_pos_pattern = 0;
1619
1620 while(true) {
1621 auto cur_pos_input = input.find(":", last_pos_input);
1622 auto cur_pos_pattern = pattern.find(":", last_pos_pattern);
1623
1624 string substr_input = input.substr(last_pos_input, cur_pos_input);
1625 string substr_pattern = pattern.substr(last_pos_pattern, cur_pos_pattern);
1626
1627 int res;
1628 if (flag & POLICY_ACTION || flag & POLICY_ARN) {
1629 res = match_internal(substr_pattern, substr_input, &matchignorecase);
1630 } else {
1631 res = match_internal(substr_pattern, substr_input, &matchcase);
1632 }
1633 if (res == 0)
1634 return 0;
1635
1636 if (cur_pos_pattern == string::npos && cur_pos_input == string::npos)
1637 return 1;
1638 else if ((cur_pos_pattern == string::npos && cur_pos_input != string::npos) ||
1639 (cur_pos_pattern != string::npos && cur_pos_input == string::npos))
1640 return 0;
1641
1642 last_pos_pattern = cur_pos_pattern + 1;
1643 last_pos_input = cur_pos_input + 1;
1644 }
1645}