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