]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_policy_s3.cc
update sources to v12.1.2
[ceph.git] / ceph / src / rgw / rgw_policy_s3.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
6#include "common/ceph_json.h"
7#include "rgw_policy_s3.h"
8#include "rgw_common.h"
9#include "rgw_crypt_sanitize.h"
10
11#define dout_context g_ceph_context
12#define dout_subsys ceph_subsys_rgw
13
14class RGWPolicyCondition {
15protected:
16 string v1;
17 string v2;
18
19 virtual bool check(const string& first, const string& second, string& err_msg) = 0;
20
21public:
22 virtual ~RGWPolicyCondition() {}
23
24 void set_vals(const string& _v1, const string& _v2) {
25 v1 = _v1;
26 v2 = _v2;
27 }
28
29 bool check(RGWPolicyEnv *env, map<string, bool, ltstr_nocase>& checked_vars, string& err_msg) {
30 string first, second;
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}
35 << "] " << v2 << " ["
36 << rgw::crypt_sanitize::s3_policy{v2, second}
37 << "]" << dendl;
38 bool ret = check(first, second, err_msg);
39 if (!ret) {
40 err_msg.append(": ");
41 err_msg.append(v1);
42 err_msg.append(", ");
43 err_msg.append(v2);
44 }
45 return ret;
46 }
47
48};
49
50
51class RGWPolicyCondition_StrEqual : public RGWPolicyCondition {
52protected:
53 bool check(const string& first, const string& second, string& msg) override {
54 bool ret = first.compare(second) == 0;
55 if (!ret) {
56 msg = "Policy condition failed: eq";
57 }
58 return ret;
59 }
60};
61
62class RGWPolicyCondition_StrStartsWith : public RGWPolicyCondition {
63protected:
64 bool check(const string& first, const string& second, string& msg) override {
65 bool ret = first.compare(0, second.size(), second) == 0;
66 if (!ret) {
67 msg = "Policy condition failed: starts-with";
68 }
69 return ret;
70 }
71};
72
73void RGWPolicyEnv::add_var(const string& name, const string& value)
74{
75 vars[name] = value;
76}
77
78bool RGWPolicyEnv::get_var(const string& name, string& val)
79{
80 map<string, string, ltstr_nocase>::iterator iter = vars.find(name);
81 if (iter == vars.end())
82 return false;
83
84 val = iter->second;
85
86 return true;
87}
88
89bool RGWPolicyEnv::get_value(const string& s, string& val, map<string, bool, ltstr_nocase>& checked_vars)
90{
91 if (s.empty() || s[0] != '$') {
92 val = s;
93 return true;
94 }
95
96 const string& var = s.substr(1);
97 checked_vars[var] = true;
98
99 return get_var(var, val);
100}
101
102
103bool RGWPolicyEnv::match_policy_vars(map<string, bool, ltstr_nocase>& policy_vars, string& err_msg)
104{
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)
110 continue;
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;
115 return false;
116 }
117 }
118 return true;
119}
120
121RGWPolicy::~RGWPolicy()
122{
123 list<RGWPolicyCondition *>::iterator citer;
124 for (citer = conditions.begin(); citer != conditions.end(); ++citer) {
125 RGWPolicyCondition *cond = *citer;
126 delete cond;
127 }
128}
129
130int RGWPolicy::set_expires(const string& e)
131{
132 struct tm t;
133 if (!parse_iso8601(e.c_str(), &t))
134 return -EINVAL;
135
136 expires = internal_timegm(&t);
137
138 return 0;
139}
140
141int RGWPolicy::add_condition(const string& op, const string& first, const string& second, string& err_msg)
142{
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) {
149 off_t min, max;
150 int r = stringtoll(first, &min);
151 if (r < 0) {
152 err_msg = "Bad content-length-range param";
153 dout(0) << "bad content-length-range param: " << first << dendl;
154 return r;
155 }
156
157 r = stringtoll(second, &max);
158 if (r < 0) {
159 err_msg = "Bad content-length-range param";
160 dout(0) << "bad content-length-range param: " << second << dendl;
161 return r;
162 }
163
164 if (min > min_length)
165 min_length = min;
166
167 if (max < max_length)
168 max_length = max;
169
170 return 0;
171 }
172
173 if (!cond) {
174 err_msg = "Invalid condition: ";
175 err_msg.append(op);
176 dout(0) << "invalid condition: " << op << dendl;
177 return -EINVAL;
178 }
179
180 cond->set_vals(first, second);
181
182 conditions.push_back(cond);
183
184 return 0;
185}
186
187int RGWPolicy::check(RGWPolicyEnv *env, string& err_msg)
188{
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
194 }
195
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;
201 string val;
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);
206 return -EACCES;
207 }
208
209 set_var_checked(name);
210
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;
216 return -EACCES;
217 }
218 }
219
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)) {
224 return -EACCES;
225 }
226 }
227
228 if (!env->match_policy_vars(checked_vars, err_msg)) {
229 dout(1) << "missing policy condition" << dendl;
230 return -EACCES;
231 }
232 return 0;
233}
234
235
236int RGWPolicy::from_json(bufferlist& bl, string& err_msg)
237{
238 JSONParser parser;
239
240 if (!parser.parse(bl.c_str(), bl.length())) {
241 err_msg = "Malformed JSON";
242 dout(0) << "malformed json" << dendl;
243 return -EINVAL;
244 }
245
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");
248 if (iter.end()) {
249 err_msg = "Policy missing expiration";
250 dout(0) << "expiration not found" << dendl;
251 return -EINVAL; // change to a "no expiration" error following S3
252 }
253
254 JSONObj *obj = *iter;
255 expiration_str = obj->get_data();
256 int r = set_expires(expiration_str);
257 if (r < 0) {
258 err_msg = "Failed to parse policy expiration";
259 return r;
260 }
261
262 iter = parser.find_first("conditions");
263 if (iter.end()) {
264 err_msg = "Policy missing conditions";
265 dout(0) << "conditions not found" << dendl;
266 return -EINVAL; // change to a "no conditions" error following S3
267 }
268
269 obj = *iter;
270
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()) {
279 vector<string> v;
280 int i;
281 for (i = 0; !citer.end() && i < 3; ++citer, ++i) {
282 JSONObj *o = *citer;
283 v.push_back(o->get_data());
284 }
285 if (i != 3 || !citer.end()) { /* we expect exactly 3 arguments here */
286 err_msg = "Bad condition array, expecting 3 arguments";
287 return -EINVAL;
288 }
289
290 int r = add_condition(v[0], v[1], v[2], err_msg);
291 if (r < 0)
292 return r;
293 } else if (!citer.end()) {
294 JSONObj *c = *citer;
c07f9fc5 295 dout(20) << "adding simple_check: " << c->get_name() << " : " << c->get_data() << dendl;
7c673cae
FG
296
297 add_simple_check(c->get_name(), c->get_data());
298 } else {
299 return -EINVAL;
300 }
301 }
302 return 0;
303}