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