26 #include <boost/unordered_set.hpp>
27 #include <boost/thread/locks.hpp>
29 #include <drizzled/plugin/authorization.h>
36 namespace po= boost::program_options;
39 using namespace drizzled;
41 namespace regex_policy
44 uint64_t max_cache_buckets= DEFAULT_MAX_CACHE_BUCKETS;
45 uint64_t max_lru_length= DEFAULT_MAX_LRU_LENGTH;
51 max_cache_buckets= vm[
"max-cache-buckets"].as<uint64_t>();
52 if (max_cache_buckets < 1)
54 errmsg_printf(error::ERROR, _(
"max-cache-buckets is too low, must be greater than 0"));
57 max_lru_length= vm[
"max-lru-length"].as<uint64_t>();
58 if (max_lru_length < 1)
60 errmsg_printf(error::ERROR, _(
"max-lru-length is too low, must be greater than 0"));
63 Policy *policy=
new Policy(fs::path(vm[
"policy"].as<string>()));
64 if (not policy->loadFile())
66 errmsg_printf(error::ERROR, _(
"Could not load regex policy file: %s\n"),
67 (policy ? policy->getError().str().c_str() : _(
"Unknown")));
81 po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()),
82 N_(
"File to load for regex authorization policies"));
83 context(
"max-cache-buckets",
84 po::value<uint64_t>()->default_value(DEFAULT_MAX_CACHE_BUCKETS),
85 N_(
"Maximum buckets for authorization cache"));
86 context(
"max-lru-length",
87 po::value<uint64_t>()->default_value(DEFAULT_MAX_LRU_LENGTH),
88 N_(
"Maximum number of LRU entries to track at once"));
91 bool Policy::loadFile()
93 ifstream file(policy_file.string().c_str());
94 boost::regex comment_re;
95 boost::regex empty_re;
96 boost::regex table_matches_re;
97 boost::regex process_matches_re;
98 boost::regex schema_matches_re;
102 comment_re= comment_regex;
103 empty_re= empty_regex;
104 table_matches_re= table_match_regex;
105 process_matches_re= process_match_regex;
106 schema_matches_re= schema_match_regex;
108 catch (
const std::exception &e)
114 if (! file.is_open())
116 error <<
"Unable to open regex policy file: " << policy_file.string();
128 if (boost::regex_match(line, comment_re))
132 if (boost::regex_match(line, empty_re))
136 boost::smatch matches;
137 PolicyItemList *policies;
138 if (boost::regex_match(line, matches, table_matches_re, boost::match_extra))
140 policies= &table_policies;
142 else if (boost::regex_match(line, matches, process_matches_re, boost::match_extra))
144 policies= &process_policies;
146 else if (boost::regex_match(line, matches, schema_matches_re, boost::match_extra))
148 policies= &schema_policies;
152 throw std::exception();
157 user_regex= matches[MATCH_REGEX_USER_POS];
158 object_regex= matches[MATCH_REGEX_OBJECT_POS];
159 action= matches[MATCH_REGEX_ACTION_POS];
163 i=
new PolicyItem(user_regex, object_regex, action);
165 catch (
const std::exception &e)
167 error <<
"Bad policy item: user=" << user_regex <<
" object=" << object_regex <<
" action=" << action;
168 throw std::exception();
170 policies->push_back(i);
174 catch (
const std::exception &e)
177 error <<
"Unable to parse line " << lines <<
" of policy file " << policy_file.string() <<
":" << e.what();
182 void clearPolicyItemList(PolicyItemList policies)
184 for (PolicyItemList::iterator x= policies.begin() ; x != policies.end() ; ++x)
193 clearPolicyItemList(table_policies);
194 clearPolicyItemList(process_policies);
195 clearPolicyItemList(schema_policies);
199 const string &obj,
const PolicyItemList &policies,
200 CheckMap &check_cache)
202 CheckItem c(user_ctx.username(), obj, check_cache);
203 if (!c.hasCachedResult())
205 PolicyItemList::const_iterator m= find_if(policies.begin(), policies.end(), c);
206 if (m != policies.end())
208 c.setCachedResult((*m)->isRestricted());
213 c.setCachedResult(
false);
216 return c.getCachedResult();
222 return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, schema_check_cache);
228 return restrictObject(user_ctx, session_ctx.username(), process_policies, process_check_cache);
234 return restrictObject(user_ctx, table.getTableName(), table_policies, table_check_cache);
239 if (p->userMatches(user))
241 errmsg_printf(error::INSPECT, _(
"User %s matches regex\n"), user.c_str());
242 if (p->objectMatches(
object))
244 errmsg_printf(error::INSPECT, _(
"Object %s matches regex %s (%s)\n"),
246 p->getObject().c_str(),
250 errmsg_printf(error::INSPECT, _(
"Object %s NOT restricted by regex %s (%s)\n"),
252 p->getObject().c_str(),
258 CheckItem::CheckItem(
const std::string &user_in,
const std::string &obj_in, CheckMap &check_cache_in)
259 : user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in)
261 UnorderedCheckMap::iterator check_val;
262 key= user +
"_" + object;
264 if ((check_val= check_cache.find(key)) != check_cache.end())
267 cached_result= check_val->second;
268 has_cached_result=
true;
272 UnorderedCheckMap::iterator CheckMap::find(std::string
const &k)
275 boost::mutex::scoped_lock lock(lru_mutex);
277 if (lru.size() > max_lru_length)
280 uint64_t size_halfway= lru.size() / 2;
281 LruList::iterator halfway= lru.begin();
282 halfway += size_halfway;
283 boost::unordered_set<std::string> uniqs;
284 uniqs.insert(lru.begin(), halfway);
287 if (size_halfway < uniqs.size())
289 lru.erase(lru.begin(), halfway);
292 lru.insert(lru.begin(), uniqs.begin(), uniqs.end());
296 boost::shared_lock<boost::shared_mutex> map_lock(map_mutex);
300 void CheckMap::insert(std::string
const &k,
bool v)
302 boost::unique_lock<boost::shared_mutex> map_lock(map_mutex);
306 if (map.bucket_count() > max_cache_buckets)
309 boost::unordered_set<std::string> found;
312 boost::mutex::scoped_lock lock(lru_mutex);
313 for (LruList::reverse_iterator x= lru.rbegin(); x < lru.rend(); ++x)
315 if (found.find(*x) == found.end())
318 if (found.size() >= max_cache_buckets)
330 if (map.bucket_count() > max_cache_buckets)
336 map.erase(*(lru.begin()));
341 errmsg_printf(error::WARN,
342 _(
"Unable to reduce size of cache below max buckets (current buckets=%" PRIu64
")"),
343 static_cast<uint64_t>(map.bucket_count()));
351 void CheckItem::setCachedResult(
bool result)
353 check_cache.insert(key, result);
354 has_cached_result=
true;
355 cached_result= result;
360 DRIZZLE_DECLARE_PLUGIN
366 N_(
"Authorization using a regex-matched policy file"),
370 regex_policy::init_options
372 DRIZZLE_DECLARE_PLUGIN_END;