1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Monty Taylor <mordred@inaugust.com>
5
* Copyright (C) 2011 Canonical, Ltd.
6
* Author: Clint Byrum <clint.byrum@canonical.com>
8
* Copied from simple_user_policy
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; version 2 of the License.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
#include <drizzled/plugin/authorization.h>
27
#include <drizzled/module/option_map.h>
33
namespace po= boost::program_options;
36
using namespace drizzled;
38
namespace regex_policy
41
static int init(module::Context &context)
43
const module::option_map &vm= context.getOptions();
45
Policy *policy= new Policy(fs::path(vm["policy"].as<string>()));
46
if (not policy->loadFile())
48
errmsg_printf(error::ERROR, _("Could not load regex policy file: %s\n"),
49
(policy ? policy->getError().str().c_str() : _("Unknown")));
55
context.registerVariable(new sys_var_const_string_val("policy", vm["policy"].as<string>()));
60
static void init_options(drizzled::module::option_context &context)
63
po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()),
64
N_("File to load for regex authorization policies"));
67
bool Policy::loadFile()
69
ifstream file(policy_file.string().c_str());
70
boost::regex comment_re;
71
boost::regex empty_re;
72
boost::regex table_matches_re;
73
boost::regex process_matches_re;
74
boost::regex schema_matches_re;
78
comment_re= comment_regex;
79
empty_re= empty_regex;
80
table_matches_re= table_match_regex;
81
process_matches_re= process_match_regex;
82
schema_matches_re= schema_match_regex;
84
catch (const std::exception &e)
92
error << "Unable to open regex policy file: " << policy_file.string();
104
if (boost::regex_match(line, comment_re))
108
if (boost::regex_match(line, empty_re))
112
boost::smatch matches;
113
PolicyItemList *policies;
114
if (boost::regex_match(line, matches, table_matches_re, boost::match_extra))
116
policies= &table_policies;
118
else if (boost::regex_match(line, matches, process_matches_re, boost::match_extra))
120
policies= &process_policies;
122
else if (boost::regex_match(line, matches, schema_matches_re, boost::match_extra))
124
policies= &schema_policies;
128
throw std::exception();
133
user_regex= matches[MATCH_REGEX_USER_POS];
134
object_regex= matches[MATCH_REGEX_OBJECT_POS];
135
action= matches[MATCH_REGEX_ACTION_POS];
139
i= new PolicyItem(user_regex, object_regex, action);
141
catch (const std::exception &e)
143
error << "Bad policy item: user=" << user_regex << " object=" << object_regex << " action=" << action;
144
throw std::exception();
146
policies->push_back(i);
150
catch (const std::exception &e)
152
/* On any non-EOF break, unparseable line */
153
error << "Unable to parse line " << lines << " of policy file " << policy_file.string() << ":" << e.what();
158
void clearPolicyItemList(PolicyItemList policies)
160
for (PolicyItemList::iterator x= policies.begin() ; x != policies.end() ; ++x)
169
clearPolicyItemList(table_policies);
170
clearPolicyItemList(process_policies);
171
clearPolicyItemList(schema_policies);
172
delete table_check_cache;
173
delete process_check_cache;
174
delete schema_check_cache;
177
bool Policy::restrictObject(const drizzled::identifier::User &user_ctx,
178
const string &obj, const PolicyItemList &policies,
179
CheckMap **check_cache)
181
CheckItem c(user_ctx.username(), obj, check_cache);
182
if (!c.hasCachedResult())
184
PolicyItemList::const_iterator m= find_if(policies.begin(), policies.end(), c);
185
if (m != policies.end())
187
c.setCachedResult((*m)->isRestricted());
191
/* TODO: make default action configurable */
192
c.setCachedResult(false);
195
return c.getCachedResult();
198
bool Policy::restrictSchema(const drizzled::identifier::User &user_ctx,
199
const drizzled::identifier::Schema& schema)
201
return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, &schema_check_cache);
204
bool Policy::restrictProcess(const drizzled::identifier::User &user_ctx,
205
const drizzled::identifier::User &session_ctx)
207
return restrictObject(user_ctx, session_ctx.username(), process_policies, &process_check_cache);
210
bool Policy::restrictTable(const drizzled::identifier::User& user_ctx,
211
const drizzled::identifier::Table& table)
213
return restrictObject(user_ctx, table.getTableName(), table_policies, &table_check_cache);
216
bool CheckItem::operator()(PolicyItem *p)
218
if (p->userMatches(user))
220
errmsg_printf(error::INSPECT, _("User %s matches regex\n"), user.c_str());
221
if (p->objectMatches(object))
223
errmsg_printf(error::INSPECT, _("Object %s matches regex %s (%s)\n"),
225
p->getObject().c_str(),
229
errmsg_printf(error::INSPECT, _("Object %s NOT restricted by regex %s (%s)\n"),
231
p->getObject().c_str(),
237
CheckItem::CheckItem(const std::string &user_in, const std::string &obj_in, CheckMap **check_cache_in)
238
: user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in)
240
CheckMap::iterator check_val;
241
std::stringstream keystream;
242
keystream << user << "_" << object;
243
key= keystream.str();
245
/* using RCU to only need to lock when updating the cache */
246
if ((*check_cache) && (check_val= (*check_cache)->find(key)) != (*check_cache)->end())
248
setCachedResult(check_val->second);
252
void CheckItem::setCachedResult(bool result)
254
// TODO: make the mutex per-cache
255
boost::mutex::scoped_lock lock(check_cache_mutex, boost::defer_lock);
258
// Copy the current one
259
CheckMap* new_cache= *check_cache ? new CheckMap(**check_cache) : new CheckMap;
262
(*new_cache)[key]= result;
264
CheckMap* old_cache= *check_cache;
265
*check_cache= new_cache;
268
has_cached_result= true;
269
cached_result= result;
274
} /* namespace regex_policy */
276
DRIZZLE_PLUGIN(regex_policy::init, NULL, regex_policy::init_options);