More explicit warning about versions mismatch.
[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 __len__( self ) :
731         return len( self.__list( self.__role ) )
732     def __iter__( self ) :
733         return iter( self.__list( self.__role ) )
734     def __contains__( self , role ) :
735         return self.has_key( role )
736     def __getitem__( self , role ) :
737         return self.__get( self.__role , role )
738     def __setitem__( self , role , value ) :
739         # FIXME: __setitem__ = Role( self.role ).setRoleCompatibility?
740         self.__set( self.__role , role , value )
741     def __delitem__( self , role ) :
742         self.__set( self.__role , role , False )
743     def __repr__( self ) :
744         r = []
745         for role in self :
746             value = self.__get( self.__role , role )
747             if value is True :
748                 r.append( str( role ) )
749             elif value is False :
750                 pass
751             else :
752                 r.append( '%s(%ds)' % ( role , value ) )
753         try :
754             name = `getRoleName( self.__role )`
755         except Error , e :
756             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
757                 raise
758             name = 'undefined'
759         return '<%s for RC Role %d (%s): %s>' \
760             % ( self.__name , self.__role , name ,
761                 ', '.join( r ) or 'none' )
762     def has_key( self , role ) :
763         return bool( self.__get( self.__role , role ) )
764     def keys( self ) :
765         return list( self )
766     def items( self ) :
767         r = []
768         # Be careful with TTL..
769         for role in self :
770             value = self.__get( self.__role , role )
771             if value :
772                 r.append( ( role , value ) )
773         return r
774     def add( self , role ) :
775         self.__set( self.__role , role , True )
776     def discard( self , role ) :
777         self.__set( self.__role , role , False )
778     def clear( self ) :
779         for role in self :
780             self.__set( self.__role , role , False )
781
782 class RoleTypeCompatibility( object ) :
783     __slots__ = ( 'role' , )
784     def __init__( self , role ) :
785         self.role = role
786     def __getitem__( self , type ) :
787         return getRoleTypeCompatibility( self.role , type )
788     def __setitem__( self , type , value ) :
789         return setRoleTypeCompatibility( self.role , type , value )
790     def __repr__( self ) :
791         return '<RoleTypeCompatibility with RC role %d>' % ( self.role , )
792
793 class DefaultIndividualFdCreateType( object ) :
794     __slots__ = ( 'role' , )
795     def __init__( self , role ) :
796         self.role = role
797     def __getitem__( self , type ) :
798         return self.role.getDefaultIndividualFdCreateType( type )
799     def get( self , type ) :
800         try :
801             return self[ type ]
802         except Error , e :
803             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
804                 raise
805     def __setitem__( self , type , value ) :
806         self.role.setDefaultIndividualFdCreateType( type , value )
807     def __delitem__( self , type ) :
808         self.role.delDefaultIndividualFdCreateType( type )
809
810 class DefaultTypes( object ) :
811     __slots__ = ( 'role' , )
812     def __init__( self , role ) :
813         self.role = role
814     def __getitem__( self , action ) :
815         return self.role.getDefaultType( action )
816     def __setitem__( self , action , value ) :
817         self.role.setDefaultType( action , value )
818
819 def _type( t ) :
820     from objects import Scd
821     if isinstance( t , Type ) :
822         return t.target , t.type
823     elif isinstance( t , Scd ) :
824         return t.type , t.id
825     else :
826         return t
827                 
828 class RoleBase( object ) :
829     __slots__ = ( '__weakref__' ,
830                   '_role' , '_id' ,
831                   'compatibility' , 'adminRoles' , 'assignRoles' ,
832                   'typeCompatibility' , 'defaultIndividualFdCreateType' )
833     def __new__( cls , role ) :
834         role = _nrole( role )
835         instance = _g_roles.get( role )
836         if instance is None :
837             instance = object.__new__( cls )
838             instance.__init_singleton__( role )
839             _g_roles[ role ] = instance
840         return instance
841     def __init_singleton__( self , role ) :
842         self._role = int( role )
843         id = headers.rsbac_rc_target_id_t()
844         id.role = role
845         self._id = byref( id )
846         self.compatibility = \
847             RoleTtlDictProxy( 'RoleCompatibility' , self._role ,
848                               getRoleCompatibilityRole ,
849                               setRoleCompatibilityRole ,
850                               listRoleCompatibilityRoles )
851         self.adminRoles = \
852             RoleTtlDictProxy( 'AdminRoles' , self._role ,
853                               getRoleAdminRole ,
854                               setRoleAdminRole ,
855                               listRoleAdminRoles )
856         self.assignRoles = \
857             RoleTtlDictProxy( 'AssignRoles' , self._role ,
858                               getRoleAssignRole ,
859                               setRoleAssignRole ,
860                               listRoleAssignRoles )
861         self.typeCompatibility = \
862             RoleTypeCompatibility( self._role )
863         self.defaultIndividualFdCreateType = \
864             DefaultIndividualFdCreateType( self._role )
865     def __int__( self ) :
866         return int( self._role )
867     def __long__( self ) :
868         return long( self._role )
869     def __repr__( self ) :
870         if self._role < 0 :
871             return '<RC PseudoRole [%d] %s>' \
872                 % ( self._role ,
873                     _g_pseudoRoles.get( self._role , 'unknown' ) )
874         else :
875             try :
876                 name = `self.getName()`
877             except Error :
878                 name = 'undefined'
879             return '<RC Role [%d] %s>' % ( self._role , name )
880     def copyTo( self , dest ) :
881         copyRole( self._role , int( dest ) )
882     def clone( self , name = None ) :
883         role = Role( cloneRole( self._role ) )
884         if name is not None :
885             role.name = name
886         return role
887     #
888     # id
889     #
890     def getId( self ) :
891         return self._role
892     id = property( getId )
893     #
894     # name
895     #
896     def getName( self ) :
897         return getRoleName( self._role )
898     def setName( self , name ) :
899         return setRoleName( self._role , name )
900     name = property( getName , setName )
901     #
902     # role_comp
903     #
904     def getRoleCompatibility( self , role ) :
905         return getRoleRoleCompatibility( self._role , role )
906     def setRoleCompatibility( self , role , value ) :
907         return setRoleRoleCompatibility( self._role , role , value )
908     #
909     # admin_roles
910     #
911     def getAdminRole( self , role ) :
912         return getRoleAdminRole( self._role , role )
913     def setAdminRole( self , role , value ) :
914         return setRoleAdminRole( self._role , role , value )
915     #
916     # assign_roles
917     #
918     def getAssignRole( self , role ) :
919         return getRoleAssignRole( self._role , role )
920     def setAssignRole( self , role , value ) :
921         return setRoleAssignRole( self._role , role , value )
922     #
923     # type_comp_*
924     #
925     def getTypeCompatibility( self , type ) :
926         return getRoleTypeCompatibility( self._role , type )
927     def setTypeCompatibility( self , type , value ) :
928         return setRoleTypeCompatibility( self._role , type , value )
929     #
930     # def_fd_ind_create_type
931     #
932     def getDefaultIndividualFdCreateType( self , type ) :
933         return getRoleDefaultIndividualFdCreateType( self._role , type )
934     def setDefaultIndividualFdCreateType( self , type1 , type2 ) :
935         return setRoleDefaultIndividualFdCreateType( self._role , type1 , type2 )
936     def delDefaultIndividualFdCreateType( self , type ) :
937         return delRoleDefaultIndividualFdCreateType( self._role , type )
938     #
939     # boot_role
940     #
941     def getBootRole( self ) :
942         return getRoleBootRole( self._role )
943     def setBootRole( self , value ) :
944         return setRoleBootRole( self._role , value )
945     bootRole = property( getBootRole , setBootRole )
946     #
947     # req_reauth
948     #
949     def getRequireReauthentication( self ) :
950         return getRoleRequireReauthentication( self._role )
951     def setRequireReauthentication( self , value ) :
952         return setRoleRequireReauthentication( self._role , value )
953     requireReauthentication = property( getRequireReauthentication ,
954                                         setRequireReauthentication )
955     #
956     # admin_type
957     #
958     def getAdminType( self ) :
959         return getRoleAdminType( self._role )
960     def setAdminType( self , value ) :
961         return setRoleAdminType( self._role , value )
962     adminType = property( getAdminType , setAdminType )
963     #
964     # remove
965     #
966     def delete( self ) :
967         removeRole( self._role )
968
969 def createRoleClass() :
970     attrs = { '__slots__' : () }
971     def addAttribute( target , name ) :
972         pname = 'default' + ''.join( [ s.capitalize() for s in name.split( '_' ) ] ) + 'Type'
973         cpname = pname[ 0 ].upper() + pname[ 1 : ]
974         #pname = 'def_%s_type' % name
975         item = getattr( headers , 'RI_def_%s_type' % name )
976         def getter( id ) :
977             raiseIfError( lib.rsbac_rc_get_item( 0 , headers.RT_ROLE ,
978                                                  id , None ,
979                                                  item , g_rcItemValueRef ,
980                                                  None ) )
981             return g_rcItemValue.type_id
982         def setter( id , value ) :
983             g_rcItemValue.type_id = value
984             raiseIfError( lib.rsbac_rc_set_item( 0 , headers.RT_ROLE ,
985                                                  id , None ,
986                                                  item , g_rcItemValueRef ,
987                                                  0 ) )
988         def mget( self ) :
989             return Type( target , getter( self._id ) )
990         def mset( self , value ) :
991             return setter( self._id , int( value ) )
992         attrs[ 'getter_' + pname ] = staticmethod( getter )
993         attrs[ 'setter_' + pname ] = staticmethod( setter )
994         #
995         attrs[ 'get' + cpname ] = mget
996         attrs[ 'set' + cpname ] = mset
997         attrs[ pname ] = property( mget , mset )
998     for target , name in (
999         ( headers.T_FD , 'fd_create' ) ,
1000         ( headers.T_USER , 'user_create' ) ,
1001         ( headers.T_GROUP , 'group_create' ) ,
1002         ( headers.T_PROCESS , 'process_create' ) ,
1003         ( headers.T_PROCESS , 'process_chown' )  ,
1004         ( headers.T_PROCESS , 'process_execute' ) ,
1005         ( headers.T_IPC , 'ipc_create' ) ,
1006         ( headers.T_FD , 'unixsock_create' ) ) :
1007         addAttribute( target , name )
1008     return type( 'Role' , ( RoleBase , ) , attrs )
1009
1010 export( 'Role' )
1011 Role = createRoleClass()
1012
1013 #-----------------------------------------------------------------------------
1014
1015 @export
1016 def getTypeName( type ) :
1017     """Get the name of a RC type
1018
1019     type -- RC type
1020
1021     """
1022     target , type = _type( type )
1023     g_rcTargetValue.type = type
1024     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_TYPE ,
1025                                          g_rcTargetValueRef , None ,
1026                                          g_rcNameTargetToItem[ target ] ,
1027                                          g_rcItemValueRef , None ) )
1028     return g_rcItemValue.name
1029
1030 @export
1031 def setTypeName( type , name ) :
1032     """Set the name of a RC type
1033
1034     type -- RC type
1035     name -- the new name as string
1036
1037     """
1038     target , type = _type( type )
1039     g_rcTargetValue.type = type
1040     slowButCorrectStringAssignation( g_rcItemValue , 'name' , name )
1041     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_TYPE ,
1042                                          g_rcTargetValueRef , None ,
1043                                          g_rcNameTargetToItem[ target ] ,
1044                                          g_rcItemValueRef , 0 ) )
1045
1046 @export
1047 def getTypeNeedSecureDelete( type ) :
1048     """Test if the RC type need secure delete.
1049
1050     type -- RC type
1051
1052     """
1053     target , type = _type( type )
1054     g_rcTargetValue.type = type
1055     if target != headers.T_FD :
1056         raise RuntimeError , 'attribute available for the FD type only'
1057     raiseIfError( lib.rsbac_rc_get_item( transaction._t , headers.RT_TYPE ,
1058                                          g_rcTargetValueRef , None ,
1059                                          headers.RI_type_fd_need_secdel ,
1060                                          g_rcItemValueRef , None ) )
1061     return bool( g_rcItemValue.need_secdel )
1062
1063 @export
1064 def setTypeNeedSecureDelete( type , value ) :
1065     """Set if the RC type need secure delete.
1066
1067     type -- RC type
1068     value - boolean
1069
1070     """
1071     target , type = _type( type )
1072     g_rcTargetValue.type = type
1073     if target != headers.T_FD :
1074         raise RuntimeError , 'attribute available for the FD type only'
1075     g_rcItemValue.need_secdel = value
1076     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_TYPE ,
1077                                          g_rcTargetValueRef , None ,
1078                                          headers.RI_type_fd_need_secdel ,
1079                                          g_rcItemValueRef , 0 ) )
1080
1081 @export
1082 def removeType( type ) :
1083     """Remove a RC type.
1084
1085     type -- RC type
1086
1087     """
1088     target , type = _type( type )
1089     g_rcTargetValue.type = type
1090     raiseIfError( lib.rsbac_rc_set_item( transaction._t , headers.RT_TYPE ,
1091                                          g_rcTargetValueRef , None ,
1092                                          g_rcTargetToTypeRemove[ target ] ,
1093                                          None , 0 ) )
1094
1095 class Type( object ) :
1096     __slots__ = ( '__weakref__' ,
1097                   '__id' , )
1098     def __new__( cls , target , type ) :
1099         if hasattr( target , 'type' ) :
1100             target = target.type
1101         type = _ntype( type )
1102         if type < 0 :
1103             target = None
1104         t = ( target , type )
1105         instance = _g_types.get( t )
1106         if instance is None :
1107             instance = object.__new__( cls )
1108             instance.__init_singleton__( target , type )
1109             _g_types[ t ] = instance
1110         return instance
1111     def __init_singleton__( self , target , type ) :
1112         self.__id = ( target , type )
1113     def __eq__( self , other ) :
1114         if isinstance( other , ( int , long ) ) :
1115             return self.type == _ntype( other )
1116         else :
1117             return ( self is other
1118                      or ( isinstance( other , Type )
1119                           and self.__id == other.__id ) )
1120     def __int__( self ) :
1121         return int( self.__id[ 1 ] )
1122     def __long__( self ) :
1123         return long( self.__id[ 1 ] )
1124     def __repr__( self ) :
1125         target , type = self.__id
1126         if type < 0 :
1127             return '<RC PseudoType [%d] %s>' \
1128                 % ( type ,
1129                     _g_pseudoTypes.get( type , 'unknown' ) , )
1130         else :
1131             try :
1132                 name = `self.getName()`
1133             except Error :
1134                 name = 'undefined'
1135             return '<RC Type [%d:%d] %s>' % ( target , type , name )
1136     def copyTo( self , dest ) :
1137         copyType( self.__id[ 0 ] , self.__id[ 1 ] , int( dest ) )
1138     def clone( self , name = None ) :
1139         type = Type( self.__id[ 0 ] , cloneType( *self.__id ) )
1140         if name is not None :
1141             type.name = name
1142         return type
1143     #
1144     # target, type
1145     #
1146     target = property( lambda self : self.__id[ 0 ] )
1147     type = property( lambda self : self.__id[ 1 ] )
1148     #
1149     # name
1150     #
1151     def getName( self ) :
1152         return getTypeName( self.__id )
1153     def setName( self , name ) :
1154         return setTypeName( self.__id , name )
1155     name = property( getName , setName )
1156     #
1157     # fd_need_secdel
1158     #
1159     def getNeedSecureDelete( self ) :
1160         return getTypeNeedSecureDelete( self.__id )
1161     def setNeedSecureDelete( self , value ) :
1162         return setTypeNeedSecureDelete( self.__id , value )
1163     needSecureDelete = property( getNeedSecureDelete , setNeedSecureDelete )
1164     #
1165     # delete
1166     #
1167     def delete( self ) :
1168         removeType( self.__id )
1169
1170 pseudoRoles = new.module( 'pseudoRoles' )
1171 for k , v in _g_pseudoRoles.items() :
1172     setattr( pseudoRoles , v , Role( k ) )
1173 pseudoTypes = new.module( 'pseudoTypes' )
1174 for k , v in _g_pseudoTypes.items() :
1175     setattr( pseudoTypes , v , Type( None , k ) )
1176
1177 class RcRoleDict( object ) :
1178     __slots__ = ()
1179     def __len__( self ) :
1180         return len( self.keys() )
1181     def __contains__( self , role ) :
1182         return self.has_key( role )
1183     def __iter__( self ) :
1184         return iter( self.keys() )
1185     def __getitem__( self , id ) :
1186         return Role( id )
1187     def __setitem__( self , id , role ) :
1188         copyRole( int( role ) , id )
1189     def __delitem__( self , id ) :
1190         Role( id ).delete()
1191     def __repr__( self ) :
1192         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
1193     def has_key( self , role ) :
1194         return role in self.keys()
1195     def keys( self ) :
1196         return getRoles()
1197     def items( self ) :
1198         return [ ( id , Role( id ) ) for id in self.keys() ]
1199     def values( self ) :
1200         return [ Role( id ) for id in self.keys() ]
1201
1202 @export
1203 def newType( target , name , start = 0 ) :
1204     """Create a new RC type.
1205
1206     target -- Type of target (Object)
1207     name -- Name for the new RC role.
1208
1209     Return a RC Type.
1210
1211     """
1212     i = start
1213     if hasattr( target , 'type' ) :
1214         target = target.type
1215     while 1 :
1216         try :
1217             Type( target , i ).name
1218         except Error , e :
1219             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
1220                 raise
1221             t = Type( target , i )
1222             t.name = name
1223             return t
1224         i += 1
1225
1226 class RcTypeDict( object ) :
1227     __slots__ = ( 'target' , )
1228     def __init__( self , target ) :
1229         self.target = target
1230     def __len__( self ) :
1231         return len( self.keys() )
1232     def __iter__( self ) :
1233         return iter( self.keys() )
1234     def __contains__( self , type ) :
1235         return self.has_key( type )
1236     def __getitem__( self , id ) :
1237         return Type( self.target , id )
1238     def __setitem__( self , id , type ) :
1239         copyType( self.target , int( type ) , id )
1240     def __delitem__( self , id ) :
1241         Type( self.target , id ).delete()
1242     def __repr__( self ) :
1243         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
1244     def has_key( self , type ) :
1245         return type in self.keys()
1246     def keys( self ) :
1247         return getTypes( self.target )
1248     def items( self ) :
1249         return [ ( id , Type( self.target , id ) ) for id in self.keys() ]
1250     def values( self ) :
1251         return [ Type( self.target , id ) for id in self.keys() ]
1252
1253 roles = RcRoleDict()
1254
1255 from rsbac._data import RequestVector
1256
1257 # Local Variables:
1258 # indent-tabs-mode: nil
1259 # python-indent: 4
1260 # End: