Statistics
| Branch: | Tag: | Revision:

one / src / acl / AclManager.cc @ 84f874bf

History | View | Annotate | Download (11.8 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)             */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

    
17
#include "AclManager.h"
18
#include "NebulaLog.h"
19

    
20
/* -------------------------------------------------------------------------- */
21
/* -------------------------------------------------------------------------- */
22

    
23
const char * AclManager::table = "acl";
24

    
25
const char * AclManager::db_names = "user, resource, rights";
26

    
27
const char * AclManager::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
28
    "acl (user BIGINT, resource BIGINT, rights BIGINT)";
29

    
30
/* -------------------------------------------------------------------------- */
31
/* -------------------------------------------------------------------------- */
32

    
33
int AclManager::start()
34
{
35
    return select();
36
}
37

    
38
/* -------------------------------------------------------------------------- */
39
/* -------------------------------------------------------------------------- */
40

    
41
AclManager::~AclManager()
42
{
43
    multimap<long long, AclRule *>::iterator  it;
44

    
45
    for ( it = acl_rules.begin(); it != acl_rules.end(); it++ )
46
    {
47
        delete it->second;
48
    }
49
}
50

    
51
/* -------------------------------------------------------------------------- */
52
/* -------------------------------------------------------------------------- */
53

    
54
const bool AclManager::authorize(int uid, const set<int> &user_groups,
55
        AuthRequest::Object obj_type, int obj_id, int obj_gid,
56
        AuthRequest::Operation op)
57
{
58
    ostringstream oss;
59

    
60
    multimap<long long, AclRule *>::iterator        it;
61
    pair<multimap<long long, AclRule *>::iterator,
62
         multimap<long long, AclRule *>::iterator>  index;
63

    
64
    bool auth = false;
65

    
66
    // Build masks for request
67
    long long user_req;
68
    long long resource_oid_req  = obj_type + AclRule::INDIVIDUAL_ID + obj_id;
69
    long long resource_gid_req  = obj_type + AclRule::GROUP_ID + obj_gid;
70
    long long resource_all_req  = obj_type + AclRule::ALL_ID;
71
    long long rights_req        = op;
72

    
73
    long long individual_obj_type =
74
            ( obj_type | AclRule::INDIVIDUAL_ID | 0xFFFFFFFF );
75

    
76
    long long group_obj_type =
77
            ( obj_type | AclRule::GROUP_ID | 0xFFFFFFFF );
78

    
79

    
80

    
81
    AclRule request_rule(AclRule::INDIVIDUAL_ID + uid, resource_oid_req, rights_req);
82
    oss << "Request " << request_rule.to_str();
83
    NebulaLog::log("ACL",Log::DEBUG,oss);
84

    
85

    
86
    // Look for rules that apply to everyone
87

    
88
    user_req = AclRule::ALL_ID;
89
    auth = match_rules(user_req, resource_oid_req, resource_gid_req,
90
            resource_all_req, rights_req, individual_obj_type, group_obj_type);
91

    
92
    if ( auth == true )
93
    {
94
        return true;
95
    }
96

    
97
    // Look for rules that apply to the individual user id
98
    user_req = AclRule::INDIVIDUAL_ID + uid;
99

    
100
    auth = match_rules(user_req, resource_oid_req, resource_gid_req,
101
            resource_all_req, rights_req, individual_obj_type, group_obj_type);
102

    
103
    if ( auth == true )
104
    {
105
        return true;
106
    }
107

    
108

    
109
    // Look for rules that apply to each one of the user's groups
110

    
111
    set<int>::iterator  g_it;
112

    
113
    for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
114
    {
115
        user_req = AclRule::GROUP_ID + *g_it;
116

    
117
        auth = match_rules(user_req, resource_oid_req, resource_gid_req,
118
                resource_all_req, rights_req, individual_obj_type,
119
                group_obj_type);
120

    
121
        if ( auth == true )
122
        {
123
            return true;
124
        }
125
    }
126

    
127

    
128
    oss.str("No more rules, permission not granted ");
129
    NebulaLog::log("ACL",Log::DEBUG,oss);
130

    
131
    return false;
132
}
133

    
134
/* -------------------------------------------------------------------------- */
135
/* -------------------------------------------------------------------------- */
136

    
137
bool AclManager::match_rules(
138
        long long user_req,
139
        long long resource_oid_req,
140
        long long resource_gid_req,
141
        long long resource_all_req,
142
        long long rights_req,
143
        long long individual_obj_type,
144
        long long group_obj_type)
145

    
146
{
147
    bool auth;
148
    ostringstream oss;
149

    
150
    multimap<long long, AclRule *>::iterator        it;
151

    
152
    pair<multimap<long long, AclRule *>::iterator,
153
         multimap<long long, AclRule *>::iterator>  index;
154

    
155
    index = acl_rules.equal_range( user_req );
156

    
157
    for ( it = index.first; it != index.second; it++)
158
    {
159
        oss.str("");
160
        oss << "> Rule  " << it->second->to_str();
161
        NebulaLog::log("ACL",Log::DEBUG,oss);
162

    
163
        auth =
164
          // Rule grants the requested rights
165
          ( ( it->second->rights & rights_req ) == rights_req )
166
          &&
167
          (
168
            // Rule grants permission for all objects of this type
169
            ( it->second->resource == resource_all_req )
170
            ||
171
            // Or rule's object type and group object ID match
172
            ( ( it->second->resource & group_obj_type ) == resource_gid_req )
173
            ||
174
            // Or rule's object type and individual object ID match
175
            ( ( it->second->resource & individual_obj_type ) == resource_oid_req )
176
          );
177

    
178
        if ( auth == true )
179
        {
180
            oss.str("Permission granted");
181
            NebulaLog::log("ACL",Log::DEBUG,oss);
182

    
183
            return true;
184
        }
185
    }
186

    
187
    return false;
188
}
189

    
190
/* -------------------------------------------------------------------------- */
191
/* -------------------------------------------------------------------------- */
192

    
193
int AclManager::add_rule(long long user, long long resource, long long rights,
194
                        string& error_str)
195
{
196
    AclRule * rule = new AclRule(user, resource, rights);
197

    
198
    ostringstream   oss;
199
    int             rc;
200

    
201
    multimap<long long, AclRule *>::iterator        it;
202
    pair<multimap<long long, AclRule *>::iterator,
203
         multimap<long long, AclRule *>::iterator>  index;
204

    
205
    bool found = false;
206

    
207
    index = acl_rules.equal_range( user );
208

    
209
    for ( it = index.first; (it != index.second && !found); it++)
210
    {
211
        found = *(it->second) == *rule;
212
        if ( it->second->resource == resource &&
213
             it->second->rights == rights )
214
        {
215
            found = true;
216
        }
217
    }
218

    
219
    if ( found )
220
    {
221
        oss << "Rule " << rule->to_str() << " already exists";
222
        error_str = oss.str();
223

    
224
        delete rule;
225
        return -1;
226
    }
227

    
228
    if ( rule->malformed(error_str) )
229
    {
230
        oss << "Rule " << rule->to_str() << " is malformed: " << error_str;
231
        error_str = oss.str();
232

    
233
        delete rule;
234
        return -2;
235
    }
236

    
237

    
238
    rc = insert(rule);
239

    
240
    if ( rc != 0 )
241
    {
242
        error_str = "Error inserting rule in DB";
243
        return -1;
244
    }
245

    
246
    acl_rules.insert( make_pair(rule->user, rule) );
247

    
248
    return 0;
249
}
250

    
251
/* -------------------------------------------------------------------------- */
252
/* -------------------------------------------------------------------------- */
253

    
254
int AclManager::del_rule(long long user, long long resource, long long rights,
255
                        string& error_str)
256
{
257
    multimap<long long, AclRule *>::iterator        it;
258
    pair<multimap<long long, AclRule *>::iterator,
259
         multimap<long long, AclRule *>::iterator>  index;
260

    
261
    int rc;
262
    bool found = false;
263

    
264
    index = acl_rules.equal_range( user );
265

    
266
    it = index.first;
267
    while ( !found && it != index.second )
268
    {
269
        found = ( it->second->resource == resource &&
270
                  it->second->rights == rights );
271

    
272
        if ( !found )
273
        {
274
            it++;
275
        }
276
    }
277

    
278
    if ( !found )
279
    {
280
        AclRule rule(user, resource, rights);
281

    
282
        ostringstream oss;
283
        oss << "Rule " << rule.to_str() << " does not exist";
284
        error_str = oss.str();
285

    
286
        return -1;
287
    }
288

    
289
    rc = drop( it->second );
290

    
291
    if ( rc != 0 )
292
    {
293
        error_str = "SQL DB error";
294
        return -1;
295
    }
296

    
297
    delete it->second;
298
    acl_rules.erase( it );
299

    
300
    return 0;
301
}
302

    
303
/* -------------------------------------------------------------------------- */
304
/* -------------------------------------------------------------------------- */
305

    
306
int AclManager::select_cb(void *nil, int num, char **values, char **names)
307
{
308
    if ( (num != 3)   ||
309
         (!values[0]) ||
310
         (!values[1]) ||
311
         (!values[2]) )
312
    {
313
        return -1;
314
    }
315

    
316
    ostringstream oss;
317
    istringstream iss;
318

    
319
    long long rule_values[3];
320

    
321
    for ( int i = 0; i < 3; i++ )
322
    {
323
        iss.str( values[i] );
324

    
325
        iss >> rule_values[i];
326

    
327
        if ( iss.fail() == true )
328
        {
329
            return -1;
330
        }
331

    
332
        iss.clear();
333
    }
334

    
335
    // TODO: Use add_rule() instead, to check possible errors, or assume
336
    // that anything that was stored into the DB is trustworthy?
337
    AclRule * rule = new AclRule(rule_values[0], rule_values[1], rule_values[2]);
338

    
339

    
340
    oss << "Loading ACL Rule " << rule->to_str();
341
    NebulaLog::log("ACL",Log::DEBUG,oss);
342

    
343
    acl_rules.insert( make_pair(rule->user, rule) );
344

    
345
    return 0;
346
}
347

    
348
/* -------------------------------------------------------------------------- */
349
/* -------------------------------------------------------------------------- */
350

    
351
int AclManager::select()
352
{
353
    ostringstream   oss;
354
    int             rc;
355

    
356
    oss << "SELECT " << db_names << " FROM " << table;
357

    
358
    set_callback(static_cast<Callbackable::Callback>(&AclManager::select_cb));
359

    
360
    rc = db->exec(oss,this);
361

    
362
    unset_callback();
363

    
364
    return rc;
365
}
366

    
367
/* -------------------------------------------------------------------------- */
368
/* -------------------------------------------------------------------------- */
369

    
370
int AclManager::insert(AclRule * rule)
371
{
372
    ostringstream   oss;
373
    int             rc;
374

    
375
    // Construct the SQL statement to Insert
376

    
377
    oss <<  "INSERT INTO "  << table <<" ("<< db_names <<") VALUES ("
378
        <<  rule->user      << ","
379
        <<  rule->resource  << ","
380
        <<  rule->rights    << ")";
381

    
382
    rc = db->exec(oss);
383

    
384
    return rc;
385
}
386

    
387
/* -------------------------------------------------------------------------- */
388
/* -------------------------------------------------------------------------- */
389

    
390
int AclManager::drop(AclRule * rule)
391
{
392
    ostringstream   oss;
393
    int             rc;
394

    
395
    oss << "DELETE FROM " << table << " WHERE "
396
        << "user=" << rule->user << "AND"
397
        << "resource=" << rule->resource << "AND"
398
        << "rights=" << rule->rights;
399

    
400
    rc = db->exec(oss);
401

    
402
    return rc;
403
}
404

    
405
/* -------------------------------------------------------------------------- */
406
/* -------------------------------------------------------------------------- */
407

    
408
int AclManager::dump(ostringstream& oss)
409
{
410
    multimap<long long, AclRule *>::iterator        it;
411
    string xml;
412

    
413
    oss << "<ACL>";
414

    
415
    for ( it = acl_rules.begin() ; it != acl_rules.end(); it++ )
416
    {
417
        oss << it->second->to_xml(xml);
418
    }
419

    
420
    oss << "</ACL>";
421

    
422
    return 0;
423
}
424

    
425
/* -------------------------------------------------------------------------- */
426
/* -------------------------------------------------------------------------- */