15
15
* limitations under the License.
16
16
*/
17
17
18
- use std:: sync:: { Arc , Mutex , MutexGuard , RwLock } ;
18
+ use std:: {
19
+ fmt:: Display ,
20
+ sync:: { Arc , Mutex , MutexGuard , RwLock } ,
21
+ } ;
19
22
20
23
use crate :: {
21
24
data_model:: objects:: { Access , Privilege } ,
@@ -24,6 +27,7 @@ use crate::{
24
27
interaction_model:: messages:: GenericPath ,
25
28
sys:: Psm ,
26
29
tlv:: { FromTLV , TLVElement , TLVList , TLVWriter , TagType , ToTLV } ,
30
+ transport:: session:: MAX_CAT_IDS_PER_NOC ,
27
31
utils:: writebuf:: WriteBuf ,
28
32
} ;
29
33
use log:: error;
@@ -67,23 +71,110 @@ impl ToTLV for AuthMode {
67
71
}
68
72
}
69
73
74
+ /// An accessor can have as many identities: one node id and Upto MAX_CAT_IDS_PER_NOC
75
+ const MAX_ACCESSOR_SUBJECTS : usize = 1 + MAX_CAT_IDS_PER_NOC ;
76
+ /// The CAT Prefix used in Subjects
77
+ pub const NOC_CAT_SUBJECT_PREFIX : u64 = 0xFFFF_FFFD_0000_0000 ;
78
+ const NOC_CAT_ID_MASK : u64 = 0xFFFF_0000 ;
79
+ const NOC_CAT_VERSION_MASK : u64 = 0xFFFF ;
80
+
81
+ fn is_noc_cat ( id : u64 ) -> bool {
82
+ ( id & NOC_CAT_SUBJECT_PREFIX ) == NOC_CAT_SUBJECT_PREFIX
83
+ }
84
+
85
+ fn get_noc_cat_id ( id : u64 ) -> u64 {
86
+ ( id & NOC_CAT_ID_MASK ) >> 16
87
+ }
88
+
89
+ fn get_noc_cat_version ( id : u64 ) -> u64 {
90
+ id & NOC_CAT_VERSION_MASK
91
+ }
92
+
93
+ pub fn gen_noc_cat ( id : u16 , version : u16 ) -> u64 {
94
+ NOC_CAT_SUBJECT_PREFIX | ( ( id as u64 ) << 16 ) | version as u64
95
+ }
96
+
97
+ pub struct AccessorSubjects ( [ u64 ; MAX_ACCESSOR_SUBJECTS ] ) ;
98
+
99
+ impl AccessorSubjects {
100
+ pub fn new ( id : u64 ) -> Self {
101
+ let mut a = Self ( Default :: default ( ) ) ;
102
+ a. 0 [ 0 ] = id;
103
+ a
104
+ }
105
+
106
+ pub fn add ( & mut self , subject : u64 ) -> Result < ( ) , Error > {
107
+ for ( i, val) in self . 0 . iter ( ) . enumerate ( ) {
108
+ if * val == 0 {
109
+ self . 0 [ i] = subject;
110
+ return Ok ( ( ) ) ;
111
+ }
112
+ }
113
+ Err ( Error :: NoSpace )
114
+ }
115
+
116
+ /// Match the match_subject with any of the current subjects
117
+ /// If a NOC CAT is specified, CAT aware matching is also performed
118
+ pub fn matches ( & self , acl_subject : u64 ) -> bool {
119
+ for v in self . 0 . iter ( ) {
120
+ if * v == 0 {
121
+ continue ;
122
+ }
123
+
124
+ if * v == acl_subject {
125
+ return true ;
126
+ } else {
127
+ // NOC CAT match
128
+ if is_noc_cat ( * v)
129
+ && is_noc_cat ( acl_subject)
130
+ && ( get_noc_cat_id ( * v) == get_noc_cat_id ( acl_subject) )
131
+ && ( get_noc_cat_version ( * v) >= get_noc_cat_version ( acl_subject) )
132
+ {
133
+ return true ;
134
+ }
135
+ }
136
+ }
137
+
138
+ false
139
+ }
140
+ }
141
+
142
+ impl Display for AccessorSubjects {
143
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: result:: Result < ( ) , std:: fmt:: Error > {
144
+ write ! ( f, "[" ) ?;
145
+ for i in self . 0 {
146
+ if is_noc_cat ( i) {
147
+ write ! ( f, "CAT({} - {})" , get_noc_cat_id( i) , get_noc_cat_version( i) ) ?;
148
+ } else if i != 0 {
149
+ write ! ( f, "{}, " , i) ?;
150
+ }
151
+ }
152
+ write ! ( f, "]" )
153
+ }
154
+ }
155
+
70
156
/// The Accessor Object
71
157
pub struct Accessor {
72
158
/// The fabric index of the accessor
73
159
pub fab_idx : u8 ,
74
- /// Accessor's identified : could be node-id, NoC CAT, group id
75
- id : u64 ,
160
+ /// Accessor's subject : could be node-id, NoC CAT, group id
161
+ subjects : AccessorSubjects ,
76
162
/// The Authmode of this session
77
163
auth_mode : AuthMode ,
78
164
// TODO: Is this the right place for this though, or should we just use a global-acl-handle-get
79
165
acl_mgr : Arc < AclMgr > ,
80
166
}
81
167
82
168
impl Accessor {
83
- pub fn new ( fab_idx : u8 , id : u64 , auth_mode : AuthMode , acl_mgr : Arc < AclMgr > ) -> Self {
169
+ pub fn new (
170
+ fab_idx : u8 ,
171
+ subjects : AccessorSubjects ,
172
+ auth_mode : AuthMode ,
173
+ acl_mgr : Arc < AclMgr > ,
174
+ ) -> Self {
84
175
Self {
85
176
fab_idx,
86
- id ,
177
+ subjects ,
87
178
auth_mode,
88
179
acl_mgr,
89
180
}
@@ -215,7 +306,7 @@ impl AclEntry {
215
306
let mut entries_exist = false ;
216
307
for i in self . subjects . iter ( ) . flatten ( ) {
217
308
entries_exist = true ;
218
- if accessor. id == * i {
309
+ if accessor. subjects . matches ( * i ) {
219
310
allow = true ;
220
311
}
221
312
}
@@ -467,8 +558,8 @@ impl AclMgr {
467
558
}
468
559
}
469
560
error ! (
470
- "ACL Disallow for src id {} fab idx {}" ,
471
- req. accessor. id , req. accessor. fab_idx
561
+ "ACL Disallow for subjects {} fab idx {}" ,
562
+ req. accessor. subjects , req. accessor. fab_idx
472
563
) ;
473
564
error ! ( "{}" , self ) ;
474
565
false
@@ -490,6 +581,7 @@ impl std::fmt::Display for AclMgr {
490
581
#[ allow( clippy:: bool_assert_comparison) ]
491
582
mod tests {
492
583
use crate :: {
584
+ acl:: { gen_noc_cat, AccessorSubjects } ,
493
585
data_model:: objects:: { Access , Privilege } ,
494
586
interaction_model:: messages:: GenericPath ,
495
587
} ;
@@ -501,7 +593,7 @@ mod tests {
501
593
fn test_basic_empty_subject_target ( ) {
502
594
let am = Arc :: new ( AclMgr :: new_with ( false ) . unwrap ( ) ) ;
503
595
am. erase_all ( ) ;
504
- let accessor = Accessor :: new ( 2 , 112233 , AuthMode :: Case , am. clone ( ) ) ;
596
+ let accessor = Accessor :: new ( 2 , AccessorSubjects :: new ( 112233 ) , AuthMode :: Case , am. clone ( ) ) ;
505
597
let path = GenericPath :: new ( Some ( 1 ) , Some ( 1234 ) , None ) ;
506
598
let mut req = AccessReq :: new ( & accessor, & path, Access :: READ ) ;
507
599
req. set_target_perms ( Access :: RWVA ) ;
@@ -529,7 +621,7 @@ mod tests {
529
621
fn test_subject ( ) {
530
622
let am = Arc :: new ( AclMgr :: new_with ( false ) . unwrap ( ) ) ;
531
623
am. erase_all ( ) ;
532
- let accessor = Accessor :: new ( 2 , 112233 , AuthMode :: Case , am. clone ( ) ) ;
624
+ let accessor = Accessor :: new ( 2 , AccessorSubjects :: new ( 112233 ) , AuthMode :: Case , am. clone ( ) ) ;
533
625
let path = GenericPath :: new ( Some ( 1 ) , Some ( 1234 ) , None ) ;
534
626
let mut req = AccessReq :: new ( & accessor, & path, Access :: READ ) ;
535
627
req. set_target_perms ( Access :: RWVA ) ;
@@ -547,11 +639,79 @@ mod tests {
547
639
assert_eq ! ( req. allow( ) , true ) ;
548
640
}
549
641
642
+ #[ test]
643
+ fn test_cat ( ) {
644
+ let am = Arc :: new ( AclMgr :: new_with ( false ) . unwrap ( ) ) ;
645
+ am. erase_all ( ) ;
646
+
647
+ let allow_cat = 0xABCD ;
648
+ let disallow_cat = 0xCAFE ;
649
+ let v2 = 2 ;
650
+ let v3 = 3 ;
651
+ // Accessor has nodeif and CAT 0xABCD_0002
652
+ let mut subjects = AccessorSubjects :: new ( 112233 ) ;
653
+ subjects. add ( gen_noc_cat ( allow_cat, v2) ) . unwrap ( ) ;
654
+
655
+ let accessor = Accessor :: new ( 2 , subjects, AuthMode :: Case , am. clone ( ) ) ;
656
+ let path = GenericPath :: new ( Some ( 1 ) , Some ( 1234 ) , None ) ;
657
+ let mut req = AccessReq :: new ( & accessor, & path, Access :: READ ) ;
658
+ req. set_target_perms ( Access :: RWVA ) ;
659
+
660
+ // Deny for CAT id mismatch
661
+ let mut new = AclEntry :: new ( 2 , Privilege :: VIEW , AuthMode :: Case ) ;
662
+ new. add_subject ( gen_noc_cat ( disallow_cat, v2) ) . unwrap ( ) ;
663
+ am. add ( new) . unwrap ( ) ;
664
+ assert_eq ! ( req. allow( ) , false ) ;
665
+
666
+ // Deny of CAT version mismatch
667
+ let mut new = AclEntry :: new ( 2 , Privilege :: VIEW , AuthMode :: Case ) ;
668
+ new. add_subject ( gen_noc_cat ( allow_cat, v3) ) . unwrap ( ) ;
669
+ am. add ( new) . unwrap ( ) ;
670
+ assert_eq ! ( req. allow( ) , false ) ;
671
+
672
+ // Allow for CAT match
673
+ let mut new = AclEntry :: new ( 2 , Privilege :: VIEW , AuthMode :: Case ) ;
674
+ new. add_subject ( gen_noc_cat ( allow_cat, v2) ) . unwrap ( ) ;
675
+ am. add ( new) . unwrap ( ) ;
676
+ assert_eq ! ( req. allow( ) , true ) ;
677
+ }
678
+
679
+ #[ test]
680
+ fn test_cat_version ( ) {
681
+ let am = Arc :: new ( AclMgr :: new_with ( false ) . unwrap ( ) ) ;
682
+ am. erase_all ( ) ;
683
+
684
+ let allow_cat = 0xABCD ;
685
+ let disallow_cat = 0xCAFE ;
686
+ let v2 = 2 ;
687
+ let v3 = 3 ;
688
+ // Accessor has nodeif and CAT 0xABCD_0003
689
+ let mut subjects = AccessorSubjects :: new ( 112233 ) ;
690
+ subjects. add ( gen_noc_cat ( allow_cat, v3) ) . unwrap ( ) ;
691
+
692
+ let accessor = Accessor :: new ( 2 , subjects, AuthMode :: Case , am. clone ( ) ) ;
693
+ let path = GenericPath :: new ( Some ( 1 ) , Some ( 1234 ) , None ) ;
694
+ let mut req = AccessReq :: new ( & accessor, & path, Access :: READ ) ;
695
+ req. set_target_perms ( Access :: RWVA ) ;
696
+
697
+ // Deny for CAT id mismatch
698
+ let mut new = AclEntry :: new ( 2 , Privilege :: VIEW , AuthMode :: Case ) ;
699
+ new. add_subject ( gen_noc_cat ( disallow_cat, v2) ) . unwrap ( ) ;
700
+ am. add ( new) . unwrap ( ) ;
701
+ assert_eq ! ( req. allow( ) , false ) ;
702
+
703
+ // Allow for CAT match and version more than ACL version
704
+ let mut new = AclEntry :: new ( 2 , Privilege :: VIEW , AuthMode :: Case ) ;
705
+ new. add_subject ( gen_noc_cat ( allow_cat, v2) ) . unwrap ( ) ;
706
+ am. add ( new) . unwrap ( ) ;
707
+ assert_eq ! ( req. allow( ) , true ) ;
708
+ }
709
+
550
710
#[ test]
551
711
fn test_target ( ) {
552
712
let am = Arc :: new ( AclMgr :: new_with ( false ) . unwrap ( ) ) ;
553
713
am. erase_all ( ) ;
554
- let accessor = Accessor :: new ( 2 , 112233 , AuthMode :: Case , am. clone ( ) ) ;
714
+ let accessor = Accessor :: new ( 2 , AccessorSubjects :: new ( 112233 ) , AuthMode :: Case , am. clone ( ) ) ;
555
715
let path = GenericPath :: new ( Some ( 1 ) , Some ( 1234 ) , None ) ;
556
716
let mut req = AccessReq :: new ( & accessor, & path, Access :: READ ) ;
557
717
req. set_target_perms ( Access :: RWVA ) ;
@@ -612,7 +772,8 @@ mod tests {
612
772
fn test_privilege ( ) {
613
773
let am = Arc :: new ( AclMgr :: new_with ( false ) . unwrap ( ) ) ;
614
774
am. erase_all ( ) ;
615
- let accessor = Accessor :: new ( 2 , 112233 , AuthMode :: Case , am. clone ( ) ) ;
775
+
776
+ let accessor = Accessor :: new ( 2 , AccessorSubjects :: new ( 112233 ) , AuthMode :: Case , am. clone ( ) ) ;
616
777
let path = GenericPath :: new ( Some ( 1 ) , Some ( 1234 ) , None ) ;
617
778
618
779
// Create an Exact Match ACL with View privilege
0 commit comments