Statistics
| Branch: | Tag: | Revision:

one / src / acl / AclManager.cc @ 621a1869

History | View | Annotate | Download (35.4 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems                */
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 <climits>
18

    
19
#include "AclManager.h"
20
#include "NebulaLog.h"
21
#include "PoolObjectAuth.h"
22

    
23
/* -------------------------------------------------------------------------- */
24
/* -------------------------------------------------------------------------- */
25

    
26
const char * AclManager::table = "acl";
27

    
28
const char * AclManager::db_names = "oid, user, resource, rights, zone";
29

    
30
const char * AclManager::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
31
    "acl (oid INT PRIMARY KEY, user BIGINT, resource BIGINT, "
32
    "rights BIGINT, zone BIGINT, UNIQUE(user, resource, rights, zone))";
33

    
34
/* -------------------------------------------------------------------------- */
35
/* -------------------------------------------------------------------------- */
36

    
37
int AclManager::init_cb(void *nil, int num, char **values, char **names)
38
{
39
    lastOID = -1;
40

    
41
    if ( values[0] != 0 )
42
    {
43
        lastOID = atoi(values[0]);
44
    }
45

    
46
    return 0;
47
}
48

    
49
/* -------------------------------------------------------------------------- */
50

    
51
AclManager::AclManager(
52
    SqlDB * _db,
53
    int     _zone_id,
54
    bool    _is_federation_slave,
55
    time_t  _timer_period)
56
        :zone_id(_zone_id), db(_db), lastOID(-1),
57
        is_federation_slave(_is_federation_slave), timer_period(_timer_period)
58
{
59
    ostringstream oss;
60

    
61
    pthread_mutex_init(&mutex, 0);
62

    
63
    set_callback(static_cast<Callbackable::Callback> (&AclManager::init_cb));
64

    
65
    oss << "SELECT last_oid FROM pool_control WHERE tablename='" << table
66
            << "'";
67

    
68
    db->exec(oss, this);
69

    
70
    unset_callback();
71

    
72
    am.addListener(this);
73

    
74
    //Federation slaves do not need to init the pool
75
    if (is_federation_slave)
76
    {
77
        return;
78
    }
79

    
80
    if (lastOID == -1)
81
    {
82
        // Add a default rules for the ACL engine
83
        string error_str;
84

    
85
        // Users in group USERS can create standard resources
86
        // @1 VM+IMAGE+TEMPLATE+DOCUMENT/* CREATE *
87
        add_rule(AclRule::GROUP_ID |
88
                    1,
89
                 AclRule::ALL_ID |
90
                    PoolObjectSQL::VM |
91
                    PoolObjectSQL::IMAGE |
92
                    PoolObjectSQL::TEMPLATE |
93
                    PoolObjectSQL::DOCUMENT |
94
                    PoolObjectSQL::SECGROUP,
95
                 AuthRequest::CREATE,
96
                 AclRule::ALL_ID,
97
                 error_str);
98

    
99
        // * ZONE/* USE *
100
        add_rule(AclRule::ALL_ID,
101
                 AclRule::ALL_ID |
102
                    PoolObjectSQL::ZONE,
103
                 AuthRequest::USE,
104
                 AclRule::ALL_ID,
105
                 error_str);
106

    
107
        // * MARKETPLACE+MARKETPLACEAPP/* USE *
108
        add_rule(AclRule::ALL_ID,
109
                 AclRule::ALL_ID |
110
                    PoolObjectSQL::MARKETPLACE |
111
                    PoolObjectSQL::MARKETPLACEAPP,
112
                 AuthRequest::USE,
113
                 AclRule::ALL_ID,
114
                 error_str);
115
    }
116
}
117

    
118
/* -------------------------------------------------------------------------- */
119
/* -------------------------------------------------------------------------- */
120

    
121
extern "C" void * acl_action_loop(void *arg)
122
{
123
    AclManager * aclm;
124

    
125
    if ( arg == 0 )
126
    {
127
        return 0;
128
    }
129

    
130
    NebulaLog::log("ACL",Log::INFO,"ACL Manager started.");
131

    
132
    aclm = static_cast<AclManager *>(arg);
133

    
134
    aclm->am.loop(aclm->timer_period,0);
135

    
136
    NebulaLog::log("ACL",Log::INFO,"ACL Manager stopped.");
137

    
138
    return 0;
139
}
140

    
141
/* -------------------------------------------------------------------------- */
142
/* -------------------------------------------------------------------------- */
143

    
144
int AclManager::start()
145
{
146
    int rc;
147

    
148
    NebulaLog::log("ACL",Log::INFO,"Starting ACL Manager...");
149

    
150
    rc = select();
151

    
152
    if (is_federation_slave)
153
    {
154
        pthread_attr_t    pattr;
155

    
156
        pthread_attr_init (&pattr);
157
        pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE);
158

    
159
        rc += pthread_create(&acl_thread,&pattr,acl_action_loop,(void *) this);
160
    }
161
    else
162
    {
163
        NebulaLog::log("ACL",Log::INFO,"ACL Manager started.");
164
    }
165

    
166
    return rc;
167
}
168

    
169
/* -------------------------------------------------------------------------- */
170
/* -------------------------------------------------------------------------- */
171

    
172
void AclManager::finalize()
173
{
174
    if (is_federation_slave)
175
    {
176
        am.trigger(ACTION_FINALIZE,0);
177
    }
178
    else
179
    {
180
        NebulaLog::log("ACL",Log::INFO,"ACL Manager stopped.");
181
    }
182
}
183

    
184
/* -------------------------------------------------------------------------- */
185
/* -------------------------------------------------------------------------- */
186

    
187
AclManager::~AclManager()
188
{
189
    multimap<long long, AclRule *>::iterator  it;
190

    
191
    lock();
192

    
193
    for ( it = acl_rules.begin(); it != acl_rules.end(); it++ )
194
    {
195
        delete it->second;
196
    }
197

    
198
    unlock();
199

    
200
    pthread_mutex_destroy(&mutex);
201
}
202

    
203
/* -------------------------------------------------------------------------- */
204
/* -------------------------------------------------------------------------- */
205

    
206
const bool AclManager::authorize(
207
        int                     uid,
208
        const set<int>&         user_groups,
209
        const PoolObjectAuth&   obj_perms,
210
        AuthRequest::Operation  op)
211
{
212
    ostringstream oss;
213

    
214
    bool auth = false;
215

    
216
    // Build masks for request
217
    long long user_req;
218
    long long resource_oid_req;
219

    
220
    if ( obj_perms.oid >= 0 )
221
    {
222
        resource_oid_req = obj_perms.obj_type |
223
                           AclRule::INDIVIDUAL_ID |
224
                           obj_perms.oid;
225
    }
226
    else
227
    {
228
        resource_oid_req = AclRule::NONE_ID;
229
    }
230

    
231
    long long resource_gid_req;
232

    
233
    if ((obj_perms.gid >= 0) && (!obj_perms.disable_group_acl))
234
    {
235
        resource_gid_req = obj_perms.obj_type |
236
                           AclRule::GROUP_ID |
237
                           obj_perms.gid;
238
    }
239
    else
240
    {
241
        resource_gid_req = AclRule::NONE_ID;
242
    }
243

    
244
    set<long long> resource_cid_req;
245

    
246
    if (!obj_perms.disable_cluster_acl)
247
    {
248
        set<int>::iterator i;
249

    
250
        for(i = obj_perms.cids.begin(); i != obj_perms.cids.end(); i++)
251
        {
252
            resource_cid_req.insert(    obj_perms.obj_type |
253
                                        AclRule::CLUSTER_ID |
254
                                        *i
255
                                    );
256
        }
257
    }
258

    
259
    long long resource_all_req ;
260

    
261
    if (!obj_perms.disable_all_acl)
262
    {
263
        resource_all_req = obj_perms.obj_type | AclRule::ALL_ID;
264
    }
265
    else
266
    {
267
        resource_all_req = AclRule::NONE_ID;
268
    }
269

    
270
    long long rights_req        = op;
271

    
272
    long long resource_oid_mask = obj_perms.obj_type |
273
                                  AclRule::INDIVIDUAL_ID |
274
                                  0x00000000FFFFFFFFLL;
275

    
276
    long long resource_gid_mask = obj_perms.obj_type |
277
                                  AclRule::GROUP_ID |
278
                                  0x00000000FFFFFFFFLL;
279

    
280
    long long resource_cid_mask = obj_perms.obj_type |
281
                                  AclRule::CLUSTER_ID |
282
                                  0x00000000FFFFFFFFLL;
283

    
284
    // Create a temporal rule, to log the request
285
    long long log_resource;
286

    
287
    if ( obj_perms.oid >= 0 )
288
    {
289
        log_resource = resource_oid_req;
290
    }
291
    else if ( obj_perms.gid >= 0 )
292
    {
293
        log_resource = resource_gid_req;
294
    }
295
    else
296
    {
297
        log_resource = resource_all_req;
298
    }
299

    
300
    AclRule log_rule(-1,
301
                     AclRule::INDIVIDUAL_ID | uid,
302
                     log_resource,
303
                     rights_req,
304
                     AclRule::INDIVIDUAL_ID | zone_id);
305

    
306
    oss << "Request " << log_rule.to_str();
307
    NebulaLog::log("ACL",Log::DDEBUG,oss);
308

    
309
    // -------------------------------------------------------------------------
310
    // Create temporary rules from the object permissions
311
    // -------------------------------------------------------------------------
312

    
313
    AclRule owner_rule;
314
    AclRule group_rule;
315
    AclRule other_rule;
316
    multimap<long long, AclRule *> tmp_rules;
317

    
318
    obj_perms.get_acl_rules(owner_rule, group_rule, other_rule, zone_id);
319

    
320
    tmp_rules.insert( make_pair(owner_rule.user, &owner_rule) );
321
    tmp_rules.insert( make_pair(group_rule.user, &group_rule) );
322
    tmp_rules.insert( make_pair(other_rule.user, &other_rule) );
323

    
324
    // -------------------------------------------------------------------------
325
    // Look for rules that apply to everyone
326
    // -------------------------------------------------------------------------
327

    
328
    user_req = AclRule::ALL_ID;
329
    auth     = match_rules_wrapper(user_req,
330
                                   resource_oid_req,
331
                                   resource_gid_req,
332
                                   resource_cid_req,
333
                                   resource_all_req,
334
                                   rights_req,
335
                                   resource_oid_mask,
336
                                   resource_gid_mask,
337
                                   resource_cid_mask,
338
                                   tmp_rules);
339
    if ( auth == true )
340
    {
341
        return true;
342
    }
343

    
344
    // -------------------------------------------------------------------------
345
    // Look for rules that apply to the individual user id
346
    // -------------------------------------------------------------------------
347

    
348
    user_req = AclRule::INDIVIDUAL_ID | uid;
349
    auth     = match_rules_wrapper(user_req,
350
                                   resource_oid_req,
351
                                   resource_gid_req,
352
                                   resource_cid_req,
353
                                   resource_all_req,
354
                                   rights_req,
355
                                   resource_oid_mask,
356
                                   resource_gid_mask,
357
                                   resource_cid_mask,
358
                                   tmp_rules);
359
    if ( auth == true )
360
    {
361
        return true;
362
    }
363

    
364
    // ----------------------------------------------------------
365
    // Look for rules that apply to each one of the user's groups
366
    // ----------------------------------------------------------
367

    
368
    set<int>::iterator  g_it;
369

    
370
    for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
371
    {
372
        user_req = AclRule::GROUP_ID | *g_it;
373
        auth     = match_rules_wrapper(user_req,
374
                                       resource_oid_req,
375
                                       resource_gid_req,
376
                                       resource_cid_req,
377
                                       resource_all_req,
378
                                       rights_req,
379
                                       resource_oid_mask,
380
                                       resource_gid_mask,
381
                                       resource_cid_mask,
382
                                       tmp_rules);
383
        if ( auth == true )
384
        {
385
            return true;
386
        }
387
    }
388

    
389
    oss.str("No more rules, permission not granted ");
390
    NebulaLog::log("ACL",Log::DDEBUG,oss);
391

    
392
    return false;
393
}
394

    
395
/* -------------------------------------------------------------------------- */
396
/* -------------------------------------------------------------------------- */
397

    
398
bool AclManager::match_rules_wrapper(
399
        const long long                     &user_req,
400
        const long long                     &resource_oid_req,
401
        const long long                     &resource_gid_req,
402
        const set<long long>                &resource_cid_req,
403
        const long long                     &resource_all_req,
404
        const long long                     &rights_req,
405
        const long long                     &individual_obj_type,
406
        const long long                     &group_obj_type,
407
        const long long                     &cluster_obj_type,
408
        const multimap<long long, AclRule*> &tmp_rules)
409
{
410
    bool auth = false;
411

    
412
    // Match against the tmp rules
413
    auth = match_rules(
414
            user_req,
415
            resource_oid_req,
416
            resource_gid_req,
417
            resource_cid_req,
418
            resource_all_req,
419
            rights_req,
420
            individual_obj_type,
421
            group_obj_type,
422
            cluster_obj_type,
423
            tmp_rules);
424

    
425
    if ( auth == true )
426
    {
427
        return true;
428
    }
429

    
430
    // Match against the internal rules
431
    lock();
432

    
433
    auth = match_rules(
434
            user_req,
435
            resource_oid_req,
436
            resource_gid_req,
437
            resource_cid_req,
438
            resource_all_req,
439
            rights_req,
440
            individual_obj_type,
441
            group_obj_type,
442
            cluster_obj_type,
443
            acl_rules);
444

    
445
    unlock();
446

    
447
    return auth;
448
}
449

    
450
/* -------------------------------------------------------------------------- */
451
/* -------------------------------------------------------------------------- */
452

    
453
inline bool match_cluster_req(
454
        const set<long long>  &resource_cid_req,
455
        const long long       &resource_cid_mask,
456
        const long long       &rule_resource)
457
{
458
    set<long long>::iterator i;
459

    
460
    for(i = resource_cid_req.begin(); i != resource_cid_req.end(); i++)
461
    {
462
        // rule's object type and cluster object ID match
463
        if ( ( rule_resource & resource_cid_mask ) == *i )
464
        {
465
            return true;
466
        }
467
    }
468

    
469
    return false;
470
}
471

    
472
/* -------------------------------------------------------------------------- */
473

    
474
bool AclManager::match_rules(
475
        const long long                     &user_req,
476
        const long long                     &resource_oid_req,
477
        const long long                     &resource_gid_req,
478
        const set<long long>                &resource_cid_req,
479
        const long long                     &resource_all_req,
480
        const long long                     &rights_req,
481
        const long long                     &resource_oid_mask,
482
        const long long                     &resource_gid_mask,
483
        const long long                     &resource_cid_mask,
484
        const multimap<long long, AclRule*> &rules)
485

    
486
{
487
    bool auth = false;
488
    ostringstream oss;
489

    
490
    multimap<long long, AclRule *>::const_iterator        it;
491

    
492
    pair<multimap<long long, AclRule *>::const_iterator,
493
         multimap<long long, AclRule *>::const_iterator>  index;
494

    
495
    long long zone_oid_mask = AclRule::INDIVIDUAL_ID | 0x00000000FFFFFFFFLL;
496
    long long zone_req      = AclRule::INDIVIDUAL_ID | zone_id;
497
    long long zone_all_req  = AclRule::ALL_ID;
498

    
499
    index = rules.equal_range( user_req );
500

    
501
    for ( it = index.first; it != index.second; it++)
502
    {
503
        oss.str("");
504
        oss << "> Rule  " << it->second->to_str();
505
        NebulaLog::log("ACL",Log::DDEBUG,oss);
506

    
507
        auth =
508
          (
509
            // Rule applies in any Zone
510
            ( ( it->second->zone & zone_all_req ) == zone_all_req )
511
            ||
512
            // Rule applies in this Zone
513
            ( ( it->second->zone & zone_oid_mask ) == zone_req )
514
          )
515
          &&
516
          // Rule grants the requested rights
517
          ( ( it->second->rights & rights_req ) == rights_req )
518
          &&
519
          (
520
            // Rule grants permission for all objects of this type
521
            ( ( it->second->resource & resource_all_req ) == resource_all_req )
522
            ||
523
            // Or rule's object type and group object ID match
524
            ( ( it->second->resource & resource_gid_mask ) == resource_gid_req )
525
            ||
526
            // Or rule's object type and individual object ID match
527
            ( ( it->second->resource & resource_oid_mask ) == resource_oid_req )
528
            ||
529
            // Or rule's object type and one of the cluster object ID match
530
            match_cluster_req(resource_cid_req, resource_cid_mask, it->second->resource)
531
          );
532

    
533
        if ( auth == true )
534
        {
535
            oss.str("Permission granted");
536
            NebulaLog::log("ACL",Log::DDEBUG,oss);
537

    
538
            break;
539
        }
540
    }
541

    
542
    return auth;
543
}
544

    
545
/* -------------------------------------------------------------------------- */
546
/* -------------------------------------------------------------------------- */
547

    
548
int AclManager::add_rule(long long user, long long resource, long long rights,
549
                        long long zone, string& error_str)
550
{
551
    if (is_federation_slave)
552
    {
553
        NebulaLog::log("ONE",Log::ERROR,
554
                "AclManager::add_rule called, but this "
555
                "OpenNebula is a federation slave");
556

    
557
        return -1;
558
    }
559

    
560
    lock();
561

    
562
    if (lastOID == INT_MAX)
563
    {
564
        lastOID = -1;
565
    }
566

    
567
    AclRule * rule = new AclRule(++lastOID, user, resource, rights, zone);
568

    
569
    ostringstream   oss;
570
    int             rc;
571

    
572
    multimap<long long, AclRule *>::iterator        it;
573
    pair<multimap<long long, AclRule *>::iterator,
574
         multimap<long long, AclRule *>::iterator>  index;
575

    
576
    bool found = false;
577

    
578
    index = acl_rules.equal_range( user );
579

    
580
    for ( it = index.first; (it != index.second && !found); it++)
581
    {
582
        found = *(it->second) == *rule;
583
    }
584

    
585
    if ( found )
586
    {
587
        goto error_duplicated;
588
    }
589

    
590
    if ( rule->malformed(error_str) )
591
    {
592
        goto error_malformed;
593
    }
594

    
595
    rc = insert(rule);
596

    
597
    if ( rc != 0 )
598
    {
599
        goto error_insert;
600
    }
601

    
602
    acl_rules.insert( make_pair(rule->user, rule) );
603
    acl_rules_oids.insert( make_pair(rule->oid, rule) );
604

    
605
    update_lastOID();
606

    
607
    unlock();
608

    
609
    return lastOID;
610

    
611

    
612
error_duplicated:
613
    oss << "Rule " << rule->to_str() << " already exists";
614
    rc = -1;
615

    
616
    goto error_common;
617

    
618
error_malformed:
619
    oss << "Rule " << rule->to_str() << " is malformed: " << error_str;
620
    rc = -2;
621

    
622
    goto error_common;
623

    
624
error_insert:
625
    oss << "Error inserting rule in DB";
626
    rc = -3;
627

    
628
    goto error_common;
629

    
630
error_common:
631
    error_str = oss.str();
632

    
633
    delete rule;
634
    lastOID--;
635

    
636
    unlock();
637

    
638
    return rc;
639
}
640

    
641
/* -------------------------------------------------------------------------- */
642
/* -------------------------------------------------------------------------- */
643

    
644

    
645
int AclManager::del_rule(int oid, string& error_str)
646
{
647

    
648
    multimap<long long, AclRule *>::iterator        it;
649
    pair<multimap<long long, AclRule *>::iterator,
650
         multimap<long long, AclRule *>::iterator>  index;
651

    
652
    AclRule *   rule;
653
    int         rc;
654
    bool        found = false;
655

    
656
    if (is_federation_slave)
657
    {
658
        NebulaLog::log("ONE",Log::ERROR,
659
                "AclManager::del_rule called, but this "
660
                "OpenNebula is a federation slave");
661

    
662
        return -1;
663
    }
664

    
665
    lock();
666

    
667
    // Check the rule exists
668
    found = acl_rules_oids.count(oid) > 0;
669

    
670
    if ( !found )
671
    {
672
        ostringstream oss;
673
        oss << "Rule " << oid << " does not exist";
674
        error_str = oss.str();
675

    
676
        unlock();
677
        return -1;
678
    }
679

    
680
    rule = acl_rules_oids[oid];
681

    
682
    // Look for it in the multimap
683

    
684
    found = false;
685

    
686
    index = acl_rules.equal_range( rule->user );
687

    
688
    it = index.first;
689
    while ( !found && it != index.second )
690
    {
691
        found = *rule == *(it->second);
692

    
693
        if ( !found )
694
        {
695
            it++;
696
        }
697
    }
698

    
699
    if ( !found )
700
    {
701
        ostringstream oss;
702
        oss << "Internal error: ACL Rule " << oid
703
            << " indexed by oid, but not in by user attribute";
704

    
705
        NebulaLog::log("ACL",Log::ERROR,oss);
706

    
707
        unlock();
708
        return -1;
709
    }
710

    
711

    
712
    rc = drop( oid );
713

    
714
    if ( rc != 0 )
715
    {
716
        error_str = "SQL DB error";
717

    
718
        unlock();
719
        return -1;
720
    }
721

    
722
    rule = it->second;
723

    
724
    acl_rules.erase( it );
725
    acl_rules_oids.erase( oid );
726

    
727
    delete rule;
728

    
729
    unlock();
730
    return 0;
731
}
732

    
733
/* -------------------------------------------------------------------------- */
734
/* -------------------------------------------------------------------------- */
735

    
736
int AclManager::del_rule(
737
        long long user,
738
        long long resource,
739
        long long rights,
740
        long long zone,
741
        string&   error_str)
742
{
743
    lock();
744

    
745
    AclRule * rule = new AclRule(-1, user, resource, rights, zone);
746

    
747
    int oid = -1;
748
    bool found = false;
749

    
750
    multimap<long long, AclRule *>::iterator        it;
751
    pair<multimap<long long, AclRule *>::iterator,
752
         multimap<long long, AclRule *>::iterator>  index;
753

    
754
    index = acl_rules.equal_range( user );
755

    
756
    for ( it = index.first; (it != index.second && !found); it++)
757
    {
758
        found = *(it->second) == *rule;
759

    
760
        if (found)
761
        {
762
            oid = it->second->get_oid();
763
        }
764
    }
765

    
766
    unlock();
767

    
768
    if (oid != -1)
769
    {
770
        return del_rule(oid, error_str);
771
    }
772
    else
773
    {
774
        error_str = "Rule does not exist";
775
        return -1;
776
    }
777
}
778

    
779
/* -------------------------------------------------------------------------- */
780
/* -------------------------------------------------------------------------- */
781

    
782
void AclManager::del_uid_rules(int uid)
783
{
784
    long long user_req = AclRule::INDIVIDUAL_ID | uid;
785

    
786
    // Delete rules that match
787
    // #uid  __/__  __
788
    del_user_matching_rules(user_req);
789
}
790

    
791
/* -------------------------------------------------------------------------- */
792
/* -------------------------------------------------------------------------- */
793

    
794
void AclManager::del_gid_rules(int gid)
795
{
796
    long long request = AclRule::GROUP_ID | gid;
797
    long long resource_gid_mask = AclRule::GROUP_ID |
798
                                  0x00000000FFFFFFFFLL;
799

    
800
    // Delete rules that match
801
    // @gid  __/__  __
802
    del_user_matching_rules(request);
803

    
804
    // __  __/@gid  __
805
    del_resource_matching_rules(request, resource_gid_mask);
806
}
807

    
808
/* -------------------------------------------------------------------------- */
809
/* -------------------------------------------------------------------------- */
810

    
811
void AclManager::del_cid_rules(int cid)
812
{
813
    long long request = AclRule::CLUSTER_ID | cid;
814
    long long resource_gid_mask = AclRule::CLUSTER_ID |
815
                                  0x00000000FFFFFFFFLL;
816

    
817
    // Delete rules that match
818
    // __  __/%cid  __
819
    del_resource_matching_rules(request, resource_gid_mask);
820
}
821

    
822
/* -------------------------------------------------------------------------- */
823
/* -------------------------------------------------------------------------- */
824

    
825
void AclManager::del_zid_rules(int zid)
826
{
827
    long long request = AclRule::INDIVIDUAL_ID | zid;
828

    
829
    // Delete rules that match
830
    // __  __/__  __ #zid
831
    del_zone_matching_rules(request);
832
}
833

    
834
/* -------------------------------------------------------------------------- */
835
/* -------------------------------------------------------------------------- */
836

    
837
void AclManager::del_resource_rules(int oid, PoolObjectSQL::ObjectType obj_type)
838
{
839
    long long request = obj_type |
840
                        AclRule::INDIVIDUAL_ID |
841
                        oid;
842

    
843
    long long mask = 0xFFFFFFFFFFFFFFFFLL;
844

    
845
    // Delete rules that are an exact match, i.e. for oid=7 and obj_type=IMAGE,
846
    // this rule applies, but can't be deleted:
847
    // __ IMAGE+TEMPLATE/#7 __
848
    del_resource_matching_rules(request, mask);
849
}
850

    
851
/* -------------------------------------------------------------------------- */
852
/* -------------------------------------------------------------------------- */
853

    
854
void AclManager::del_user_matching_rules(long long user_req)
855
{
856
    multimap<long long, AclRule *>::iterator        it;
857
    pair<multimap<long long, AclRule *>::iterator,
858
         multimap<long long, AclRule *>::iterator>  index;
859

    
860
    vector<int>             oids;
861
    vector<int>::iterator   oid_it;
862
    string                  error_str;
863

    
864
    lock();
865

    
866
    index = acl_rules.equal_range( user_req );
867

    
868
    for ( it = index.first; it != index.second; it++)
869
    {
870
        oids.push_back(it->second->oid);
871
    }
872

    
873
    unlock();
874

    
875
    for ( oid_it = oids.begin() ; oid_it < oids.end(); oid_it++ )
876
    {
877
        del_rule(*oid_it, error_str);
878
    }
879
}
880

    
881
/* -------------------------------------------------------------------------- */
882
/* -------------------------------------------------------------------------- */
883

    
884
void AclManager::del_resource_matching_rules(long long resource_req,
885
                                             long long resource_mask)
886
{
887
    multimap<long long, AclRule *>::iterator        it;
888

    
889
    vector<int>             oids;
890
    vector<int>::iterator   oid_it;
891
    string                  error_str;
892

    
893
    lock();
894

    
895
    for ( it = acl_rules.begin(); it != acl_rules.end(); it++ )
896
    {
897
        if ( ( it->second->resource & resource_mask ) == resource_req )
898
        {
899
            oids.push_back(it->second->oid);
900
        }
901
    }
902

    
903
    unlock();
904

    
905
    for ( oid_it = oids.begin() ; oid_it < oids.end(); oid_it++ )
906
    {
907
        del_rule(*oid_it, error_str);
908
    }
909
}
910

    
911
/* -------------------------------------------------------------------------- */
912
/* -------------------------------------------------------------------------- */
913

    
914
void AclManager::del_zone_matching_rules(long long zone_req)
915
{
916
    multimap<long long, AclRule *>::iterator        it;
917

    
918
    vector<int>             oids;
919
    vector<int>::iterator   oid_it;
920
    string                  error_str;
921

    
922
    lock();
923

    
924
    for ( it = acl_rules.begin(); it != acl_rules.end(); it++ )
925
    {
926
        if ( it->second->zone == zone_req )
927
        {
928
            oids.push_back(it->second->oid);
929
        }
930
    }
931

    
932
    unlock();
933

    
934
    for ( oid_it = oids.begin() ; oid_it < oids.end(); oid_it++ )
935
    {
936
        del_rule(*oid_it, error_str);
937
    }
938
}
939

    
940
/* -------------------------------------------------------------------------- */
941
/* -------------------------------------------------------------------------- */
942

    
943
void AclManager::reverse_search(int                       uid,
944
                                const set<int>&           user_groups,
945
                                PoolObjectSQL::ObjectType obj_type,
946
                                AuthRequest::Operation    op,
947
                                bool                      disable_all_acl,
948
                                bool                      disable_cluster_acl,
949
                                bool                      disable_group_acl,
950
                                bool&                     all,
951
                                vector<int>&              oids,
952
                                vector<int>&              gids,
953
                                vector<int>&              cids)
954
{
955
    ostringstream oss;
956

    
957
    multimap<long long, AclRule *>::iterator        it;
958
    pair<multimap<long long, AclRule *>::iterator,
959
         multimap<long long, AclRule *>::iterator>  index;
960

    
961
    // Build masks for request
962
    long long resource_oid_req = obj_type | AclRule::INDIVIDUAL_ID;
963
    long long resource_gid_req = obj_type | AclRule::GROUP_ID;
964
    long long resource_all_req = obj_type | AclRule::ALL_ID;
965
    long long resource_cid_req = obj_type | AclRule::CLUSTER_ID;
966
    long long rights_req       = op;
967

    
968
    long long resource_oid_mask =
969
            ( obj_type | AclRule::INDIVIDUAL_ID );
970

    
971
    long long resource_gid_mask  =
972
            ( obj_type | AclRule::GROUP_ID );
973

    
974
    long long resource_cid_mask  =
975
            ( obj_type | AclRule::CLUSTER_ID );
976

    
977
    long long zone_oid_req =
978
            AclRule::INDIVIDUAL_ID | zone_id;
979

    
980
    long long zone_all_req = AclRule::ALL_ID;
981

    
982
    // Create a temporal rule, to log the request
983
    long long log_resource;
984

    
985
    log_resource = resource_all_req;
986

    
987
    AclRule log_rule(-1,
988
                     AclRule::INDIVIDUAL_ID | uid,
989
                     log_resource,
990
                     rights_req,
991
                     zone_oid_req);
992

    
993
    oss << "Reverse search request " << log_rule.to_str();
994
    NebulaLog::log("ACL",Log::DDEBUG,oss);
995

    
996
    // ---------------------------------------------------
997
    // Look for the rules that match
998
    // ---------------------------------------------------
999

    
1000
    vector<long long>           user_reqs;
1001
    vector<long long>::iterator reqs_it;
1002

    
1003
    set<int>::iterator  g_it;
1004

    
1005
    // rules that apply to everyone
1006
    user_reqs.push_back(AclRule::ALL_ID);
1007

    
1008
    // rules that apply to the individual user id
1009
    user_reqs.push_back(AclRule::INDIVIDUAL_ID | uid);
1010

    
1011
    // rules that apply to each one of the user's groups
1012
    for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
1013
    {
1014
        user_reqs.push_back(AclRule::GROUP_ID | *g_it);
1015
    }
1016

    
1017
    all = false;
1018

    
1019
    for (reqs_it = user_reqs.begin(); reqs_it != user_reqs.end(); reqs_it++)
1020
    {
1021
        lock();
1022

    
1023
        index = acl_rules.equal_range( *reqs_it );
1024

    
1025
        for ( it = index.first; it != index.second; it++)
1026
        {
1027
                // Rule grants the requested rights
1028
            if ( ( ( it->second->rights & rights_req ) == rights_req )
1029
                 &&
1030
                 // Rule applies in this zone or in all zones
1031
                 ( ( it->second->zone == zone_oid_req )
1032
                   ||
1033
                   ( it->second->zone == zone_all_req )
1034
                 )
1035
               )
1036
            {
1037
                oss.str("");
1038
                oss << "> Rule  " << it->second->to_str();
1039
                NebulaLog::log("ACL",Log::DDEBUG,oss);
1040

    
1041
                // Rule grants permission for all objects of this type
1042
                if ((!disable_all_acl) &&
1043
                    ((it->second->resource & resource_all_req) == resource_all_req))
1044
                {
1045
                    all = true;
1046
                    break;
1047
                }
1048
                // Rule grants permission for all objects of a group
1049
                else if ((!disable_group_acl) &&
1050
                         ((it->second->resource & resource_gid_mask) == resource_gid_req))
1051
                {
1052
                    gids.push_back(it->second->resource_id());
1053
                }
1054
                // Rule grants permission for all objects of a cluster
1055
                else if ((!disable_cluster_acl) &&
1056
                         ((it->second->resource & resource_cid_mask) == resource_cid_req))
1057
                {
1058
                    cids.push_back(it->second->resource_id());
1059
                }
1060
                // Rule grants permission for an individual object
1061
                else if ((it->second->resource & resource_oid_mask) == resource_oid_req)
1062
                {
1063
                    oids.push_back(it->second->resource_id());
1064
                }
1065
            }
1066
        }
1067

    
1068
        unlock();
1069

    
1070
        if ( all == true )
1071
        {
1072
            oids.clear();
1073
            gids.clear();
1074
            cids.clear();
1075
        }
1076
    }
1077
}
1078

    
1079
/* -------------------------------------------------------------------------- */
1080
/* -------------------------------------------------------------------------- */
1081

    
1082
int AclManager::bootstrap(SqlDB * _db)
1083
{
1084
    ostringstream oss(db_bootstrap);
1085

    
1086
    return _db->exec(oss);
1087
}
1088

    
1089
/* -------------------------------------------------------------------------- */
1090
/* -------------------------------------------------------------------------- */
1091

    
1092
void AclManager::update_lastOID()
1093
{
1094
    // db->escape_str is not used for 'table' since its name can't be set in
1095
    // any way by the user, it is hardcoded.
1096

    
1097
    ostringstream oss;
1098

    
1099
    oss << "REPLACE INTO pool_control (tablename, last_oid) VALUES ("
1100
        << "'" <<   table       << "',"
1101
        <<          lastOID     << ")";
1102

    
1103
    db->exec(oss);
1104
}
1105

    
1106
/* -------------------------------------------------------------------------- */
1107
/* -------------------------------------------------------------------------- */
1108

    
1109
int AclManager::select_cb(void *nil, int num, char **values, char **names)
1110
{
1111
    if ( (num != 5)   ||
1112
         (!values[0]) ||
1113
         (!values[1]) ||
1114
         (!values[2]) ||
1115
         (!values[3]) ||
1116
         (!values[4]) )
1117
    {
1118
        return -1;
1119
    }
1120

    
1121
    ostringstream oss;
1122
    istringstream iss;
1123

    
1124
    int oid = atoi(values[0]);
1125

    
1126
    long long rule_values[4];
1127

    
1128
    for ( int i = 0; i < 4; i++ )
1129
    {
1130
        iss.str( values[i+1] );
1131

    
1132
        iss >> rule_values[i];
1133

    
1134
        if ( iss.fail() == true )
1135
        {
1136
            return -1;
1137
        }
1138

    
1139
        iss.clear();
1140
    }
1141

    
1142
    AclRule * rule = new AclRule(oid,
1143
                                 rule_values[0],
1144
                                 rule_values[1],
1145
                                 rule_values[2],
1146
                                 rule_values[3]);
1147

    
1148
    oss << "Loading ACL Rule " << rule->to_str();
1149
    NebulaLog::log("ACL",Log::DDEBUG,oss);
1150

    
1151
    acl_rules.insert( make_pair(rule->user, rule) );
1152
    acl_rules_oids.insert( make_pair(rule->oid, rule) );
1153

    
1154
    return 0;
1155
}
1156

    
1157
/* -------------------------------------------------------------------------- */
1158
/* -------------------------------------------------------------------------- */
1159

    
1160
int AclManager::select()
1161
{
1162
    ostringstream   oss;
1163
    int             rc;
1164

    
1165
    oss << "SELECT " << db_names << " FROM " << table;
1166

    
1167
    set_callback(static_cast<Callbackable::Callback>(&AclManager::select_cb));
1168

    
1169
    lock();
1170

    
1171
    acl_rules.clear();
1172
    acl_rules_oids.clear();
1173

    
1174
    rc = db->exec(oss,this);
1175

    
1176
    unlock();
1177

    
1178
    unset_callback();
1179

    
1180
    return rc;
1181
}
1182

    
1183
/* -------------------------------------------------------------------------- */
1184
/* -------------------------------------------------------------------------- */
1185

    
1186
int AclManager::insert(AclRule * rule, SqlDB * db)
1187
{
1188
    ostringstream   oss;
1189
    int             rc;
1190

    
1191
    // Construct the SQL statement to Insert
1192

    
1193
    oss <<  "INSERT INTO "  << table <<" ("<< db_names <<") VALUES ("
1194
        <<  rule->oid       << ","
1195
        <<  rule->user      << ","
1196
        <<  rule->resource  << ","
1197
        <<  rule->rights    << ","
1198
        <<  rule->zone      << ")";
1199

    
1200
    rc = db->exec(oss);
1201

    
1202
    return rc;
1203
}
1204

    
1205
/* -------------------------------------------------------------------------- */
1206
/* -------------------------------------------------------------------------- */
1207

    
1208

    
1209
int AclManager::drop(int oid)
1210
{
1211
    ostringstream   oss;
1212
    int             rc;
1213

    
1214
    oss << "DELETE FROM " << table << " WHERE "
1215
        << "oid=" << oid;
1216

    
1217
    rc = db->exec(oss);
1218

    
1219
    return rc;
1220
}
1221

    
1222
/* -------------------------------------------------------------------------- */
1223
/* -------------------------------------------------------------------------- */
1224

    
1225
int AclManager::dump(ostringstream& oss)
1226
{
1227
    map<int, AclRule *>::iterator        it;
1228
    string xml;
1229

    
1230
    lock();
1231

    
1232
    oss << "<ACL_POOL>";
1233

    
1234
    for ( it = acl_rules_oids.begin() ; it != acl_rules_oids.end(); it++ )
1235
    {
1236
        oss << it->second->to_xml(xml);
1237
    }
1238

    
1239
    oss << "</ACL_POOL>";
1240

    
1241
    unlock();
1242

    
1243
    return 0;
1244
}
1245

    
1246
/* -------------------------------------------------------------------------- */
1247
/* -------------------------------------------------------------------------- */
1248

    
1249
void AclManager::do_action(const string &action, void * arg)
1250
{
1251
    if (action == ACTION_TIMER)
1252
    {
1253
        select();
1254
    }
1255
    else if (action == ACTION_FINALIZE)
1256
    {
1257
        NebulaLog::log("ACL",Log::INFO,"Stopping ACL Manager...");
1258
    }
1259
    else
1260
    {
1261
        ostringstream oss;
1262
        oss << "Unknown action name: " << action;
1263

    
1264
        NebulaLog::log("ACL", Log::ERROR, oss);
1265
    }
1266
}
1267

    
1268
/* -------------------------------------------------------------------------- */
1269
/* -------------------------------------------------------------------------- */