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>
31
namespace po= boost::program_options;
34
using namespace drizzled;
36
namespace regex_policy
39
static int init(module::Context &context)
41
const module::option_map &vm= context.getOptions();
43
Policy *policy= new (nothrow) Policy(fs::path(vm["policy"].as<string>()));
44
if (policy == NULL or not policy->loadFile())
46
errmsg_printf(error::ERROR, _("Could not load regex policy file: %s\n"),
47
(policy ? policy->getError().str().c_str() : _("Unknown")));
56
context.registerVariable(new sys_var_const_string_val("policy", vm["policy"].as<string>()));
61
static void init_options(drizzled::module::option_context &context)
64
po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()),
65
N_("File to load for regex authorization policies"));
68
bool Policy::loadFile()
70
ifstream file(policy_file.string().c_str());
71
boost::regex comment_re;
72
boost::regex empty_re;
73
boost::regex table_matches_re;
74
boost::regex process_matches_re;
75
boost::regex schema_matches_re;
79
comment_re= comment_regex;
80
empty_re= empty_regex;
81
table_matches_re= table_match_regex;
82
process_matches_re= process_match_regex;
83
schema_matches_re= schema_match_regex;
85
catch (const std::exception &e)
93
error << "Unable to open regex policy file: " << policy_file.string();
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;
119
else if (boost::regex_match(line, matches, process_matches_re, boost::match_extra))
121
policies= &process_policies;
123
else if (boost::regex_match(line, matches, schema_matches_re, boost::match_extra))
125
policies= &schema_policies;
129
throw std::exception();
134
user_regex= matches[MATCH_REGEX_USER_POS];
135
object_regex= matches[MATCH_REGEX_OBJECT_POS];
136
action= matches[MATCH_REGEX_ACTION_POS];
140
i= new PolicyItem(user_regex, object_regex, action);
142
catch (const std::exception &e)
144
error << "Bad policy item: user=" << user_regex << " object=" << object_regex << " action=" << action;
145
throw std::exception();
147
policies->push_back(i);
151
catch (const std::exception &e)
153
/* On any non-EOF break, unparseable line */
154
error << "Unable to parse line " << lines << " of policy file " << policy_file.string() << ":" << e.what();
159
void clearPolicyItemList(PolicyItemList policies)
161
for (PolicyItemList::iterator x= policies.begin() ; x != policies.end() ; ++x)
170
clearPolicyItemList(table_policies);
171
clearPolicyItemList(process_policies);
172
clearPolicyItemList(schema_policies);
173
delete table_check_cache;
174
delete process_check_cache;
175
delete schema_check_cache;
178
bool Policy::restrictObject(const drizzled::identifier::User &user_ctx,
179
const string &obj, const PolicyItemList &policies,
180
CheckMap **check_cache)
182
CheckItem c(user_ctx.username(), obj, check_cache);
183
if (!c.hasCachedResult())
185
PolicyItemList::const_iterator m= find_if(policies.begin(), policies.end(), c);
186
if (m != policies.end())
188
c.setCachedResult((*m)->isRestricted());
192
/* TODO: make default action configurable */
193
c.setCachedResult(false);
196
return c.getCachedResult();
199
bool Policy::restrictSchema(const drizzled::identifier::User &user_ctx,
200
drizzled::identifier::Schema::const_reference schema)
202
return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, &schema_check_cache);
205
bool Policy::restrictProcess(const drizzled::identifier::User &user_ctx,
206
const drizzled::identifier::User &session_ctx)
208
return restrictObject(user_ctx, session_ctx.username(), process_policies, &process_check_cache);
211
bool Policy::restrictTable(drizzled::identifier::User::const_reference user_ctx,
212
drizzled::identifier::Table::const_reference table)
214
return restrictObject(user_ctx, table.getTableName(), table_policies, &table_check_cache);
217
bool CheckItem::operator()(PolicyItem *p)
219
if (p->userMatches(user))
221
errmsg_printf(error::INSPECT, _("User %s matches regex\n"), user.c_str());
222
if (p->objectMatches(object))
224
errmsg_printf(error::INSPECT, _("Object %s matches regex %s (%s)\n"),
226
p->getObject().c_str(),
230
errmsg_printf(error::INSPECT, _("Object %s NOT restricted by regex %s (%s)\n"),
232
p->getObject().c_str(),
238
CheckItem::CheckItem(const std::string &user_in, const std::string &obj_in, CheckMap **check_cache_in)
239
: user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in)
241
CheckMap::iterator check_val;
242
std::stringstream keystream;
243
keystream << user << "_" << object;
244
key= keystream.str();
246
/* using RCU to only need to lock when updating the cache */
247
if ((*check_cache) && (check_val= (*check_cache)->find(key)) != (*check_cache)->end())
249
setCachedResult(check_val->second);
253
void CheckItem::setCachedResult(bool result)
255
// TODO: make the mutex per-cache
258
boost::mutex::scoped_lock lock(check_cache_mutex, boost::defer_lock);
261
// Copy the current one
264
new_cache= new CheckMap(**check_cache);
268
new_cache= new CheckMap();
272
(*new_cache)[key]= result;
274
old_cache= *check_cache;
275
*check_cache= new_cache;
278
has_cached_result= true;
279
cached_result= result;
287
} /* namespace regex_policy */
289
DRIZZLE_PLUGIN(regex_policy::init, NULL, regex_policy::init_options);