Fixed another attribute definition. Added __weakref__ to RC classes.
[py-rsbac] / rsbac / rc.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 """
21
22 This module provides access to RC type and RC role objects for the
23 RSBAC Python bindings.
24
25 """
26
27 __all__ = []
28
29 def export( o ) :
30     if not isinstance( o , basestring ) :
31         name = o.__name__
32     else :
33         name , o = o , None
34     if name in __all__ :
35         raise ImportError , 'duplicate name %r in module %r' % ( name , __name__ )
36     __all__.append( name )
37     return o
38
39 import new
40 import weakref
41 from ctypes import byref, c_uint32
42
43 from rsbac import headers, lib, transaction
44 from rsbac.errors import Error, raiseIfError
45 from rsbac._utils import aptr, slowButCorrectStringAssignation, fetch
46
47 # Singletons. Obviously bad for MT. But good for performance..
48 g_rcItemValue = headers.rsbac_rc_item_value_t()
49 g_rcItemValueRef = byref( g_rcItemValue )
50
51 g_rcTargetValue = headers.rsbac_rc_target_id_t()
52 g_rcTargetValueRef = byref( g_rcTargetValue )
53
54 g_rcTargetValue2 = headers.rsbac_rc_target_id_t()
55 g_rcTargetValue2Ref = byref( g_rcTargetValue2 )
56
57 g_ttl = headers.rsbac_time_t()
58 g_ttlRef = byref( g_ttl )
59
60 g_rcNameTargetToItem = {
61     headers.T_FD      : headers.RI_type_fd_name ,
62     headers.T_FILE    : headers.RI_type_fd_name ,
63     headers.T_DIR     : headers.RI_type_fd_name ,
64     headers.T_FIFO    : headers.RI_type_fd_name ,
65     headers.T_DEV     : headers.RI_type_dev_name ,
66     headers.T_IPC     : headers.RI_type_ipc_name ,
67     headers.T_USER    : headers.RI_type_user_name ,
68     headers.T_GROUP   : headers.RI_type_group_name ,
69     headers.T_PROCESS : headers.RI_type_process_name ,
70     headers.T_NETDEV  : headers.RI_type_netdev_name ,
71     headers.T_NETTEMP : headers.RI_type_nettemp_name ,
72     headers.T_NETOBJ  : headers.RI_type_netobj_name ,
73     headers.T_SCD     : headers.RI_type_scd_name
74     }
75
76 g_rcCompatibilityTargetToItem = {
77     headers.T_FD      : headers.RI_type_comp_fd ,
78     headers.T_FILE    : headers.RI_type_comp_fd ,
79     headers.T_DIR     : headers.RI_type_comp_fd ,
80     headers.T_FIFO    : headers.RI_type_comp_fd ,
81     headers.T_DEV     : headers.RI_type_comp_dev ,
82     headers.T_IPC     : headers.RI_type_comp_ipc ,
83     headers.T_USER    : headers.RI_type_comp_user ,
84     headers.T_GROUP   : headers.RI_type_comp_group ,
85     headers.T_PROCESS : headers.RI_type_comp_process ,
86     headers.T_NETDEV  : headers.RI_type_comp_netdev ,
87     headers.T_NETTEMP : headers.RI_type_comp_nettemp ,
88     headers.T_NETOBJ  : headers.RI_type_comp_netobj ,
89     headers.T_SCD     : headers.RI_type_comp_scd
90     }
91
92 g_rcTargetToTypeRemove = {
93     headers.T_FD      : headers.RI_type_fd_remove ,
94     headers.T_FILE    : headers.RI_type_fd_remove ,
95     headers.T_DIR     : headers.RI_type_fd_remove ,
96     headers.T_FIFO    : headers.RI_type_fd_remove ,
97     headers.T_DEV     : headers.RI_type_dev_remove ,
98     headers.T_IPC     : headers.RI_type_ipc_remove ,
99     headers.T_USER    : headers.RI_type_user_remove ,
100     headers.T_GROUP   : headers.RI_type_group_remove ,
101     headers.T_PROCESS : headers.RI_type_process_remove ,
102     headers.T_NETDEV  : headers.RI_type_netdev_remove ,
103     headers.T_NETTEMP : headers.RI_type_nettemp_remove ,
104     headers.T_NETOBJ  : headers.RI_type_netobj_remove
105     }
106
107 # RC role specific data
108 _g_role_mod = headers.rsbac_rc_role_id_t( -1 ).value + 1
109 assert _g_role_mod > 0
110 _g_role_max_value = headers.rsbac_rc_role_id_t( -32 ).value
111 def _nrole( n ) :
112     n %= _g_role_mod
113     if n >= _g_role_max_value :
114         return int( n - _g_role_mod )
115     else :
116         return int( n )
117 _g_roles = weakref.WeakValueDictionary()
118 _g_pseudoRoles = {
119     -1 : 'inherit_user' ,
120     -2 : 'inherit_process' ,
121     -3 : 'inherit_parent' ,
122     -4 : 'inherit_up_mixed' ,
123     -5 : 'use_force_role'
124     }
125
126 # RC type specific data
127 _g_type_mod = headers.rsbac_rc_type_id_t( -1 ).value + 1
128 assert _g_type_mod > 0
129 _g_type_max_value = headers.rsbac_rc_type_id_t( -32 ).value
130 def _ntype( n ) :
131     n %= _g_type_mod
132     if n >= _g_type_max_value :
133         return int( n - _g_type_mod )
134     else :
135         return int( n )
136 _g_types = weakref.WeakValueDictionary()
137 _g_pseudoTypes = {
138     -1 : 'inherit_process' ,
139     -2 : 'inherit_parent' ,
140     -3 : 'no_create' ,
141     -4 : 'no_execute' ,
142     -5 : 'use_new_role_def_create' ,
143     -6 : 'no_chown' ,
144     -7 : 'use_fd'
145     }
146
147 @export
148 def copyRole( source , dest ) :
149     """Copy a RC role.
150
151     source -- RC role as integer
152     dest -- RC role as integer
153
154     """
155     raiseIfError( lib.rsbac_rc_copy_role( transaction._t ,
156                                           source , dest ) )
157
158 @export
159 def grant( role , type , requests ) :
160     """Grant 'requests' to 'role' for the given 'type'.
161
162     role -- RC role
163     type -- RC type
164     requests -- RequestVector
165
166     """
167     rights , ttl = role.typeCompatibility[ type ]
168     rights |= rsbac.RequestVector( requests )
169     role.typeCompatibility[ type ] = rights , ttl
170
171 @export
172 def revoke( role , type , requests ) :
173     """Revoke 'requests' to 'role' for the given 'type'.
174
175     role -- RC Role
176     type -- RC type
177     requests -- RequestVector
178
179     """
180     rights , ttl = role.typeCompatibility[ type ]
181     rights &= ~rsbac.RequestVector( requests )
182     role.typeCompatibility[ type ] = rights , ttl
183
184 def findUnnamedRole( start = 0 ) :
185     """Find an unnamed role.
186
187     start -- Minimal RC role id to use, as integer.
188
189     Return an integer.
190
191     """
192     i = start
193     while 1 :
194         try :
195             getRoleName( i )
196         except Error , e :
197             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
198                 raise
199             break
200         i += 1
201     return i
202
203 def findUnnamedRoles( n = 1 , start = 0 ) :
204     """Find a set of unnammed roles.
205
206     n -- Number of unnnamed roles to find.
207     start -- Minimal RC role id to use, as integer.
208
209     Return a list of integers.
210
211     """
212     r = []
213     i = start
214     for j in range( n ) :
215         role = findUnnamedRole( i )
216         r.append( role )
217         i = role + 1
218     return r
219
220 @export
221 def newRole( name , start = 0 ) :
222     """Create a new RC role.
223
224     name -- Name for the new RC role.
225
226     Return a RC Role.
227
228     """
229     role = findUnnamedRole( start )
230     setRoleName( role , name )
231     return Role( role )
232
233 @export
234 def cloneRole( source , start = 0 ) :
235     """Clone a RC role under another name.
236
237     source -- RC role as integer
238     name -- Name of the new role
239
240     """
241     role = findUnnamedRole( start )
242     copyRole( source , role )
243     return role
244
245 def findUnnamedType( target , start = 0 ) :
246     """Find an unnamed type.
247
248     start -- Minimal RC type id to use, as integer.
249
250     Return an integer.
251     """
252     i = start
253     while 1 :
254         try :
255             getTypeName( ( target , i ) )
256         except Error , e :
257             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
258                 raise
259             break
260         i += 1
261     return i
262
263 def findUnnamedTypes( target , n = 1 , start = 0 ) :
264     """Find a set of unnammed types.
265
266     n -- Number of unnnamed types to find.
267     start -- Minimal RC type id to use, as integer.
268
269     Return a list of integers.
270
271     """
272     r = []
273     i = start
274     for j in range( n ) :
275         type = findUnnamedType( target , i )
276         r.append( type )
277         i = type + 1
278     return r
279
280 @export
281 def copyType( target , source , dest ) :
282     """Copy a RC type.
283
284     The target specify which type of RC type should be copied.
285
286     target -- RSBAC object type as integer
287     source -- RC type as integer
288     dest -- RC Type as integer
289
290     """
291     raiseIfError( lib.rsbac_rc_copy_type( transaction._t , target ,
292                                           source , dest ) )
293
294 @export
295 def cloneType( target , source , start = 0 ) :
296     """Clone a RC type under another name.
297
298     source -- RC type as integer
299     name -- Name of the new type
300
301     """
302     type = findUnnamedType( target , start )
303     copyType( target , source , type )
304     return type
305
306 @export
307 def getList( rcTarget , rcId , item ) :
308     """Retrieve a list of RC items (role or type).
309
310     rcTarget -- RT_ROLE, RT_TYPE or None.
311     rcId -- role or target as integer.
312     item -- a value from RI_* defines.
313
314     """
315     # FIXME: I'm assuming that all roles are returned when querying
316     # with RI_name, and that target can be NULL. Is that right?
317     if rcId is None :
318         id = None
319     elif rcTarget == headers.RT_ROLE :
320         g_rcTargetValue.role = rcId
321     elif rcTarget == headers.RT_TYPE :
322         g_rcTargetValue.type = rcId
323     else :
324         raise RuntimeError , 'unexpected rc target %d' % ( rcTarget , )
325     arr = fetch( c_uint32 ,
326                  lambda n , a : lib.rsbac_rc_get_list( transaction._t ,
327                                                        rcTarget , g_rcTargetValueRef ,
328                                                        item , n , a , None ) )
329     return sorted( map( int , arr ) )
330
331 @export
332 def getRoleList( role , item ) :
333     """Retrieve a list of items associated with a role.
334
335     role -- RC role as integer or None
336     item -- a value from RI_* defines.
337
338     """
339     return getList( headers.RT_ROLE , role , item )
340
341 @export
342 def getTypeList( type , item ) :
343     """Retrieve a list of items associated with a type.
344
345     type -- RC type as integer (or None?)
346     item -- a value from RI_* defines.
347
348     """
349     return getList( headers.RT_TYPE , type , item )
350
351 @export
352 def getRoles() :
353     """Retrieve a list of all defined roles (those with a name.)
354
355     """
356     # FIXME: I'm assuming that all roles are returned when querying
357     # with RI_name, and that target can be NULL. Is that correct?
358     return getRoleList( None , headers.RI_name )
359
360 g_scdRcTypes = None
361
362 @export
363 def getTypes( target ) :
364     """Retrieve a list of all defined types (those with a name.)
365
366     target -- RSBAC object type as integer
367
368     """
369     if target == headers.T_SCD :
370         global g_scdRcTypes
371         if g_scdRcTypes is None :
372             r = []
373             for key in dir( headers ) :
374                 if ( key.startswith( 'ST_' ) or key.startswith( 'AST_' ) ) \
375                     and not key.endswith( '_none' ) :
376                     r.append( int( getattr( headers , key ) ) )
377             r.sort()
378             g_scdRcTypes = r
379         return g_scdRcTypes
380     else :
381         if target not in g_rcNameTargetToItem :
382             raise RuntimeError , 'Unexpected target %r' % ( target , )
383         return getTypeList( None , g_rcNameTargetToItem[ target ] )
384
385 @export
386 def changeRole( role , password = None ) :
387     """Change the role of the current process.
388
389     role -- RC role as integer
390     password -- the password as a string or None
391
392     """
393     raiseIfError( lib.rsbac_rc_change_role( role , password ) )
394
395 @export
396 def getCurrentRole() :
397     """Return the role of the current process.
398
399     Return a RC role as an integer.
400
401     """
402     role = headers.rsbac_rc_role_id_t()
403     raiseIfError( lib.rsbac_rc_get_current_role( byref( role ) ) )
404     return int( role.value )
405
406 @export
407 def getRoleName( role ) :
408     """Get the name of a RC role.
409
410     role -- RC role as integer
411
412     """
413     g_rcTargetValue.role = role
414     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_ROLE ,
415                                          g_rcTargetValueRef , None ,
416                                          headers.RI_name , g_rcItemValueRef ,
417                                          None ) )
418     return g_rcItemValue.name
419
420 @export
421 def setRoleName( role , name ) :
422     """Set the name of a RC role.
423
424     role -- RC role as integer
425     name -- the new name as string
426
427     """
428     g_rcTargetValue.role = role
429     slowButCorrectStringAssignation( g_rcItemValue , 'name' , name )
430     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
431                                          g_rcTargetValueRef , None ,
432                                          headers.RI_name , g_rcItemValueRef ,
433                                          0 ) )
434
435 @export
436 def getRoleTypeCompatibility( role , type ) :
437     """Get RC role compatibility with the given type.
438
439     role -- RC role as integer
440     type -- RC type as either a tuple (target,type) or an Object class
441     or instance.
442
443     Return a tuple (RequestVector,ttl).
444
445     """
446     g_rcTargetValue.role = role
447     target , type = _type( type )
448     g_rcTargetValue2.type = type
449     item = g_rcCompatibilityTargetToItem[ target ]
450     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_ROLE ,
451                                          g_rcTargetValueRef , g_rcTargetValue2Ref ,
452                                          item , g_rcItemValueRef ,
453                                          g_ttlRef ) )
454     return RequestVector( g_rcItemValue.rights ) , g_ttl.value
455
456 @export
457 def setRoleTypeCompatibility( role , type , value ) :
458     """Set RC role compatibility with the given type.
459
460     role -- RC role as integer
461     type -- RC type
462     value -- A tuple (RequestVector,ttl) or a RequestVector (implying
463     unlimited TTL.)
464
465     """
466     g_rcTargetValue.role = role
467     target , type = _type( type )
468     g_rcTargetValue2.type = type
469     item = g_rcCompatibilityTargetToItem[ target ]
470     if not isinstance( value , ( tuple , list ) ) :
471         value = ( value , 0 )
472     rights , ttl = value
473     g_rcItemValue.rights = int( rights )
474     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
475                                          g_rcTargetValueRef , g_rcTargetValue2Ref ,
476                                          item , g_rcItemValueRef ,
477                                          ttl ) )
478
479 @export
480 def getRoleDefaultIndividualFdCreateType( role , type ) :
481     """Get RC role default individual FD create type
482
483     role -- RC role as integer
484     type -- RC type
485
486     Return a Type
487
488     """
489     # FIXME.. Return an integer, and use Type in the class wrapper
490     # instead.
491     g_rcTargetValue.role = role
492     g_rcTargetValue2.type = int( type ) # FIXME: Check target type
493     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_ROLE ,
494                                          g_rcTargetValueRef , g_rcTargetValue2Ref ,
495                                          headers.RI_def_fd_ind_create_type ,
496                                          g_rcItemValueRef , None ) )
497     return Type( headers.T_FD , g_rcItemValue.type_id )
498
499 @export
500 def setRoleDefaultIndividualFdCreateType( role , type1 , type2 ) :
501     """Set RC role default individual FD create type
502
503     role -- RC role as integer
504     type1 -- RC type
505     type2 -- RC type
506
507     """
508     g_rcTargetValue.role = role
509     g_rcTargetValue2.type = int( type1 ) # FIXME: Check target type
510     g_rcItemValue.type_id = int( type2 ) # FIXME: Check target type
511     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
512                                          g_rcTargetValueRef , g_rcTargetValue2Ref ,
513                                          headers.RI_def_fd_ind_create_type ,
514                                          g_rcItemValueRef , 0 ) )
515
516 @export
517 def delRoleDefaultIndividualFdCreateType( role , type ) :
518     """Remove RC role default individidual FD create type setting
519
520     role -- RC role as integer
521     type -- RC type
522     """
523     g_rcTargetValue.role = role
524     g_rcTargetValue2.type = int( type ) # FIXME: Check target type
525     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
526                                          g_rcTargetValueRef , g_rcTargetValue2Ref ,
527                                          headers.RI_def_fd_ind_create_type_remove ,
528                                          None , 0 ) )
529
530 @export
531 def getRoleAdminType( role ) :
532     """Get the RC role admin type.
533
534     role -- RC role as integer
535
536     """
537     g_rcTargetValue.role = role
538     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_ROLE ,
539                                          g_rcTargetValueRef , None ,
540                                          headers.RI_admin_type , g_rcItemValueRef ,
541                                          None ) )
542     return g_rcItemValue.admin_type
543
544 @export
545 def setRoleAdminType( role , value ) :
546     """Set the RC role admin type.
547
548     role -- RC role as integer
549     value -- RC role admin type (0 [no admin], 1 [role admin] or 2 [system admin])
550
551     """
552     g_rcTargetValue.role = role
553     g_rcItemValue.admin_type = value
554     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
555                                          g_rcTargetValueRef , None ,
556                                          headers.RI_admin_type , g_rcItemValueRef ,
557                                          0 ) )
558
559 @export
560 def getRoleBootRole( role ) :
561     """Test if the RC role is a boot role.
562
563     role -- RC role as integer
564
565     """
566     g_rcTargetValue.role = role
567     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_ROLE ,
568                                          g_rcTargetValueRef , None ,
569                                          headers.RI_boot_role ,
570                                          g_rcItemValueRef , None ) )
571     return bool( g_rcItemValue.boot_role )
572
573 @export
574 def setRoleBootRole( role , value ) :
575     """Set if the RC role is a boot role.
576
577     role -- RC role as integer
578     value -- boolean
579
580     """
581     g_rcTargetValue.role = role
582     g_rcItemValue.boot_role = value
583     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
584                                          g_rcTargetValueRef , None ,
585                                          headers.RI_boot_role ,
586                                          g_rcItemValueRef , 0 ) )
587
588 @export
589 def getRoleRequireReauthentication( role ) :
590     """Test if the role requires reauthentication
591
592     role -- RC role as integer
593
594     """
595     g_rcTargetValue.role = role
596     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_ROLE ,
597                                          g_rcTargetValueRef , None ,
598                                          headers.RI_req_reauth ,
599                                          g_rcItemValueRef , None ) )
600     return bool( g_rcItemValue.req_reauth )
601
602 @export
603 def setRoleRequireReauthentication( role , value ) :
604     """Set if the role requires reauthentication
605
606     role -- RC role as integer
607     value -- boolean
608
609     """
610     g_rcTargetValue.role = role
611     g_rcItemValue.req_reauth = value
612     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
613                                          g_rcTargetValueRef , None ,
614                                          headers.RI_req_reauth ,
615                                          g_rcItemValueRef , 0 ) )
616
617 @export
618 def removeRole( role ) :
619     """Remove a RC role.
620
621     role -- RC role as integer
622
623     """
624     g_rcTargetValue.role = role
625     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_ROLE ,
626                                          g_rcTargetValueRef , None ,
627                                          headers.RI_remove_role , None , 0 ) )
628
629 def makeGetSetRoles( name , item , docGet = None , docSet = None ) :
630     import sys
631     RT_ROLE = headers.RT_ROLE
632     def get( roleA , roleB ) :
633         g_rcTargetValue.role = roleA
634         g_rcTargetValue2.role = roleB
635         raiseIfError( lib.rsbac_rc_get_item( transaction._t , RT_ROLE ,
636                                              g_rcTargetValueRef , g_rcTargetValue2Ref ,
637                                              item , g_rcItemValueRef , g_ttlRef ) )
638         return int( g_ttl.value ) or bool( g_rcItemValue.comp )
639     if docGet is not None :
640         get.__doc__ = docGet + """
641
642         roleA -- RC role as integer
643         roleB -- RC role as integer
644
645         """
646     def set( roleA , roleB , value ) :
647         g_rcTargetValue.role = roleA
648         g_rcTargetValue2.role = roleB
649         if value is True :
650             flag , ttl = True , 0
651         elif not value or value < 1 :
652             flag , ttl = False , 0
653         else :
654             flag , ttl = True , value
655         g_rcItemValue.comp = flag
656         raiseIfError( lib.rsbac_rc_set_item( transaction._t , RT_ROLE ,
657                                              g_rcTargetValueRef , g_rcTargetValue2Ref ,
658                                              item , g_rcItemValueRef , ttl ) )
659     if docSet is not None :
660         set.__doc__ = docSet + """
661
662         roleA -- RC role as integer
663         roleB -- RC role as integer
664         value -- False, True or an integer.
665
666         """
667     def list( role ) :
668         return getList( RT_ROLE , role , item )
669     m = sys.modules[ __name__ ]
670     setattr( m , 'get' + name , get )
671     setattr( m , 'set' + name , set )
672     setattr( m , 'list' + name + 's' , list )
673     __all__.append( 'get' + name )
674     __all__.append( 'set' + name )
675     __all__.append( 'list' + name + 's' )
676
677 makeGetSetRoles( 'RoleCompatibilityRole' , headers.RI_role_comp ,
678                  'Test if the RC role is compatible with another one.' ,
679                  'Set if the RC role is compatible with another one.' )
680
681 makeGetSetRoles( 'RoleAdminRole' , headers.RI_admin_roles ,
682                  None , # FIXME
683                  None ) # FIXME
684
685 makeGetSetRoles( 'RoleAssignRole' , headers.RI_assign_roles ,
686                  None , # FIXME
687                  None ) # FIXME
688
689 # FIXME: dict interface!
690 class RoleTtlDictProxy( object ) :
691     __slots__ = ( '__name' , '__role' , '__get' , '__set' , '__list' )
692     def __init__( self , name , role , get , set , list ) :
693         self.__name = name
694         self.__role = role
695         self.__get = get
696         self.__set = set
697         self.__list = list
698     def __iter__( self ) :
699         return iter( self.__list( self.__role ) )
700     def __contains__( self , role ) :
701         return bool( self.__get( self.__role , role ) )
702     def __getitem__( self , role ) :
703         return self.__get( self.__role , role )
704     def __setitem__( self , role , value ) :
705         # FIXME: __setitem__ = Role( self.role ).setRoleCompatibility?
706         self.__set( self.__role , role , value )
707     def __delitem__( self , role ) :
708         self.__set( self.__role , role , False )
709     def __repr__( self ) :
710         r = []
711         for role in self :
712             value = self.__get( self.__role , role )
713             if value is True :
714                 r.append( str( role ) )
715             elif value is False :
716                 pass
717             else :
718                 r.append( '%s(%ds)' % ( role , value ) )
719         try :
720             name = `getRoleName( self.__role )`
721         except Error , e :
722             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
723                 raise
724             name = 'undefined'
725         return '<%s for RC Role %d (%s): %s>' \
726             % ( self.__name , self.__role , name ,
727                 ', '.join( r ) or 'none' )
728     def keys( self ) :
729         return list( self )
730     def items( self ) :
731         r = []
732         # Be careful with TTL..
733         for role in self :
734             value = self.__get( self.__role , role )
735             if value :
736                 r.append( ( role , value ) )
737         return r
738     def add( self , role ) :
739         self.__set( self.__role , role , True )
740     def discard( self , role ) :
741         self.__set( self.__role , role , False )
742     def clear( self ) :
743         for role in self :
744             self.__set( self.__role , role , False )
745
746 class RoleTypeCompatibility( object ) :
747     __slots__ = ( 'role' , )
748     def __init__( self , role ) :
749         self.role = role
750     def __getitem__( self , type ) :
751         return getRoleTypeCompatibility( self.role , type )
752     def __setitem__( self , type , value ) :
753         return setRoleTypeCompatibility( self.role , type , value )
754     def __repr__( self ) :
755         return '<RoleTypeCompatibility with RC role %d>' % ( self.role , )
756
757 class DefaultIndividualFdCreateType( object ) :
758     __slots__ = ( 'role' , )
759     def __init__( self , role ) :
760         self.role = role
761     def __getitem__( self , type ) :
762         return self.role.getDefaultIndividualFdCreateType( type )
763     def get( self , type ) :
764         try :
765             return self[ type ]
766         except Error , e :
767             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
768                 raise
769     def __setitem__( self , type , value ) :
770         self.role.setDefaultIndividualFdCreateType( type , value )
771     def __delitem__( self , type ) :
772         self.role.delDefaultIndividualFdCreateType( type )
773
774 class DefaultTypes( object ) :
775     __slots__ = ( 'role' , )
776     def __init__( self , role ) :
777         self.role = role
778     def __getitem__( self , action ) :
779         return self.role.getDefaultType( action )
780     def __setitem__( self , action , value ) :
781         self.role.setDefaultType( action , value )
782
783 def _type( t ) :
784     from objects import Scd
785     if isinstance( t , Type ) :
786         return t.target , t.type
787     elif isinstance( t , Scd ) :
788         return t.type , t.id
789     else :
790         return t
791                 
792 class RoleBase( object ) :
793     __slots__ = ( '__weakref__' ,
794                   '_role' , '_id' ,
795                   'compatibility' , 'adminRoles' , 'assignRoles' ,
796                   'typeCompatibility' , 'defaultIndividualFdCreateType' )
797     def __new__( cls , role ) :
798         role = _nrole( role )
799         instance = _g_roles.get( role )
800         if instance is None :
801             instance = object.__new__( cls )
802             instance.__init_singleton__( role )
803             _g_roles[ role ] = instance
804         return instance
805     def __init_singleton__( self , role ) :
806         self._role = int( role )
807         id = headers.rsbac_rc_target_id_t()
808         id.role = role
809         self._id = byref( id )
810         self.compatibility = \
811             RoleTtlDictProxy( 'RoleCompatibility' , self._role ,
812                               getRoleCompatibilityRole ,
813                               setRoleCompatibilityRole ,
814                               listRoleCompatibilityRoles )
815         self.adminRoles = \
816             RoleTtlDictProxy( 'AdminRoles' , self._role ,
817                               getRoleAdminRole ,
818                               setRoleAdminRole ,
819                               listRoleAdminRoles )
820         self.assignRoles = \
821             RoleTtlDictProxy( 'AssignRoles' , self._role ,
822                               getRoleAssignRole ,
823                               setRoleAssignRole ,
824                               listRoleAssignRoles )
825         self.typeCompatibility = \
826             RoleTypeCompatibility( self._role )
827         self.defaultIndividualFdCreateType = \
828             DefaultIndividualFdCreateType( self._role )
829     def __int__( self ) :
830         return int( self._role )
831     def __long__( self ) :
832         return long( self._role )
833     def __repr__( self ) :
834         if self._role < 0 :
835             return '<RC PseudoRole [%d] %s>' \
836                 % ( self._role ,
837                     _g_pseudoRoles.get( self._role , 'unknown' ) )
838         else :
839             try :
840                 name = `self.getName()`
841             except Error :
842                 name = 'undefined'
843             return '<RC Role [%d] %s>' % ( self._role , name )
844     def copyTo( self , dest ) :
845         copyRole( self._role , int( dest ) )
846     def clone( self , name = None ) :
847         role = Role( cloneRole( self._role ) )
848         if name is not None :
849             role.name = name
850         return role
851     #
852     # id
853     #
854     def getId( self ) :
855         return self._role
856     id = property( getId )
857     #
858     # name
859     #
860     def getName( self ) :
861         return getRoleName( self._role )
862     def setName( self , name ) :
863         return setRoleName( self._role , name )
864     name = property( getName , setName )
865     #
866     # role_comp
867     #
868     def getRoleCompatibility( self , role ) :
869         return getRoleRoleCompatibility( self._role , role )
870     def setRoleCompatibility( self , role , value ) :
871         return setRoleRoleCompatibility( self._role , role , value )
872     #
873     # admin_roles
874     #
875     def getAdminRole( self , role ) :
876         return getRoleAdminRole( self._role , role )
877     def setAdminRole( self , role , value ) :
878         return setRoleAdminRole( self._role , role , value )
879     #
880     # assign_roles
881     #
882     def getAssignRole( self , role ) :
883         return getRoleAssignRole( self._role , role )
884     def setAssignRole( self , role , value ) :
885         return setRoleAssignRole( self._role , role , value )
886     #
887     # type_comp_*
888     #
889     def getTypeCompatibility( self , type ) :
890         return getRoleTypeCompatibility( self._role , type )
891     def setTypeCompatibility( self , type , value ) :
892         return setRoleTypeCompatibility( self._role , type , value )
893     #
894     # def_fd_ind_create_type
895     #
896     def getDefaultIndividualFdCreateType( self , type ) :
897         return getRoleDefaultIndividualFdCreateType( self._role , type )
898     def setDefaultIndividualFdCreateType( self , type1 , type2 ) :
899         return setRoleDefaultIndividualFdCreateType( self._role , type1 , type2 )
900     def delDefaultIndividualFdCreateType( self , type ) :
901         return delRoleDefaultIndividualFdCreateType( self._role , type )
902     #
903     # boot_role
904     #
905     def getBootRole( self ) :
906         return getRoleBootRole( self._role )
907     def setBootRole( self , value ) :
908         return setRoleBootRole( self._role , value )
909     bootRole = property( getBootRole , setBootRole )
910     #
911     # req_reauth
912     #
913     def getRequireReauthentication( self ) :
914         return getRoleRequireReauthentication( self._role )
915     def setRequireReauthentication( self , value ) :
916         return setRoleRequireReauthentication( self._role , value )
917     requireReauthentication = property( getRequireReauthentication ,
918                                         setRequireReauthentication )
919     #
920     # admin_type
921     #
922     def getAdminType( self ) :
923         return getRoleAdminType( self._role )
924     def setAdminType( self , value ) :
925         return setRoleAdminType( self._role , value )
926     adminType = property( getAdminType , setAdminType )
927     #
928     # remove
929     #
930     def delete( self ) :
931         removeRole( self._role )
932
933 def createRoleClass() :
934     attrs = { '__slots__' : () }
935     def addAttribute( target , name ) :
936         pname = 'default' + ''.join( [ s.capitalize() for s in name.split( '_' ) ] ) + 'Type'
937         cpname = pname[ 0 ].upper() + pname[ 1 : ]
938         #pname = 'def_%s_type' % name
939         item = getattr( headers , 'RI_def_%s_type' % name )
940         def getter( id ) :
941             raiseIfError( lib.rsbac_rc_get_item( 0 , headers.RT_ROLE ,
942                                                  id , None ,
943                                                  item , g_rcItemValueRef ,
944                                                  None ) )
945             return g_rcItemValue.type_id
946         def setter( id , value ) :
947             g_rcItemValue.type_id = value
948             raiseIfError( lib.rsbac_rc_set_item( 0 , headers.RT_ROLE ,
949                                                  id , None ,
950                                                  item , g_rcItemValueRef ,
951                                                  0 ) )
952         def mget( self ) :
953             return Type( target , getter( self._id ) )
954         def mset( self , value ) :
955             return setter( self._id , int( value ) )
956         attrs[ 'getter_' + pname ] = staticmethod( getter )
957         attrs[ 'setter_' + pname ] = staticmethod( setter )
958         #
959         attrs[ 'get' + cpname ] = mget
960         attrs[ 'set' + cpname ] = mset
961         attrs[ pname ] = property( mget , mset )
962     for target , name in (
963         ( headers.T_FD , 'fd_create' ) ,
964         ( headers.T_USER , 'user_create' ) ,
965         ( headers.T_GROUP , 'group_create' ) ,
966         ( headers.T_PROCESS , 'process_create' ) ,
967         ( headers.T_PROCESS , 'process_chown' )  ,
968         ( headers.T_PROCESS , 'process_execute' ) ,
969         ( headers.T_IPC , 'ipc_create' ) ,
970         ( headers.T_FD , 'unixsock_create' ) ) :
971         addAttribute( target , name )
972     return type( 'Role' , ( RoleBase , ) , attrs )
973
974 export( 'Role' )
975 Role = createRoleClass()
976
977 #-----------------------------------------------------------------------------
978
979 @export
980 def getTypeName( type ) :
981     """Get the name of a RC type
982
983     type -- RC type
984
985     """
986     target , type = _type( type )
987     g_rcTargetValue.type = type
988     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_TYPE ,
989                                          g_rcTargetValueRef , None ,
990                                          g_rcNameTargetToItem[ target ] ,
991                                          g_rcItemValueRef , None ) )
992     return g_rcItemValue.name
993
994 @export
995 def setTypeName( type , name ) :
996     """Set the name of a RC type
997
998     type -- RC type
999     name -- the new name as string
1000
1001     """
1002     target , type = _type( type )
1003     g_rcTargetValue.type = type
1004     slowButCorrectStringAssignation( g_rcItemValue , 'name' , name )
1005     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_TYPE ,
1006                                          g_rcTargetValueRef , None ,
1007                                          g_rcNameTargetToItem[ target ] ,
1008                                          g_rcItemValueRef , 0 ) )
1009
1010 @export
1011 def getTypeNeedSecureDelete( type ) :
1012     """Test if the RC type need secure delete.
1013
1014     type -- RC type
1015
1016     """
1017     target , type = _type( type )
1018     g_rcTargetValue.type = type
1019     if target != headers.T_FD :
1020         raise RuntimeError , 'attribute available for the FD type only'
1021     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_TYPE ,
1022                                          g_rcTargetValueRef , None ,
1023                                          headers.RI_type_fd_need_secdel ,
1024                                          g_rcItemValueRef , None ) )
1025     return bool( g_rcItemValue.need_secdel )
1026
1027 @export
1028 def setTypeNeedSecureDelete( type , value ) :
1029     """Set if the RC type need secure delete.
1030
1031     type -- RC type
1032     value - boolean
1033
1034     """
1035     target , type = _type( type )
1036     g_rcTargetValue.type = type
1037     if target != headers.T_FD :
1038         raise RuntimeError , 'attribute available for the FD type only'
1039     g_rcItemValue.need_secdel = value
1040     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_TYPE ,
1041                                          g_rcTargetValueRef , None ,
1042                                          headers.RI_type_fd_need_secdel ,
1043                                          g_rcItemValueRef , 0 ) )
1044
1045 @export
1046 def removeType( type ) :
1047     """Remove a RC type.
1048
1049     type -- RC type
1050
1051     """
1052     target , type = _type( type )
1053     g_rcTargetValue.type = type
1054     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_TYPE ,
1055                                          g_rcTargetValueRef , None ,
1056                                          g_rcTargetToTypeRemove[ target ] ,
1057                                          None , 0 ) )
1058
1059 class Type( object ) :
1060     __slots__ = ( '__weakref__' ,
1061                   '__id' , )
1062     def __new__( cls , target , type ) :
1063         if hasattr( target , 'type' ) :
1064             target = target.type
1065         type = _ntype( type )
1066         if type < 0 :
1067             target = None
1068         t = ( target , type )
1069         instance = _g_types.get( t )
1070         if instance is None :
1071             instance = object.__new__( cls )
1072             instance.__init_singleton__( target , type )
1073             _g_types[ t ] = instance
1074         return instance
1075     def __init_singleton__( self , target , type ) :
1076         self.__id = ( target , type )
1077     def __eq__( self , other ) :
1078         if isinstance( other , ( int , long ) ) :
1079             return self.type == _ntype( other )
1080         else :
1081             return ( self is other
1082                      or ( isinstance( other , Type )
1083                           and self.__id == other.__id ) )
1084     def __int__( self ) :
1085         return int( self.__id[ 1 ] )
1086     def __long__( self ) :
1087         return long( self.__id[ 1 ] )
1088     def __repr__( self ) :
1089         target , type = self.__id
1090         if type < 0 :
1091             return '<RC PseudoType [%d] %s>' \
1092                 % ( type ,
1093                     _g_pseudoTypes.get( type , 'unknown' ) , )
1094         else :
1095             try :
1096                 name = `self.getName()`
1097             except Error :
1098                 name = 'undefined'
1099             return '<RC Type [%d:%d] %s>' % ( target , type , name )
1100     def copyTo( self , dest ) :
1101         copyType( self.__id[ 0 ] , self.__id[ 1 ] , int( dest ) )
1102     def clone( self , name = None ) :
1103         type = Type( self.__id[ 0 ] , cloneType( *self.__id ) )
1104         if name is not None :
1105             type.name = name
1106         return type
1107     #
1108     # target, type
1109     #
1110     target = property( lambda self : self.__id[ 0 ] )
1111     type = property( lambda self : self.__id[ 1 ] )
1112     #
1113     # name
1114     #
1115     def getName( self ) :
1116         return getTypeName( self.__id )
1117     def setName( self , name ) :
1118         return setTypeName( self.__id , name )
1119     name = property( getName , setName )
1120     #
1121     # fd_need_secdel
1122     #
1123     def getNeedSecureDelete( self ) :
1124         return getTypeNeedSecureDelete( self.__id )
1125     def setNeedSecureDelete( self , value ) :
1126         return setTypeNeedSecureDelete( self.__id , value )
1127     needSecureDelete = property( getNeedSecureDelete , setNeedSecureDelete )
1128     #
1129     # delete
1130     #
1131     def delete( self ) :
1132         removeType( self.__id )
1133
1134 pseudoRoles = new.module( 'pseudoRoles' )
1135 for k , v in _g_pseudoRoles.items() :
1136     setattr( pseudoRoles , v , Role( k ) )
1137 pseudoTypes = new.module( 'pseudoTypes' )
1138 for k , v in _g_pseudoTypes.items() :
1139     setattr( pseudoTypes , v , Type( None , k ) )
1140
1141 class RcRoleDict( object ) :
1142     __slots__ = ()
1143     def keys( self ) :
1144         return getRoles()
1145     def items( self ) :
1146         return [ ( id , Role( id ) ) for id in self.keys() ]
1147     def values( self ) :
1148         return [ Role( id ) for id in self.keys() ]
1149     def __iter__( self ) :
1150         return iter( self.keys() )
1151     def __getitem__( self , id ) :
1152         return Role( id )
1153     def __setitem__( self , *args ) :
1154         raise RuntimeError
1155     def __delitem__( self , id ) :
1156         Role( id ).delete()
1157     def __repr__( self ) :
1158         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
1159
1160 def newType( target , name , start = 0 ) :
1161     i = start
1162     if hasattr( target , 'type' ) :
1163         target = target.type
1164     while 1 :
1165         try :
1166             Type( target , i ).name
1167         except Error , e :
1168             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
1169                 raise
1170             t = Type( target , i )
1171             t.name = name
1172             return t
1173         i += 1
1174
1175 class RcTypeDict( object ) :
1176     __slots__ = ( 'target' , )
1177     def __init__( self , target ) :
1178         self.target = target
1179     def keys( self ) :
1180         return getTypes( self.target )
1181     def items( self ) :
1182         return [ ( id , Type( self.target , id ) ) for id in self.keys() ]
1183     def values( self ) :
1184         return [ Type( self.target , id ) for id in self.keys() ]
1185     def __iter__( self ) :
1186         return iter( self.keys() )
1187     def __getitem__( self , id ) :
1188         return Type( self.target , id )
1189     def __setitem__( self , *args ) :
1190         raise RuntimeError
1191     def __delitem__( self , id ) :
1192         Type( self.target , id ).delete()
1193     def __repr__( self ) :
1194         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
1195
1196 roles = RcRoleDict()
1197
1198 from rsbac._data import RequestVector
1199
1200 # Local Variables:
1201 # indent-tabs-mode: nil
1202 # python-indent: 4
1203 # End: