1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "common/ceph_json.h"
7 #include "rgw_policy_s3.h"
8 #include "rgw_common.h"
9 #include "rgw_crypt_sanitize.h"
11 #define dout_context g_ceph_context
12 #define dout_subsys ceph_subsys_rgw
14 class RGWPolicyCondition
{
19 virtual bool check(const string
& first
, const string
& second
, string
& err_msg
) = 0;
22 virtual ~RGWPolicyCondition() {}
24 void set_vals(const string
& _v1
, const string
& _v2
) {
29 bool check(RGWPolicyEnv
*env
, map
<string
, bool, ltstr_nocase
>& checked_vars
, string
& err_msg
) {
31 env
->get_value(v1
, first
, checked_vars
);
32 env
->get_value(v2
, second
, checked_vars
);
33 dout(1) << "policy condition check " << v1
<< " ["
34 << rgw::crypt_sanitize::s3_policy
{v1
, first
}
36 << rgw::crypt_sanitize::s3_policy
{v2
, second
}
38 bool ret
= check(first
, second
, err_msg
);
51 class RGWPolicyCondition_StrEqual
: public RGWPolicyCondition
{
53 bool check(const string
& first
, const string
& second
, string
& msg
) override
{
54 bool ret
= first
.compare(second
) == 0;
56 msg
= "Policy condition failed: eq";
62 class RGWPolicyCondition_StrStartsWith
: public RGWPolicyCondition
{
64 bool check(const string
& first
, const string
& second
, string
& msg
) override
{
65 bool ret
= first
.compare(0, second
.size(), second
) == 0;
67 msg
= "Policy condition failed: starts-with";
73 void RGWPolicyEnv::add_var(const string
& name
, const string
& value
)
78 bool RGWPolicyEnv::get_var(const string
& name
, string
& val
)
80 map
<string
, string
, ltstr_nocase
>::iterator iter
= vars
.find(name
);
81 if (iter
== vars
.end())
89 bool RGWPolicyEnv::get_value(const string
& s
, string
& val
, map
<string
, bool, ltstr_nocase
>& checked_vars
)
91 if (s
.empty() || s
[0] != '$') {
96 const string
& var
= s
.substr(1);
97 checked_vars
[var
] = true;
99 return get_var(var
, val
);
103 bool RGWPolicyEnv::match_policy_vars(map
<string
, bool, ltstr_nocase
>& policy_vars
, string
& err_msg
)
105 map
<string
, string
, ltstr_nocase
>::iterator iter
;
106 string ignore_prefix
= "x-ignore-";
107 for (iter
= vars
.begin(); iter
!= vars
.end(); ++iter
) {
108 const string
& var
= iter
->first
;
109 if (strncasecmp(ignore_prefix
.c_str(), var
.c_str(), ignore_prefix
.size()) == 0)
111 if (policy_vars
.count(var
) == 0) {
112 err_msg
= "Policy missing condition: ";
113 err_msg
.append(iter
->first
);
114 dout(1) << "env var missing in policy: " << iter
->first
<< dendl
;
121 RGWPolicy::~RGWPolicy()
123 list
<RGWPolicyCondition
*>::iterator citer
;
124 for (citer
= conditions
.begin(); citer
!= conditions
.end(); ++citer
) {
125 RGWPolicyCondition
*cond
= *citer
;
130 int RGWPolicy::set_expires(const string
& e
)
133 if (!parse_iso8601(e
.c_str(), &t
))
136 expires
= internal_timegm(&t
);
141 int RGWPolicy::add_condition(const string
& op
, const string
& first
, const string
& second
, string
& err_msg
)
143 RGWPolicyCondition
*cond
= NULL
;
144 if (stringcasecmp(op
, "eq") == 0) {
145 cond
= new RGWPolicyCondition_StrEqual
;
146 } else if (stringcasecmp(op
, "starts-with") == 0) {
147 cond
= new RGWPolicyCondition_StrStartsWith
;
148 } else if (stringcasecmp(op
, "content-length-range") == 0) {
150 int r
= stringtoll(first
, &min
);
152 err_msg
= "Bad content-length-range param";
153 dout(0) << "bad content-length-range param: " << first
<< dendl
;
157 r
= stringtoll(second
, &max
);
159 err_msg
= "Bad content-length-range param";
160 dout(0) << "bad content-length-range param: " << second
<< dendl
;
164 if (min
> min_length
)
167 if (max
< max_length
)
174 err_msg
= "Invalid condition: ";
176 dout(0) << "invalid condition: " << op
<< dendl
;
180 cond
->set_vals(first
, second
);
182 conditions
.push_back(cond
);
187 int RGWPolicy::check(RGWPolicyEnv
*env
, string
& err_msg
)
189 uint64_t now
= ceph_clock_now().sec();
190 if (expires
<= now
) {
191 dout(0) << "NOTICE: policy calculated as expired: " << expiration_str
<< dendl
;
192 err_msg
= "Policy expired";
193 return -EACCES
; // change to condition about expired policy following S3
196 list
<pair
<string
, string
> >::iterator viter
;
197 for (viter
= var_checks
.begin(); viter
!= var_checks
.end(); ++viter
) {
198 pair
<string
, string
>& p
= *viter
;
199 const string
& name
= p
.first
;
200 const string
& check_val
= p
.second
;
202 if (!env
->get_var(name
, val
)) {
203 dout(20) << " policy check failed, variable not found: '" << name
<< "'" << dendl
;
204 err_msg
= "Policy check failed, variable not found: ";
205 err_msg
.append(name
);
209 set_var_checked(name
);
211 dout(20) << "comparing " << name
<< " [" << val
<< "], " << check_val
<< dendl
;
212 if (val
.compare(check_val
) != 0) {
213 err_msg
= "Policy check failed, variable not met condition: ";
214 err_msg
.append(name
);
215 dout(1) << "policy check failed, val=" << val
<< " != " << check_val
<< dendl
;
220 list
<RGWPolicyCondition
*>::iterator citer
;
221 for (citer
= conditions
.begin(); citer
!= conditions
.end(); ++citer
) {
222 RGWPolicyCondition
*cond
= *citer
;
223 if (!cond
->check(env
, checked_vars
, err_msg
)) {
228 if (!env
->match_policy_vars(checked_vars
, err_msg
)) {
229 dout(1) << "missing policy condition" << dendl
;
236 int RGWPolicy::from_json(bufferlist
& bl
, string
& err_msg
)
240 if (!parser
.parse(bl
.c_str(), bl
.length())) {
241 err_msg
= "Malformed JSON";
242 dout(0) << "malformed json" << dendl
;
246 // as no time was included in the request, we hope that the user has included a short timeout
247 JSONObjIter iter
= parser
.find_first("expiration");
249 err_msg
= "Policy missing expiration";
250 dout(0) << "expiration not found" << dendl
;
251 return -EINVAL
; // change to a "no expiration" error following S3
254 JSONObj
*obj
= *iter
;
255 expiration_str
= obj
->get_data();
256 int r
= set_expires(expiration_str
);
258 err_msg
= "Failed to parse policy expiration";
262 iter
= parser
.find_first("conditions");
264 err_msg
= "Policy missing conditions";
265 dout(0) << "conditions not found" << dendl
;
266 return -EINVAL
; // change to a "no conditions" error following S3
271 iter
= obj
->find_first();
272 for (; !iter
.end(); ++iter
) {
273 JSONObj
*child
= *iter
;
274 dout(20) << "data=" << child
->get_data() << dendl
;
275 dout(20) << "is_object=" << child
->is_object() << dendl
;
276 dout(20) << "is_array=" << child
->is_array() << dendl
;
277 JSONObjIter citer
= child
->find_first();
278 if (child
->is_array()) {
281 for (i
= 0; !citer
.end() && i
< 3; ++citer
, ++i
) {
283 v
.push_back(o
->get_data());
285 if (i
!= 3 || !citer
.end()) { /* we expect exactly 3 arguments here */
286 err_msg
= "Bad condition array, expecting 3 arguments";
290 int r
= add_condition(v
[0], v
[1], v
[2], err_msg
);
293 } else if (!citer
.end()) {
295 dout(20) << "adding simple_check: " << c
->get_name() << " : " << c
->get_data() << dendl
;
297 add_simple_check(c
->get_name(), c
->get_data());