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