00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025
00026 #include <drizzled/plugin/authorization.h>
00027 #include <drizzled/module/option_map.h>
00028
00029 #include "policy.h"
00030
00031 #include <fstream>
00032
00033 namespace po= boost::program_options;
00034
00035 using namespace std;
00036 using namespace drizzled;
00037
00038 namespace regex_policy
00039 {
00040
00041 static int init(module::Context &context)
00042 {
00043 const module::option_map &vm= context.getOptions();
00044
00045 Policy *policy= new Policy(fs::path(vm["policy"].as<string>()));
00046 if (not policy->loadFile())
00047 {
00048 errmsg_printf(error::ERROR, _("Could not load regex policy file: %s\n"),
00049 (policy ? policy->getError().str().c_str() : _("Unknown")));
00050 delete policy;
00051 return 1;
00052 }
00053
00054 context.add(policy);
00055 context.registerVariable(new sys_var_const_string_val("policy", vm["policy"].as<string>()));
00056
00057 return 0;
00058 }
00059
00060 static void init_options(drizzled::module::option_context &context)
00061 {
00062 context("policy",
00063 po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()),
00064 N_("File to load for regex authorization policies"));
00065 }
00066
00067 bool Policy::loadFile()
00068 {
00069 ifstream file(policy_file.string().c_str());
00070 boost::regex comment_re;
00071 boost::regex empty_re;
00072 boost::regex table_matches_re;
00073 boost::regex process_matches_re;
00074 boost::regex schema_matches_re;
00075
00076 try
00077 {
00078 comment_re= comment_regex;
00079 empty_re= empty_regex;
00080 table_matches_re= table_match_regex;
00081 process_matches_re= process_match_regex;
00082 schema_matches_re= schema_match_regex;
00083 }
00084 catch (const std::exception &e)
00085 {
00086 error << e.what();
00087 return false;
00088 }
00089
00090 if (! file.is_open())
00091 {
00092 error << "Unable to open regex policy file: " << policy_file.string();
00093 return false;
00094 }
00095
00096 int lines= 0;
00097 try
00098 {
00099 while (! file.eof())
00100 {
00101 ++lines;
00102 string line;
00103 getline(file, line);
00104 if (boost::regex_match(line, comment_re))
00105 {
00106 continue;
00107 }
00108 if (boost::regex_match(line, empty_re))
00109 {
00110 continue;
00111 }
00112 boost::smatch matches;
00113 PolicyItemList *policies;
00114 if (boost::regex_match(line, matches, table_matches_re, boost::match_extra))
00115 {
00116 policies= &table_policies;
00117 }
00118 else if (boost::regex_match(line, matches, process_matches_re, boost::match_extra))
00119 {
00120 policies= &process_policies;
00121 }
00122 else if (boost::regex_match(line, matches, schema_matches_re, boost::match_extra))
00123 {
00124 policies= &schema_policies;
00125 }
00126 else
00127 {
00128 throw std::exception();
00129 }
00130 string user_regex;
00131 string object_regex;
00132 string action;
00133 user_regex= matches[MATCH_REGEX_USER_POS];
00134 object_regex= matches[MATCH_REGEX_OBJECT_POS];
00135 action= matches[MATCH_REGEX_ACTION_POS];
00136 PolicyItem *i;
00137 try
00138 {
00139 i= new PolicyItem(user_regex, object_regex, action);
00140 }
00141 catch (const std::exception &e)
00142 {
00143 error << "Bad policy item: user=" << user_regex << " object=" << object_regex << " action=" << action;
00144 throw std::exception();
00145 }
00146 policies->push_back(i);
00147 }
00148 return true;
00149 }
00150 catch (const std::exception &e)
00151 {
00152
00153 error << "Unable to parse line " << lines << " of policy file " << policy_file.string() << ":" << e.what();
00154 return false;
00155 }
00156 }
00157
00158 void clearPolicyItemList(PolicyItemList policies)
00159 {
00160 for (PolicyItemList::iterator x= policies.begin() ; x != policies.end() ; ++x)
00161 {
00162 delete *x;
00163 *x= NULL;
00164 }
00165 }
00166
00167 Policy::~Policy()
00168 {
00169 clearPolicyItemList(table_policies);
00170 clearPolicyItemList(process_policies);
00171 clearPolicyItemList(schema_policies);
00172 delete table_check_cache;
00173 delete process_check_cache;
00174 delete schema_check_cache;
00175 }
00176
00177 bool Policy::restrictObject(const drizzled::identifier::User &user_ctx,
00178 const string &obj, const PolicyItemList &policies,
00179 CheckMap **check_cache)
00180 {
00181 CheckItem c(user_ctx.username(), obj, check_cache);
00182 if (!c.hasCachedResult())
00183 {
00184 PolicyItemList::const_iterator m= find_if(policies.begin(), policies.end(), c);
00185 if (m != policies.end())
00186 {
00187 c.setCachedResult((*m)->isRestricted());
00188 }
00189 else
00190 {
00191
00192 c.setCachedResult(false);
00193 }
00194 }
00195 return c.getCachedResult();
00196 }
00197
00198 bool Policy::restrictSchema(const drizzled::identifier::User &user_ctx,
00199 const drizzled::identifier::Schema& schema)
00200 {
00201 return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, &schema_check_cache);
00202 }
00203
00204 bool Policy::restrictProcess(const drizzled::identifier::User &user_ctx,
00205 const drizzled::identifier::User &session_ctx)
00206 {
00207 return restrictObject(user_ctx, session_ctx.username(), process_policies, &process_check_cache);
00208 }
00209
00210 bool Policy::restrictTable(const drizzled::identifier::User& user_ctx,
00211 const drizzled::identifier::Table& table)
00212 {
00213 return restrictObject(user_ctx, table.getTableName(), table_policies, &table_check_cache);
00214 }
00215
00216 bool CheckItem::operator()(PolicyItem *p)
00217 {
00218 if (p->userMatches(user))
00219 {
00220 errmsg_printf(error::INSPECT, _("User %s matches regex\n"), user.c_str());
00221 if (p->objectMatches(object))
00222 {
00223 errmsg_printf(error::INSPECT, _("Object %s matches regex %s (%s)\n"),
00224 object.c_str(),
00225 p->getObject().c_str(),
00226 p->getAction());
00227 return true;
00228 }
00229 errmsg_printf(error::INSPECT, _("Object %s NOT restricted by regex %s (%s)\n"),
00230 object.c_str(),
00231 p->getObject().c_str(),
00232 p->getAction());
00233 }
00234 return false;
00235 }
00236
00237 CheckItem::CheckItem(const std::string &user_in, const std::string &obj_in, CheckMap **check_cache_in)
00238 : user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in)
00239 {
00240 CheckMap::iterator check_val;
00241 std::stringstream keystream;
00242 keystream << user << "_" << object;
00243 key= keystream.str();
00244
00245
00246 if ((*check_cache) && (check_val= (*check_cache)->find(key)) != (*check_cache)->end())
00247 {
00248 setCachedResult(check_val->second);
00249 }
00250 }
00251
00252 void CheckItem::setCachedResult(bool result)
00253 {
00254
00255 boost::mutex::scoped_lock lock(check_cache_mutex, boost::defer_lock);
00256 lock.lock();
00257
00258
00259 CheckMap* new_cache= *check_cache ? new CheckMap(**check_cache) : new CheckMap;
00260
00261
00262 (*new_cache)[key]= result;
00263
00264 CheckMap* old_cache= *check_cache;
00265 *check_cache= new_cache;
00266
00267 lock.unlock();
00268 has_cached_result= true;
00269 cached_result= result;
00270
00271 delete old_cache;
00272 }
00273
00274 }
00275
00276 DRIZZLE_PLUGIN(regex_policy::init, NULL, regex_policy::init_options);