Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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
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 class RGWPolicyCondition {
15 protected:
16   string v1;
17   string v2;
18
19   virtual bool check(const string& first, const string& second, string& err_msg) = 0;
20
21 public:
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
51 class RGWPolicyCondition_StrEqual : public RGWPolicyCondition {
52 protected:
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
62 class RGWPolicyCondition_StrStartsWith : public RGWPolicyCondition {
63 protected:
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
73 void RGWPolicyEnv::add_var(const string& name, const string& value)
74 {
75   vars[name] = value;
76 }
77
78 bool 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
89 bool 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
103 bool 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
121 RGWPolicy::~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
130 int 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
141 int 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
187 int 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
236 int 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;
295       dout(20) << "adding simple_check: " << c->get_name() << " : " << c->get_data() << dendl;
296
297       add_simple_check(c->get_name(), c->get_data());
298     } else {
299       return -EINVAL;
300     }
301   }
302   return 0;
303 }