]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_policy_s3.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rgw / rgw_policy_s3.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
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
14 using namespace std;
15
16 class RGWPolicyCondition {
17 protected:
18 string v1;
19 string v2;
20
21 virtual bool check(const string& first, const string& second, string& err_msg) = 0;
22
23 public:
24 virtual ~RGWPolicyCondition() {}
25
26 void set_vals(const string& _v1, const string& _v2) {
27 v1 = _v1;
28 v2 = _v2;
29 }
30
31 bool check(RGWPolicyEnv *env, map<string, bool, ltstr_nocase>& checked_vars, string& err_msg) {
32 string first, second;
33 env->get_value(v1, first, checked_vars);
34 env->get_value(v2, second, checked_vars);
35 dout(1) << "policy condition check " << v1 << " ["
36 << rgw::crypt_sanitize::s3_policy{v1, first}
37 << "] " << v2 << " ["
38 << rgw::crypt_sanitize::s3_policy{v2, second}
39 << "]" << dendl;
40 bool ret = check(first, second, err_msg);
41 if (!ret) {
42 err_msg.append(": ");
43 err_msg.append(v1);
44 err_msg.append(", ");
45 err_msg.append(v2);
46 }
47 return ret;
48 }
49
50 };
51
52
53 class RGWPolicyCondition_StrEqual : public RGWPolicyCondition {
54 protected:
55 bool check(const string& first, const string& second, string& msg) override {
56 bool ret = first.compare(second) == 0;
57 if (!ret) {
58 msg = "Policy condition failed: eq";
59 }
60 return ret;
61 }
62 };
63
64 class RGWPolicyCondition_StrStartsWith : public RGWPolicyCondition {
65 protected:
66 bool check(const string& first, const string& second, string& msg) override {
67 bool ret = first.compare(0, second.size(), second) == 0;
68 if (!ret) {
69 msg = "Policy condition failed: starts-with";
70 }
71 return ret;
72 }
73 };
74
75 void RGWPolicyEnv::add_var(const string& name, const string& value)
76 {
77 vars[name] = value;
78 }
79
80 bool RGWPolicyEnv::get_var(const string& name, string& val)
81 {
82 map<string, string, ltstr_nocase>::iterator iter = vars.find(name);
83 if (iter == vars.end())
84 return false;
85
86 val = iter->second;
87
88 return true;
89 }
90
91 bool RGWPolicyEnv::get_value(const string& s, string& val, map<string, bool, ltstr_nocase>& checked_vars)
92 {
93 if (s.empty() || s[0] != '$') {
94 val = s;
95 return true;
96 }
97
98 const string& var = s.substr(1);
99 checked_vars[var] = true;
100
101 return get_var(var, val);
102 }
103
104
105 bool RGWPolicyEnv::match_policy_vars(map<string, bool, ltstr_nocase>& policy_vars, string& err_msg)
106 {
107 map<string, string, ltstr_nocase>::iterator iter;
108 string ignore_prefix = "x-ignore-";
109 for (iter = vars.begin(); iter != vars.end(); ++iter) {
110 const string& var = iter->first;
111 if (strncasecmp(ignore_prefix.c_str(), var.c_str(), ignore_prefix.size()) == 0)
112 continue;
113 if (policy_vars.count(var) == 0) {
114 err_msg = "Policy missing condition: ";
115 err_msg.append(iter->first);
116 dout(1) << "env var missing in policy: " << iter->first << dendl;
117 return false;
118 }
119 }
120 return true;
121 }
122
123 RGWPolicy::~RGWPolicy()
124 {
125 list<RGWPolicyCondition *>::iterator citer;
126 for (citer = conditions.begin(); citer != conditions.end(); ++citer) {
127 RGWPolicyCondition *cond = *citer;
128 delete cond;
129 }
130 }
131
132 int RGWPolicy::set_expires(const string& e)
133 {
134 struct tm t;
135 if (!parse_iso8601(e.c_str(), &t))
136 return -EINVAL;
137
138 expires = internal_timegm(&t);
139
140 return 0;
141 }
142
143 int RGWPolicy::add_condition(const string& op, const string& first, const string& second, string& err_msg)
144 {
145 RGWPolicyCondition *cond = NULL;
146 if (stringcasecmp(op, "eq") == 0) {
147 cond = new RGWPolicyCondition_StrEqual;
148 } else if (stringcasecmp(op, "starts-with") == 0) {
149 cond = new RGWPolicyCondition_StrStartsWith;
150 } else if (stringcasecmp(op, "content-length-range") == 0) {
151 off_t min, max;
152 int r = stringtoll(first, &min);
153 if (r < 0) {
154 err_msg = "Bad content-length-range param";
155 dout(0) << "bad content-length-range param: " << first << dendl;
156 return r;
157 }
158
159 r = stringtoll(second, &max);
160 if (r < 0) {
161 err_msg = "Bad content-length-range param";
162 dout(0) << "bad content-length-range param: " << second << dendl;
163 return r;
164 }
165
166 if (min > min_length)
167 min_length = min;
168
169 if (max < max_length)
170 max_length = max;
171
172 return 0;
173 }
174
175 if (!cond) {
176 err_msg = "Invalid condition: ";
177 err_msg.append(op);
178 dout(0) << "invalid condition: " << op << dendl;
179 return -EINVAL;
180 }
181
182 cond->set_vals(first, second);
183
184 conditions.push_back(cond);
185
186 return 0;
187 }
188
189 int RGWPolicy::check(RGWPolicyEnv *env, string& err_msg)
190 {
191 uint64_t now = ceph_clock_now().sec();
192 if (expires <= now) {
193 dout(0) << "NOTICE: policy calculated as expired: " << expiration_str << dendl;
194 err_msg = "Policy expired";
195 return -EACCES; // change to condition about expired policy following S3
196 }
197
198 list<pair<string, string> >::iterator viter;
199 for (viter = var_checks.begin(); viter != var_checks.end(); ++viter) {
200 pair<string, string>& p = *viter;
201 const string& name = p.first;
202 const string& check_val = p.second;
203 string val;
204 if (!env->get_var(name, val)) {
205 dout(20) << " policy check failed, variable not found: '" << name << "'" << dendl;
206 err_msg = "Policy check failed, variable not found: ";
207 err_msg.append(name);
208 return -EACCES;
209 }
210
211 set_var_checked(name);
212
213 dout(20) << "comparing " << name << " [" << val << "], " << check_val << dendl;
214 if (val.compare(check_val) != 0) {
215 err_msg = "Policy check failed, variable not met condition: ";
216 err_msg.append(name);
217 dout(1) << "policy check failed, val=" << val << " != " << check_val << dendl;
218 return -EACCES;
219 }
220 }
221
222 list<RGWPolicyCondition *>::iterator citer;
223 for (citer = conditions.begin(); citer != conditions.end(); ++citer) {
224 RGWPolicyCondition *cond = *citer;
225 if (!cond->check(env, checked_vars, err_msg)) {
226 return -EACCES;
227 }
228 }
229
230 if (!env->match_policy_vars(checked_vars, err_msg)) {
231 dout(1) << "missing policy condition" << dendl;
232 return -EACCES;
233 }
234 return 0;
235 }
236
237
238 int RGWPolicy::from_json(bufferlist& bl, string& err_msg)
239 {
240 JSONParser parser;
241
242 if (!parser.parse(bl.c_str(), bl.length())) {
243 err_msg = "Malformed JSON";
244 dout(0) << "malformed json" << dendl;
245 return -EINVAL;
246 }
247
248 // as no time was included in the request, we hope that the user has included a short timeout
249 JSONObjIter iter = parser.find_first("expiration");
250 if (iter.end()) {
251 err_msg = "Policy missing expiration";
252 dout(0) << "expiration not found" << dendl;
253 return -EINVAL; // change to a "no expiration" error following S3
254 }
255
256 JSONObj *obj = *iter;
257 expiration_str = obj->get_data();
258 int r = set_expires(expiration_str);
259 if (r < 0) {
260 err_msg = "Failed to parse policy expiration";
261 return r;
262 }
263
264 iter = parser.find_first("conditions");
265 if (iter.end()) {
266 err_msg = "Policy missing conditions";
267 dout(0) << "conditions not found" << dendl;
268 return -EINVAL; // change to a "no conditions" error following S3
269 }
270
271 obj = *iter;
272
273 iter = obj->find_first();
274 for (; !iter.end(); ++iter) {
275 JSONObj *child = *iter;
276 dout(20) << "data=" << child->get_data() << dendl;
277 dout(20) << "is_object=" << child->is_object() << dendl;
278 dout(20) << "is_array=" << child->is_array() << dendl;
279 JSONObjIter citer = child->find_first();
280 if (child->is_array()) {
281 vector<string> v;
282 int i;
283 for (i = 0; !citer.end() && i < 3; ++citer, ++i) {
284 JSONObj *o = *citer;
285 v.push_back(o->get_data());
286 }
287 if (i != 3 || !citer.end()) { /* we expect exactly 3 arguments here */
288 err_msg = "Bad condition array, expecting 3 arguments";
289 return -EINVAL;
290 }
291
292 int r = add_condition(v[0], v[1], v[2], err_msg);
293 if (r < 0)
294 return r;
295 } else if (!citer.end()) {
296 JSONObj *c = *citer;
297 dout(20) << "adding simple_check: " << c->get_name() << " : " << c->get_data() << dendl;
298
299 add_simple_check(c->get_name(), c->get_data());
300 } else {
301 return -EINVAL;
302 }
303 }
304 return 0;
305 }