26 #include <boost/foreach.hpp>
27 #include <boost/unordered_set.hpp>
28 #include <boost/thread/locks.hpp>
30 #include <drizzled/item.h>
31 #include <drizzled/plugin/authorization.h>
38 namespace po= boost::program_options;
46 uint64_t max_cache_buckets= DEFAULT_MAX_CACHE_BUCKETS;
47 uint64_t max_lru_length= DEFAULT_MAX_LRU_LENGTH;
49 bool parsePolicyFile(std::string, PolicyItemList&, PolicyItemList&, PolicyItemList&);
56 std::string newPolicyFile(var->value->
str_value.data());
57 if (policy->setPolicyFile(newPolicyFile))
62 errmsg_printf(error::ERROR, _(
"regex_policy file cannot be NULL"));
66 bool parsePolicyFile(std::string new_policy_file, PolicyItemList& table_policies_dummy, PolicyItemList& schema_policies_dummy, PolicyItemList& process_policies_dummy)
68 ifstream file(new_policy_file.c_str());
69 boost::regex comment_re;
70 boost::regex empty_re;
71 boost::regex table_matches_re;
72 boost::regex process_matches_re;
73 boost::regex schema_matches_re;
74 table_policies_dummy.clear();
75 schema_policies_dummy.clear();
76 process_policies_dummy.clear();
80 comment_re= comment_regex;
81 empty_re= empty_regex;
82 table_matches_re= table_match_regex;
83 process_matches_re= process_match_regex;
84 schema_matches_re= schema_match_regex;
86 catch (
const std::exception &e)
88 errmsg_printf(error::ERROR,
"%s", _(e.what()));
94 string error_msg=
"Unable to open regex policy file: " + new_policy_file;
95 errmsg_printf(error::ERROR,
"%s", _(error_msg.c_str()));
102 for (
string line; getline(file, line); )
105 if (boost::regex_match(line, comment_re))
109 if (boost::regex_match(line, empty_re))
113 boost::smatch matches;
114 PolicyItemList *policies;
115 if (boost::regex_match(line, matches, table_matches_re, boost::match_extra))
117 policies= &table_policies_dummy;
119 else if (boost::regex_match(line, matches, process_matches_re, boost::match_extra))
121 policies= &process_policies_dummy;
123 else if (boost::regex_match(line, matches, schema_matches_re, boost::match_extra))
125 policies= &schema_policies_dummy;
129 throw std::exception();
131 string user_regex= matches[MATCH_REGEX_USER_POS];
132 string object_regex= matches[MATCH_REGEX_OBJECT_POS];
133 string action= matches[MATCH_REGEX_ACTION_POS];
136 policies->push_back(
new PolicyItem(user_regex, object_regex, action));
138 catch (
const std::exception &e)
140 string error_msg=
"Bad policy item: user=" + user_regex +
" object=" + object_regex +
" action=" + action;
141 errmsg_printf(error::ERROR,
"%s", _(error_msg.c_str()));
142 throw std::exception();
147 catch (
const std::exception &e)
150 string error_msg=
"Unable to parse policy file " + new_policy_file +
":" + e.what();
151 errmsg_printf(error::ERROR,
"%s", _(error_msg.c_str()));
161 max_cache_buckets= vm[
"max-cache-buckets"].as<uint64_t>();
162 if (max_cache_buckets < 1)
164 errmsg_printf(error::ERROR, _(
"max-cache-buckets is too low, must be greater than 0"));
167 max_lru_length= vm[
"max-lru-length"].as<uint64_t>();
168 if (max_lru_length < 1)
170 errmsg_printf(error::ERROR, _(
"max-lru-length is too low, must be greater than 0"));
173 policy=
new Policy(vm[
"policy"].as<string>());
174 if (!policy->setPolicyFile(policy->getPolicyFile()))
176 errmsg_printf(error::ERROR, _(
"Could not load regex policy file: %s\n"),
177 (policy ? policy->getError().str().c_str() : _(
"Unknown")));
182 context.registerVariable(
new sys_var_std_string(
"policy", policy->getPolicyFile(), NULL, &updatePolicyFile));
190 po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()),
191 N_(
"File to load for regex authorization policies"));
192 context(
"max-cache-buckets",
193 po::value<uint64_t>()->default_value(DEFAULT_MAX_CACHE_BUCKETS),
194 N_(
"Maximum buckets for authorization cache"));
195 context(
"max-lru-length",
196 po::value<uint64_t>()->default_value(DEFAULT_MAX_LRU_LENGTH),
197 N_(
"Maximum number of LRU entries to track at once"));
200 void Policy::setPolicies(PolicyItemList new_table_policies, PolicyItemList new_schema_policies, PolicyItemList new_process_policies)
202 policy->clearPolicies();
204 for (PolicyItemList::iterator it= new_table_policies.begin(); it!= new_table_policies.end(); it++)
205 table_policies.push_back(*it);
207 for (PolicyItemList::iterator it= new_schema_policies.begin(); it!= new_schema_policies.end(); it++)
208 schema_policies.push_back(*it);
210 for (PolicyItemList::iterator it= new_process_policies.begin(); it!= new_process_policies.end(); it++)
211 process_policies.push_back(*it);
214 std::string& Policy::getPolicyFile()
216 return sysvar_policy_file;
219 bool Policy::setPolicyFile(std::string &new_policy_file)
221 if (new_policy_file.empty())
223 errmsg_printf(error::ERROR, _(
"regex_policy file cannot be an empty string"));
227 PolicyItemList new_table_policies;
228 PolicyItemList new_schema_policies;
229 PolicyItemList new_process_policies;
230 if(parsePolicyFile(new_policy_file, new_table_policies, new_schema_policies, new_process_policies))
232 policy->setPolicies(new_table_policies, new_schema_policies, new_process_policies);
233 sysvar_policy_file= new_policy_file;
234 fs::path newPolicyFile(getPolicyFile());
235 policy_file= newPolicyFile;
241 static void clearPolicyItemList(PolicyItemList& policies)
243 BOOST_FOREACH(PolicyItem* x, policies)
251 clearPolicyItemList(table_policies);
252 clearPolicyItemList(process_policies);
253 clearPolicyItemList(schema_policies);
260 void Policy::clearPolicies()
262 table_policies.clear();
263 process_policies.clear();
264 schema_policies.clear();
265 table_check_cache.clear();
266 process_check_cache.clear();
267 schema_check_cache.clear();
272 const string &obj,
const PolicyItemList &policies,
273 CheckMap &check_cache)
275 CheckItem c(user_ctx.username(), obj, check_cache);
276 if (!c.hasCachedResult())
278 PolicyItemList::const_iterator m= find_if(policies.begin(), policies.end(), c);
279 if (m != policies.end())
281 c.setCachedResult((*m)->isRestricted());
286 c.setCachedResult(
false);
289 return c.getCachedResult();
295 return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, schema_check_cache);
301 return restrictObject(user_ctx, session_ctx.username(), process_policies, process_check_cache);
307 return restrictObject(user_ctx, table.getTableName(), table_policies, table_check_cache);
312 if (p->userMatches(user))
314 errmsg_printf(error::INSPECT, _(
"User %s matches regex\n"), user.c_str());
315 if (p->objectMatches(
object))
317 errmsg_printf(error::INSPECT, _(
"Object %s matches regex %s (%s)\n"),
319 p->getObject().c_str(),
323 errmsg_printf(error::INSPECT, _(
"Object %s NOT restricted by regex %s (%s)\n"),
325 p->getObject().c_str(),
331 CheckItem::CheckItem(
const std::string &user_in,
const std::string &obj_in, CheckMap &check_cache_in)
332 : user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in)
334 key= user +
"_" + object;
336 if (
bool* check_val= check_cache.find(key))
339 cached_result= *check_val;
340 has_cached_result=
true;
344 bool* CheckMap::find(std::string
const &k)
347 boost::mutex::scoped_lock lock(lru_mutex);
349 if (lru.size() > max_lru_length)
352 uint64_t size_halfway= lru.size() / 2;
353 LruList::iterator halfway= lru.begin();
354 halfway += size_halfway;
355 boost::unordered_set<std::string> uniqs;
356 uniqs.insert(lru.begin(), halfway);
359 if (size_halfway < uniqs.size())
361 lru.erase(lru.begin(), halfway);
364 lru.insert(lru.begin(), uniqs.begin(), uniqs.end());
368 boost::shared_lock<boost::shared_mutex> map_lock(map_mutex);
369 return find_ptr(map, k);
372 void CheckMap::insert(std::string
const &k,
bool v)
374 boost::unique_lock<boost::shared_mutex> map_lock(map_mutex);
378 if (map.bucket_count() > max_cache_buckets)
381 boost::unordered_set<std::string> found;
384 boost::mutex::scoped_lock lock(lru_mutex);
385 for (LruList::reverse_iterator x= lru.rbegin(); x < lru.rend(); ++x)
387 if (found.find(*x) == found.end())
390 if (found.size() >= max_cache_buckets)
402 if (map.bucket_count() > max_cache_buckets)
408 map.erase(*(lru.begin()));
413 errmsg_printf(error::WARN,
414 _(
"Unable to reduce size of cache below max buckets (current buckets=%" PRIu64
")"),
415 static_cast<uint64_t>(map.bucket_count()));
423 void CheckItem::setCachedResult(
bool result)
425 check_cache.insert(key, result);
426 has_cached_result=
true;
427 cached_result= result;
432 DRIZZLE_DECLARE_PLUGIN
438 N_(
"Authorization using a regex-matched policy file"),
442 regex_policy::init_options
444 DRIZZLE_DECLARE_PLUGIN_END;
A set of Session members describing the current authenticated user.
TODO: Rename this file - func.h is stupid.
An Proxy Wrapper around boost::program_options::variables_map.