~drizzle-trunk/drizzle/development

2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
4
 *  Copyright (C) 2010 Monty Taylor <mordred@inaugust.com>
5
 *  Copyright (C) 2011 Canonical, Ltd.
6
 *  Author: Clint Byrum <clint.byrum@canonical.com>
7
 *
8
 *  Copied from simple_user_policy
9
 *
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.
13
 *
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.
18
 *
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
22
 */
23
24
#include <config.h>
25
26
#include <drizzled/plugin/authorization.h>
27
#include <drizzled/module/option_map.h>
28
29
#include "policy.h"
30
31
namespace po= boost::program_options;
32
33
using namespace std;
34
using namespace drizzled;
35
36
namespace regex_policy
37
{
38
39
static int init(module::Context &context)
40
{
41
  const module::option_map &vm= context.getOptions();
42
2246.3.1 by Olaf van der Spek
Remove std::nothrow from new()
43
  Policy *policy= new Policy(fs::path(vm["policy"].as<string>()));
44
  if (not policy->loadFile())
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
45
  {
46
    errmsg_printf(error::ERROR, _("Could not load regex policy file: %s\n"),
47
                  (policy ? policy->getError().str().c_str() : _("Unknown")));
2246.3.1 by Olaf van der Spek
Remove std::nothrow from new()
48
    delete policy;
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
49
    return 1;
50
  }
51
52
  context.add(policy);
53
  context.registerVariable(new sys_var_const_string_val("policy", vm["policy"].as<string>()));
54
55
  return 0;
56
}
57
58
static void init_options(drizzled::module::option_context &context)
59
{
60
  context("policy",
61
      po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()),
62
      N_("File to load for regex authorization policies"));
63
}
64
65
bool Policy::loadFile()
66
{
67
  ifstream file(policy_file.string().c_str());
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
68
  boost::regex comment_re;
69
  boost::regex empty_re;
70
  boost::regex table_matches_re;
71
  boost::regex process_matches_re;
72
  boost::regex schema_matches_re;
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
73
74
  try
75
  {
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
76
    comment_re= comment_regex;
77
    empty_re= empty_regex;
78
    table_matches_re= table_match_regex;
79
    process_matches_re= process_match_regex;
80
    schema_matches_re= schema_match_regex;
81
  }   
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
82
  catch (const std::exception &e)
83
  {
84
    error << e.what();
85
    return false;
86
  }
87
88
  if (! file.is_open())
89
  {
90
    error << "Unable to open regex policy file: " << policy_file.string();
91
    return false;
92
  }
93
94
  int lines= 0;
95
  try
96
  {
97
    while (! file.eof())
98
    {
99
      ++lines;
100
      string line;
101
      getline(file, line);
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
102
      if (boost::regex_match(line, comment_re))
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
103
      {
104
        continue;
105
      }
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
106
      if (boost::regex_match(line, empty_re))
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
107
      {
108
        continue;
109
      }
110
      boost::smatch matches;
111
      PolicyItemList *policies;
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
112
      if (boost::regex_match(line, matches, table_matches_re, boost::match_extra))
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
113
      {
114
        policies= &table_policies;
115
      }
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
116
      else if (boost::regex_match(line, matches, process_matches_re, boost::match_extra))
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
117
      {
118
        policies= &process_policies;
119
      }
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
120
      else if (boost::regex_match(line, matches, schema_matches_re, boost::match_extra))
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
121
      {
122
        policies= &schema_policies;
123
      }
124
      else
125
      {
126
        throw std::exception();
127
      }
128
      string user_regex;
129
      string object_regex;
130
      string action;
131
      user_regex= matches[MATCH_REGEX_USER_POS];
132
      object_regex= matches[MATCH_REGEX_OBJECT_POS];
133
      action= matches[MATCH_REGEX_ACTION_POS];
134
      PolicyItem *i;
135
      try
136
      {
137
        i= new PolicyItem(user_regex, object_regex, action);
138
      }
139
      catch (const std::exception &e)
140
      {
141
        error << "Bad policy item: user=" << user_regex << " object=" << object_regex << " action=" << action;
142
        throw std::exception();
143
      }
144
      policies->push_back(i);
145
    }
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
146
    return true;
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
147
  }
148
  catch (const std::exception &e)
149
  {
150
    /* On any non-EOF break, unparseable line */
151
    error << "Unable to parse line " << lines << " of policy file " << policy_file.string() << ":" << e.what();
2215.5.4 by Clint Byrum
fixing valgrind problems in a more sane way
152
    return false;
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
153
  }
154
}
155
2215.5.5 by Clint Byrum
add destructor for Policy object, should eliminate last valgrind warnings
156
void clearPolicyItemList(PolicyItemList policies)
157
{
158
  for (PolicyItemList::iterator x= policies.begin() ; x != policies.end() ; ++x)
159
  {
160
    delete *x;
161
    *x= NULL;
162
  }
163
} 
164
165
Policy::~Policy()
166
{
167
  clearPolicyItemList(table_policies);
168
  clearPolicyItemList(process_policies);
169
  clearPolicyItemList(schema_policies);
170
  delete table_check_cache;
171
  delete process_check_cache;
172
  delete schema_check_cache;
173
}
174
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
175
bool Policy::restrictObject(const drizzled::identifier::User &user_ctx,
176
                                   const string &obj, const PolicyItemList &policies,
177
                                   CheckMap **check_cache)
178
{
179
  CheckItem c(user_ctx.username(), obj, check_cache);
180
  if (!c.hasCachedResult())
181
  {
182
    PolicyItemList::const_iterator m= find_if(policies.begin(), policies.end(), c);
183
    if (m != policies.end())
184
    {
185
      c.setCachedResult((*m)->isRestricted());
186
    }
187
    else
188
    {
189
      /* TODO: make default action configurable */
190
      c.setCachedResult(false);
191
    }
192
  }
193
  return c.getCachedResult();
194
}
195
196
bool Policy::restrictSchema(const drizzled::identifier::User &user_ctx,
2246.4.9 by Olaf van der Spek
Remove const_reference and reference from identifier::Schema
197
                                   const drizzled::identifier::Schema& schema)
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
198
{
199
  return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, &schema_check_cache);
200
}
201
202
bool Policy::restrictProcess(const drizzled::identifier::User &user_ctx,
203
                                    const drizzled::identifier::User &session_ctx)
204
{
205
  return restrictObject(user_ctx, session_ctx.username(), process_policies, &process_check_cache);
206
}
207
2246.4.11 by Olaf van der Spek
Remove const_reference and reference from identifier::User
208
bool Policy::restrictTable(const drizzled::identifier::User& user_ctx,
2246.4.10 by Olaf van der Spek
Remove const_reference and reference from identifier::Table
209
                             const drizzled::identifier::Table& table)
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
210
{
211
  return restrictObject(user_ctx, table.getTableName(), table_policies, &table_check_cache);
212
}
213
214
bool CheckItem::operator()(PolicyItem *p)
215
{
216
  if (p->userMatches(user))
217
  {
218
    errmsg_printf(error::INSPECT, _("User %s matches regex\n"), user.c_str());
219
    if (p->objectMatches(object))
220
    {
221
      errmsg_printf(error::INSPECT, _("Object %s matches regex %s (%s)\n"), 
222
          object.c_str(),
223
          p->getObject().c_str(),
224
          p->getAction());
225
      return true;
226
    }
227
    errmsg_printf(error::INSPECT, _("Object %s NOT restricted by regex %s (%s)\n"), 
228
        object.c_str(),
229
        p->getObject().c_str(),
230
        p->getAction());
231
  }
232
  return false;
233
}
234
235
CheckItem::CheckItem(const std::string &user_in, const std::string &obj_in, CheckMap **check_cache_in)
236
  : user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in)
237
{
238
  CheckMap::iterator check_val;
239
  std::stringstream keystream;
240
  keystream << user << "_" << object;
241
  key= keystream.str();
242
243
  /* using RCU to only need to lock when updating the cache */
244
  if ((*check_cache) && (check_val= (*check_cache)->find(key)) != (*check_cache)->end())
245
  {
246
    setCachedResult(check_val->second);
247
  }
248
}
249
250
void CheckItem::setCachedResult(bool result)
251
{
252
  // TODO: make the mutex per-cache
253
  CheckMap *old_cache;
254
  CheckMap *new_cache;
255
  boost::mutex::scoped_lock lock(check_cache_mutex, boost::defer_lock);
256
  lock.lock();
257
258
  // Copy the current one
259
  if (*check_cache)
260
  {
261
    new_cache= new CheckMap(**check_cache);
262
  }
263
  else
264
  {
265
    new_cache= new CheckMap();
266
  }
2215.5.3 by Clint Byrum
fixing valgrind warnings
267
2215.5.1 by Clint Byrum
Adding regex_policy plugin for detailed authorization specifiction
268
  // Update it
269
  (*new_cache)[key]= result;
270
  // Replace old
271
  old_cache= *check_cache;
272
  *check_cache= new_cache;
273
274
  lock.unlock();
275
  has_cached_result= true;
276
  cached_result= result;
277
278
  if (old_cache)
279
  {
280
    delete old_cache;
281
  }
282
}
283
284
} /* namespace regex_policy */
285
286
DRIZZLE_PLUGIN(regex_policy::init, NULL, regex_policy::init_options);