Added acl.grant and acl.revoke functions.
[py-rsbac] / rsbac / acl.py
1 # -*- coding:utf-8 -*-
2
3 # py-rsbac - RSBAC Python bindings
4 # Copyright (C) 2006  Frederic Jolliton <pyrsbac@tuxee.net>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 __all__ = [ 'Group' , 'groups' ]
21
22 def export( o ) :
23     if not isinstance( o , basestring ) :
24         name = o.__name__
25     else :
26         name , o = o , None
27     if name in __all__ :
28         raise ImportError , 'duplicate name %r in module %r' % ( name , __name__ )
29     __all__.append( name )
30     return o
31
32 from ctypes import byref, pointer
33
34 from rsbac import headers, lib, transaction
35 from rsbac._data import AclRequestVector
36 from rsbac.errors import raiseIfError, Error
37 from rsbac._utils import fetch, intToTtl, ttlToInt, unlimitedTtl, unchangedTtl
38
39 g_aclSyscallArg = headers.rsbac_acl_syscall_arg_t()
40 g_aclSyscallArgRef = byref( g_aclSyscallArg )
41
42 g_aclSyscallByNameArg = headers.rsbac_acl_syscall_n_arg_t()
43 g_aclSyscallByNameArgRef = byref( g_aclSyscallByNameArg )
44
45 # for acl_remove_user
46 g_targetId = headers.rsbac_target_id_t()
47
48 @export
49 def grant( subject , object , requests ) :
50     """Grant 'requests' to 'subject' for the given 'object'.
51
52     subject -- RC Role, User or ACL Group
53     object -- Object
54     requests -- RequestVector
55
56     """
57     rights , ttl = object.acl[ subject ]
58     rights |= AclRequestVector( requests )
59     object.acl[ subject ] = rights , unchangedTtl
60
61 @export
62 def revoke( subject , object , requests ) :
63     """Revoke 'requests' to '' for the given 'type'.
64
65     subject -- RC Role, User or ACL Group
66     object -- Object
67     requests -- RequestVector
68
69     """
70     rights , ttl = object.acl[ subject ]
71     rights &= ~AclRequestVector( requests )
72     object.acl[ subject ] = rights , unchangedTtl
73
74 def _acl_preset( target , tid , subjectType , subjectId , rights , ttl ) :
75     g_aclSyscallArg.target = target
76     g_aclSyscallArg.tid = tid
77     g_aclSyscallArg.subj_type = subjectType
78     g_aclSyscallArg.subj_id = subjectId
79     g_aclSyscallArg.rights = rights
80     g_aclSyscallArg.ttl = ttl
81     return g_aclSyscallArgRef
82
83 def _acl_preset_n( target , name , subjectType , subjectId , rights , ttl ) :
84     g_aclSyscallByNameArg.target = target
85     g_aclSyscallByNameArg.name = name
86     g_aclSyscallByNameArg.subj_type = subjectType
87     g_aclSyscallByNameArg.subj_id = subjectId
88     g_aclSyscallByNameArg.rights = rights
89     g_aclSyscallByNameArg.ttl = ttl
90     return g_aclSyscallByNameArgRef
91
92 def _to_acl_subject( object ) :
93     from rsbac.objects import User
94     if isinstance( object , Role ) :
95         return headers.ACLS_ROLE , object._role
96     elif isinstance( object , User ) :
97         return headers.ACLS_USER , object.uid
98     elif isinstance( object , Group ) :
99         return headers.ACLS_GROUP , object._id
100     else :
101         raise RuntimeError , 'unexpected ACL subject of type %r' % ( object.__class__ , )
102
103 def _from_acl_subject( type , id ) :
104     if type == headers.ACLS_USER :
105         return User( id )
106     elif type == headers.ACLS_ROLE :
107         return Role( id )
108     elif type == headers.ACLS_GROUP :
109         return Group( id )
110     else :
111         raise RuntimeError , 'unexpected subject type %r' % ( type , )
112
113 #
114 # set_acl_entry
115 #
116
117 def setAclEntryById( target , subject , rights , ttl = unlimitedTtl ) :
118     st , si = _to_acl_subject( subject )
119     raiseIfError( lib.rsbac_acl( transaction._t ,
120                                  headers.ACLC_set_acl_entry ,
121                                  _acl_preset( target.type , target._id._obj ,
122                                               st , si ,
123                                               int( rights ) , ttlToInt( ttl ) ) ) )
124
125 def setAclEntryByName( target , subject , rights , ttl = unlimitedTtl ) :
126     st , si = _to_acl_subject( subject )
127     raiseIfError( lib.rsbac_acl_n( transaction._t ,
128                                    headers.ACLC_set_acl_entry ,
129                                    _acl_preset_n( target.type , target._id ,
130                                                   st , si ,
131                                                   int( rights ) , ttlToInt( ttl ) ) ) )
132
133 #
134 # remove_acl_entry
135 #
136
137 def removeAclEntryById( target , subject ) :
138     st , si = _to_acl_subject( subject )
139     raiseIfError( lib.rsbac_acl( transaction._t ,
140                                  headers.ACLC_remove_acl_entry ,
141                                  _acl_preset( target.type , target._id._obj ,
142                                               st , si ,
143                                               0 , 0 ) ) )
144
145 def removeAclEntryByName( target , subject ) :
146     st , si = _to_acl_subject( subject )
147     raiseIfError( lib.rsbac_acl_n( transaction._t ,
148                                    headers.ACLC_remove_acl_entry ,
149                                    _acl_preset_n( target.type , target._id ,
150                                                   st , si ,
151                                                   0 , 0 ) ) )
152
153 #
154 # remove_acl
155 #
156
157 def removeAclById( target ) :
158     raiseIfError( lib.rsbac_acl( transaction._t ,
159                                  headers.ACLC_remove_acl ,
160                                  _acl_preset( target.type , target._id._obj ,
161                                               0 , 0 , 0 , 0 ) ) )
162
163 def removeAclByName( target ) :
164     raiseIfError( lib.rsbac_acl_n( transaction._t ,
165                                    headers.ACLC_remove_acl ,
166                                    _acl_preset_n( target.type , target._id ,
167                                                   0 , 0 , 0 , 0 ) ) )
168
169 # add_to_acl_entry
170 # remove_from_acl_entry
171
172 #
173 # set_mask
174 #
175
176 def setAclMaskById( target , mask ) :
177     raiseIfError( lib.rsbac_acl( transaction._t ,
178                                  headers.ACLC_remove_acl ,
179                                  _acl_preset( target.type , target._id._obj ,
180                                               0 , 0 ,
181                                               mask , 0 ) ) )
182
183 def setAclMaskByName( target , mask ) :
184     raiseIfError( lib.rsbac_acl_n( transaction._t ,
185                                    headers.ACLC_remove_acl ,
186                                    _acl_preset_n( target.type , target._id ,
187                                                   0 , 0 ,
188                                                   mask , 0 ) ) )
189
190 #
191 # remove_user
192 #
193
194 @export
195 def aclRemoveUser( user ) :
196     """Remove user from all groups and all ACLs.
197
198     user -- UID as integer
199
200     """
201     g_targetId.user = user
202     raiseIfError( lib.rsbac_acl( transaction._t ,
203                                  headers.ACLC_remove_user ,
204                                  _acl_preset( headers.T_USER , g_targetId ,
205                                               0 , 0 , 0 , 0 ) ) )
206
207 #
208 # get_acl_rights
209 #
210
211 def getAclRightsById( target , subject , effective = False ) :
212     st , si = _to_acl_subject( subject )
213     rights = headers.rsbac_acl_rights_vector_t()
214     raiseIfError( lib.rsbac_acl_get_rights( transaction._t ,
215                                             _acl_preset( target.type , target._id._obj ,
216                                                          st , si ,
217                                                          0 , 0 ) ,
218                                             byref( rights ) ,
219                                             effective ) )
220     return AclRequestVector( rights.value )
221
222 def getAclRightsByName( target , subject , effective = False ) :
223     st , si = _to_acl_subject( subject )
224     rights = headers.rsbac_acl_rights_vector_t()
225     raiseIfError( lib.rsbac_acl_get_rights_n( transaction._t ,
226                                               _acl_preset_n( target.type , target._id ,
227                                                              st , si ,
228                                                              0 , 0 ) ,
229                                               byref( rights ) ,
230                                               effective ) )
231     return AclRequestVector( rights.value )
232
233 #
234 # acl_get_tlist
235 #
236
237 def _unpackAclTlist( entries , ttls ) :
238     return [ ( _from_acl_subject( entry.subj_type , entry.subj_id ) ,
239                AclRequestVector( entry.rights ) ,
240                intToTtl( ttl ) )
241              for entry , ttl in zip( entries , ttls ) ]
242
243 def getAclTargetListById( target ) :
244     arrs = fetch( ( headers.rsbac_acl_entry_t ,
245                     headers.rsbac_time_t ) ,
246                   lambda n , a , b : lib.rsbac_acl_get_tlist( transaction._t ,
247                                                               target.type ,
248                                                               target._id._obj ,
249                                                               a , b , n ) ,
250                   32 )
251     return _unpackAclTlist( *arrs )
252
253 def getAclTargetListByName( target ) :
254     arrs = fetch( ( headers.rsbac_acl_entry_t ,
255                     headers.rsbac_time_t ) ,
256                   lambda n , a , b : lib.rsbac_acl_get_tlist_n( transaction._t ,
257                                                                 target.type ,
258                                                                 target._id ,
259                                                                 a , b , n ) ,
260                   32 )
261     return _unpackAclTlist( *arrs )
262
263 #
264 # acl_get_mask
265 #
266
267 def getAclMaskById( target ) :
268     rights = headers.rsbac_acl_rights_vector_t()
269     raiseIfError( lib.rsbac_acl_get_mask( transaction._t ,
270                                           target.type , target._id._obj ,
271                                           byref( rights ) ) )
272     return AclRequestVector( rights.value )
273
274 def getAclMaskByName( target ) :
275     rights = headers.rsbac_acl_rights_vector_t()
276     raiseIfError( lib.rsbac_acl_get_mask_n( transaction._t ,
277                                             target.type , target._id ,
278                                             byref( rights ) ) )
279     return AclRequestVector( rights.value )
280
281 #
282 # dispatchers
283 #
284
285 @export
286 def setAclEntry( target , subject , rights , ttl = unlimitedTtl ) :
287     """Set an ACL entry for a target-subject couple.
288
289     target -- Object
290     subject -- either an instance of objects.User, acl.Group or rc.Role.
291     rights -- AclRequestVector
292     ttl -- TTL
293
294     """
295     if target._byName :
296         return setAclEntryByName( target , subject , rights , ttl )
297     else :
298         return setAclEntryById( target , subject , rights , ttl )
299
300 @export
301 def removeAclEntry( target , subject ) :
302     """Remove an ACL entry.
303
304     target -- Object
305     subject -- either an instance of objects.User, acl.Group or rc.Role.
306
307     """
308     if target._byName :
309         return removeAclEntryByName( target , subject )
310     else :
311         return removeAclEntryById( target , subject )
312
313 @export
314 def removeAcl( target ) :
315     """Remove all ACL entries on a target.
316
317     target -- Object
318
319     """
320     if target._byName :
321         return removeAclByName( target )
322     else :
323         return removeAclById( target )
324
325 @export
326 def setAclMask( target , mask ) :
327     """Set ACL mask on a target.
328
329     target -- Object
330     mask -- AclRequestVector
331
332     """
333     if target._byName :
334         return setAclMaskByName( target , mask )
335     else :
336         return setAclMaskById( target , mask )
337
338 @export
339 def getAclRights( target , subject , effective = False ) :
340     """Get ACL rights for a target-subject couple.
341
342     target -- Object
343     subject -- either an instance of objects.User, acl.Group or rc.Role.
344     effective -- True to retrieve effective rights, False otherwise.
345
346     Returns an AclRequestVector.
347
348     """
349     if target._byName :
350         return getAclRightsByName( target , subject , effective )
351     else :
352         return getAclRightsById( target , subject , effective )
353
354 @export
355 def getAclMask( target ) :
356     """Get ACL mask for a target.
357
358     target -- Object
359
360     Returns an AclRequestVector.
361
362     """
363     if target._byName :
364         return getAclMaskByName( target , mask )
365     else :
366         return getAclMaskById( target , mask )
367
368 @export
369 def getAclTargetList( target ) :
370     """Get all ACL entries for a target.
371
372     target -- Object
373
374     Returns a list of 3-tuple (Object, AclRequestVector, ttl).
375
376     """
377     if target._byName :
378         return getAclTargetListByName( target )
379     else :
380         return getAclTargetListById( target )
381
382 class AclBase( object ) :
383     __slots__ = ( 'target' , )
384     def __init__( self , target ) :
385         object.__init__( self )
386         self.target = target
387     def __len__( self ) :
388         return len( self._list() )
389     def __iter__( self ) :
390         return iter( self.keys() )
391     def __repr__( self ) :
392         return '<ACL for %s: %d entries>' % ( repr( self.target ).strip( '<>' ) , len( self ) )
393     def keys( self ) :
394         return [ e[ 0 ] for e in self._list() ]
395     def values( self ) :
396         return [ ( e[ 1 ] , e[ 2 ] ) for e in self._list() ]
397     def items( self ) :
398         return [ ( e[ 0 ] , ( e[ 1 ] , e[ 2 ] ) ) for e in self._list() ]
399
400 class AclById( AclBase ) :
401     __slots__ = ()
402     def _list( self ) :
403         return getAclTargetListById( self.target )
404     def __getitem__( self , subject ) :
405         # FIXME: temporary solution. Waiting for an O(1) way to get
406         # (right,TTL) couple.
407         for k , v in self.items() :
408             if k == subject :
409                 return v
410         return getAclRightsById( self.target , subject ) , False
411     def __setitem__( self , subject , value ) :
412         if not isinstance( value , tuple ) :
413             value = value , None
414         rights , ttl = value
415         setAclEntryById( self.target , subject , rights , ttl )
416     def __delitem__( self , subject ) :
417         removeAclEntryById( self.target , subject )
418     # def update( self ) : pass
419     def clear( self ) :
420         # FIXME: temporary solution. Should sys_rsbac_remove_acl
421         # handle T_PROCESS instead?
422         if isinstance( self.target , Process ) :
423             map( self.__delitem__ , self )
424         else :
425             removeAclById( self.target )
426
427 class AclByName( AclBase ) :
428     __slots__ = ()
429     def _list( self ) :
430         return getAclTargetListByName( self.target )
431     def __iter__( self ) :
432         return ( n[ 0 ] for n in self.__list() )
433     def __getitem__( self , subject ) :
434         # FIXME: temporary solution. Waiting for an O(1) way to get
435         # (right,TTL) couple.
436         for k , v in self.items() :
437             if k == subject :
438                 return v
439         return getAclRightsByName( self.target , subject ) , False
440     def __setitem__( self , subject , value ) :
441         if not isinstance( value , tuple ) :
442             value = value , None
443         rights , ttl = value
444         setAclEntryByName( self.target , subject , rights , ttl )
445     def __delitem__( self , subject ) :
446         removeAclEntryByName( self.target , subject )
447     def clear( self ) :
448         removeAclByName( self.target )
449
450 class EffectiveAclById( AclBase ) :
451     __slots__ = ()
452     def _list( self ) :
453         return getAclTargetListById( self.target )
454     def __iter__( self ) :
455         return ( n[ 0 ] for n in self.__list() )
456     def __getitem__( self , subject ) :
457         return getAclRightsById( self.target , subject , True ) , False
458
459 class EffectiveAclByName( AclBase ) :
460     __slots__ = ()
461     def _list( self ) :
462         return getAclTargetListByName( self.target )
463     def __iter__( self ) :
464         return ( n[ 0 ] for n in self.__list() )
465     def __getitem__( self , subject ) :
466         return getAclRightsByName( self.target , subject , True ) , False
467
468 #--[ Group ]------------------------------------------------------------------
469
470 @export
471 def addGroup( name , type = headers.ACLG_PRIVATE , id = None ) :
472     """Add an ACL group.
473
474     type -- type of group (either ACLG_GLOBAL or ACLG_PRIVATE)
475     name -- group name as string
476     id -- a positive integer or None (automatic ID)
477
478     Returns the ID of the new group.
479
480     """
481     if id is None :
482         id = 0
483     id_ = headers.rsbac_acl_group_id_t()
484     id_.value = id
485     arg = headers.rsbac_acl_group_syscall_arg_t()
486     arg.add_group.type = type
487     arg.add_group.name = name
488     arg.add_group.group_id_p = pointer( id_ )
489     raiseIfError( lib.rsbac_acl_group( transaction._t ,
490                                        headers.ACLGS_add_group ,
491                                        byref( arg ) ) )
492     return int( id_.value )
493
494 @export
495 def addGlobalGroup( name , id = None ) :
496     """Add an global ACL group.
497
498     name -- group name as string
499     id -- a positive integer or None (automatic ID)
500
501     Returns the ID of the new group.
502
503     """
504     return addGroup( name , headers.ACLG_GLOBAL , id )
505
506 @export
507 def addPrivateGroup( name , id = None ) :
508     """Add an private ACL group.
509
510     name -- group name as string
511     id -- a positive integer or None (automatic ID)
512
513     Returns the ID of the new group.
514
515     """
516     return addGroup( name , headers.ACLG_PRIVATE , id )
517
518 @export
519 def changeGroup( id , owner , type , name ) :
520     """Change ACL group attributes.
521
522     Change the owner, type and name of an existing ACL group.
523
524     id -- ACL group as integer
525     owner -- user as integer
526     type -- either headers.ACLG_PRIVATE or headers.ACLG_GLOBAL
527     name -- group name
528
529     """
530     arg = headers.rsbac_acl_group_syscall_arg_t()
531     arg.change_group.id = id
532     arg.change_group.owner = owner
533     arg.change_group.type = type
534     arg.change_group.name = name
535     raiseIfError( lib.rsbac_acl_group( transaction._t ,
536                                        headers.ACLGS_change_group ,
537                                        byref( arg ) ) )
538
539 @export
540 def removeGroup( id ) :
541     """Remove an ACL group.
542
543     id -- ACL group as integer
544
545     """
546     arg = headers.rsbac_acl_group_syscall_arg_t()
547     arg.remove_group.id = id
548     raiseIfError( lib.rsbac_acl_group( transaction._t ,
549                                        headers.ACLGS_remove_group ,
550                                        byref( arg ) ) )
551
552 def _unpackEntry( entry ) :
553     return int( entry.id ) , int( entry.owner ) , int( entry.type ) , entry.name
554
555 @export
556 def getGroupEntry( id ) :
557     """Get group entry attributes.
558
559     id -- ACL group as integer
560
561     Returns a tuple with 4 attributes: id, owner, type and name.
562
563     """
564     entry = headers.rsbac_acl_group_entry_t()
565     arg = headers.rsbac_acl_group_syscall_arg_t()
566     arg.get_group_entry.id = id
567     arg.get_group_entry.entry_p = pointer( entry )
568     raiseIfError( lib.rsbac_acl_group( transaction._t ,
569                                        headers.ACLGS_get_group_entry ,
570                                        byref( arg ) ) )
571     return _unpackEntry( entry )
572
573 def _listGroups( includeGlobal , arr , n ) :
574     arg = headers.rsbac_acl_group_syscall_arg_t()
575     arg.list_groups.include_global = includeGlobal
576     arg.list_groups.group_entry_array = arr
577     arg.list_groups.maxnum = n
578     return raiseIfError( lib.rsbac_acl_group( transaction._t ,
579                                               headers.ACLGS_list_groups ,
580                                               byref( arg ) ) )
581
582 # FIXME: Other groups may be viewed/changed while not listed by
583 # _listGroups (the groups belonging to other users.)
584 @export
585 def getGroupList( includeGlobal = False ) :
586     """Get the list of ACL groups.
587
588     includeGlobal -- boolean. If True, include global groups.
589
590     Returns list of group ID.
591
592     """
593     arr = fetch( headers.rsbac_acl_group_entry_t ,
594                  lambda n , a : _listGroups( includeGlobal , a , n ) ,
595                  32 )
596     return map( _unpackEntry , arr )
597
598 @export
599 def addGroupMember( group , user , ttl = unlimitedTtl ) :
600     """Add a member to an ACL group.
601
602     group -- ACL group as integer
603     user -- user as integer
604     ttl -- TTL
605
606     """
607     arg = headers.rsbac_acl_group_syscall_arg_t()
608     arg.add_member.group = int( group )
609     arg.add_member.user = int( user )
610     arg.add_member.ttl = ttlToInt( ttl )
611     return raiseIfError( lib.rsbac_acl_group( transaction._t ,
612                                               headers.ACLGS_add_member ,
613                                               byref( arg ) ) )
614
615 @export
616 def removeGroupMember( group , user ) :
617     """Remove a member from an ACL group.
618
619     group -- ACL group as integer
620     user -- user as integer
621
622     """
623     arg = headers.rsbac_acl_group_syscall_arg_t()
624     arg.remove_member.group = int( group )
625     arg.remove_member.user = int( user )
626     return raiseIfError( lib.rsbac_acl_group( transaction._t ,
627                                               headers.ACLGS_remove_member ,
628                                               byref( arg ) ) )
629
630 def _getUserGroups( user , groups , ttls , n ) :
631     arg = headers.rsbac_acl_group_syscall_arg_t()
632     arg.get_user_groups.user = user
633     arg.get_user_groups.group_array = groups
634     arg.get_user_groups.ttl_array = ttls
635     arg.get_user_groups.maxnum = n
636     return raiseIfError( lib.rsbac_acl_group( transaction._t ,
637                                               headers.ACLGS_get_user_groups ,
638                                               byref( arg ) ) )
639
640 @export
641 def getUserGroups( uid ) :
642     """Get the ACL groups to which a user belong.
643
644     uid -- user as integer
645
646     Returns a list of pair (id,ttl).
647
648     """
649     arrs = fetch( ( headers.rsbac_acl_group_id_t ,
650                     headers.rsbac_time_t ) ,
651                   lambda n , a , b : _getUserGroups( uid , a , b , n ) ,
652                   32 )
653     return [ ( int( a ) , int( b ) ) for a , b in zip( *arrs ) ]
654
655 def _getGroupMembers( group , users , ttls , n ) :
656     arg = headers.rsbac_acl_group_syscall_arg_t()
657     arg.get_group_members.group = group
658     arg.get_group_members.user_array = users
659     arg.get_group_members.ttl_array = ttls
660     arg.get_group_members.maxnum = n
661     return raiseIfError( lib.rsbac_acl_group( transaction._t ,
662                                               headers.ACLGS_get_group_members ,
663                                               byref( arg ) ) )
664
665 @export
666 def getGroupMembers( id ) :
667     """Get the members of the given ACL group.
668
669     id -- ACL group
670
671     Returns a list of pair (uid,ttl).
672
673     """
674     arrs = fetch( ( headers.rsbac_uid_t ,
675                     headers.rsbac_time_t ) ,
676                   lambda n , a , b : _getGroupMembers( id , a , b , n ) ,
677                   32 )
678     return [ ( int( a ) , intToTtl( b ) ) for a , b in zip( *arrs ) ]
679
680 class AclGroupMembersTtlDictProxy( object ) :
681     __slots__ = ( '__group' , )
682     def __init__( self , id ) :
683         self.__group = id
684     def __getitem__( self , user ) :
685         for uid , ttl in getGroupMembers( self.__group ) :
686             if uid == user :
687                 return ttl
688         return False
689     def __setitem__( self , user , value ) :
690         addGroupMember( self.__group , user , value )
691     def __iter__( self ) :
692         return ( n[ 0 ] for n in getGroupMembers( self.__group ) )
693     def __repr__( self ) :
694         r = []
695         for user , ttl in getGroupMembers( self.__group ) :
696             if ttl is True :
697                 r.append( str( user ) )
698             else :
699                 r.append( '%s(%ds)' % ( user , ttl ) )
700         return '<Members for ACL group %d: %s>' \
701             % ( self.__group , ', '.join( r ) or 'none' )
702     def add( self , user , ttl = unlimitedTtl ) :
703         addGroupMember( self.__group , user , ttl )
704     def discard( self , user ) :
705         removeGroupMember( self.__group , user )
706     def clear( self ) :
707         map( self.discard , self )
708
709 # FIXME: Add a note about settings (not settable individually
710 # normally)
711 class Group( object ) :
712     __slots__ = ( '_id' , 'members' )
713     def __init__( self , id ) :
714         self._id = id
715         self.members = AclGroupMembersTtlDictProxy( id )
716     def __repr__( self ) :
717         try :
718             entry = getGroupEntry( self._id )
719             assert entry[ 2 ] in ( headers.ACLG_GLOBAL , headers.ACLG_PRIVATE )
720             desc = '%r %s' % \
721                 ( entry[ 3 ] ,
722                   ( 'PRIVATE' , 'GLOBAL' )[ entry[ 2 ] == headers.ACLG_GLOBAL ] )
723         except Error , e :
724             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
725                 raise
726             desc = 'undefined'
727         return '<ACL Group [%d] %s>' % ( self._id , desc )
728     #
729     # owner
730     #
731     def getOwner( self ) :
732         return User( getGroupEntry( self._id )[ 1 ] )
733     def setOwner( self , value ) :
734         entry = getGroupEntry( self._id )
735         changeGroup( self._id , int( value ) , entry[ 2 ] , entry[ 3 ] )
736     owner = property( getOwner , setOwner )
737     #
738     # private (not really a boolean, but let's say it is)
739     #
740     def getPrivate( self ) :
741         entry = getGroupEntry( self._id )
742         type = entry[ 2 ]
743         assert type in ( headers.ACLG_GLOBAL , headers.ACLG_PRIVATE )
744         return type == headers.ACLG_PRIVATE
745     def setPrivate( self , value ) :
746         entry = getGroupEntry( self._id )
747         if value :
748             value = headers.ACLG_PRIVATE
749         else :
750             value = headers.ACLG_GLOBAL
751         changeGroup( self._id , entry[ 1 ] , value , entry[ 3 ] )
752     private = property( getPrivate , setPrivate )
753     #
754     # name
755     #
756     def getName( self ) :
757         return getGroupEntry( self._id )[ 3 ]
758     def setName( self , value ) :
759         entry = getGroupEntry( self._id )
760         changeGroup( self._id , entry[ 1 ] , entry[ 2 ] , value )
761     name = property( getName , setName )
762
763 class GroupDict( object ) :
764     __slots__ = ()
765     def __iter__( self ) :
766         return ( item[ 0 ] for item in getGroupList( True ) )
767     def __getitem__( self , id ) :
768         return Group( id )
769     def __delitem__( self , id ) :
770         return removeGroup( id )
771     def __repr__( self ) :
772         return '{' + ', '.join( '%s: %s' % ( a , b ) for a , b in self.items() ) + '}'
773     def keys( self ) :
774         return list( self )
775     def values( self ) :
776         return map( Group , self )
777     def items( self ) :
778         return [ ( group , Group( group ) ) for group in self ]
779
780 groups = GroupDict()
781
782 from rsbac.rc import Role
783 from rsbac.objects import User, Process
784
785 # Local Variables:
786 # indent-tabs-mode: nil
787 # python-indent: 4
788 # End: