3 # py-rsbac - RSBAC Python bindings
4 # Copyright (C) 2006 Frederic Jolliton <pyrsbac@tuxee.net>
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.
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.
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
22 'FD' , 'File' , 'Fifo' , 'Symlink' , 'Directory' , 'Device' ,
23 'User' , 'Group' , 'Process' ,
24 'Ipc' , 'IpcSem' , 'IpcMsg' , 'IpcShm' ,
25 'IpcAnonPipe' , 'IpcMqueue' , 'IpcAnonUnix' ,
26 'NetworkDevice' , 'NetworkTemplate'
35 from ctypes import byref
37 from rsbac import headers, lib, transaction
38 from rsbac._data import RequestVector, AclRequestVector, JailScdVector
39 from rsbac._data import FileFlags, PaxFlags, CapsFlags, JailFlags
40 from rsbac.errors import Error, raiseIfError
41 from rsbac._utils import aptr, slowButCorrectStringAssignation
42 from rsbac._utils import stringToByteArray, byteArrayToString, fetch
43 from rsbac._utils import ipToInt, intToIp
44 from rsbac._utils import processName, digits
45 from rsbac.roles import SystemRole
47 # Singleton. Obviously bad for MT. But good for performance..
48 g_attributeValue = headers.rsbac_attribute_value_t()
49 g_attributeValueRef = byref( g_attributeValue )
51 from rsbac_auto import g_attributes
53 from rsbac.rc import RcTypeDict, Role, Type
55 def buildObjectClass( className , parents , target , byName ) :
56 if isinstance( target , tuple ) :
57 target , realTarget = target
59 target , realTarget = target , target
60 attrs = { '__slots__' : () }
62 fget = lib.rsbac_get_attr_n
63 fset = lib.rsbac_set_attr_n
64 frem = lib.rsbac_remove_target_n
65 amget = lib.rsbac_acl_get_mask_n
66 amset = lib.rsbac_acl_n
68 fget = lib.rsbac_get_attr
69 fset = lib.rsbac_set_attr
70 frem = lib.rsbac_remove_target
71 amget = lib.rsbac_acl_get_mask
74 raiseIfError( frem( transaction._t , target , id ) )
76 return remover( self._id )
77 attrs[ 'remover' ] = staticmethod( remover )
78 attrs[ 'remove' ] = mremove
79 def addAclMaskAttribute() :
80 rights = headers.rsbac_acl_rights_vector_t()
81 rightsRef = byref( rights )
82 sm = headers.ACLC_set_mask
84 raiseIfError( amget( transaction._t , target , id , rightsRef ) )
87 arg = headers.rsbac_acl_syscall_n_arg_t()
89 arg = headers.rsbac_acl_syscall_arg_t()
93 def setter( id , mask ) :
96 raiseIfError( amset( transaction._t , sm , argRef ) )
98 def setter( id , mask ) :
101 raiseIfError( amset( transaction._t , sm , argRef ) )
103 return AclRequestVector( getter( self._id ) )
104 def mset( self , value ) :
105 return setter( self._id , int( value ) )
106 attrs[ 'getter_acl_mask' ] = staticmethod( getter )
107 attrs[ 'setter_acl_mask' ] = staticmethod( setter )
108 attrs[ 'get_acl_mask' ] = mget
109 attrs[ 'set_acl_mask' ] = mset
110 attrs[ 'acl_mask' ] = property( mget , mset )
111 def addLogArrayAttribute() :
112 module = headers.SW_GEN
113 attr1 = headers.A_log_array_low
114 attr2 = headers.A_log_array_high
116 raiseIfError( fget( transaction._t , module , target , id , attr1 , g_attributeValueRef , 0 ) )
117 v1 = g_attributeValue.log_array_low
118 raiseIfError( fget( transaction._t , module , target , id , attr2 , g_attributeValueRef , 0 ) )
119 v2 = g_attributeValue.log_array_high
120 return tuple( [ int( item[ 0 ] + 2 * item[ 1 ] )
121 for item in zip( digits( v1 , 2 , 64 ) ,
122 digits( v2 , 2 , 64 ) ) ] )
123 def getterEffective( id ) :
124 raiseIfError( fget( transaction._t , module , target ,
125 id , attr1 , g_attributeValueRef , 1 ) )
126 v1 = g_attributeValue.log_array_low
127 raiseIfError( fget( transaction._t , module , target ,
128 id , attr2 , g_attributeValueRef , 1 ) )
129 v2 = g_attributeValue.log_array_high
130 return tuple( [ int( item[ 0 ] + 2 * item[ 1 ] )
131 for item in zip( digits( v1 , 2 , 64 ) ,
132 digits( v2 , 2 , 64 ) ) ] )
133 def setter( id , value ) :
134 if not isinstance( value , ( tuple , list ) ) or len( value ) != 64 :
135 raise RuntimeError , 'expected a sequence of 64 elements'
144 g_attributeValue.log_array_low = v1
145 raiseIfError( fset( transaction._t , module , target ,
146 id , attr1 , g_attributeValueRef , 0 ) )
147 g_attributeValue.log_array_high = v2
148 raiseIfError( fset( transaction._t , module , target ,
149 id , attr2 , g_attributeValueRef , 0 ) )
151 return getter( self._id )
152 def mgetEffective( self ) :
153 return getterEffective( self._id )
154 def mset( self , value ) :
155 setter( self._id , value )
156 attrs[ 'getter_log_array' ] = staticmethod( getter )
157 attrs[ 'getter_eff_log_array' ] = staticmethod( getterEffective )
158 attrs[ 'setter_log_array' ] = staticmethod( setter )
159 attrs[ 'get_log_array' ] = mget
160 attrs[ 'get_eff_log_array' ] = mgetEffective
161 attrs[ 'set_log_array' ] = mset
162 attrs[ 'log_array' ] = property( mget , mset )
163 attrs[ 'eff_log_array' ] = property( mgetEffective )
164 def addAttribute( module , vid , name , field ,
165 pre = None , post = None ,
166 mpre = None , mpost = None ) :
168 # getter for real value
172 raiseIfError( fget( transaction._t , module , target ,
173 id , vid , g_attributeValueRef , 0 ) )
174 return getattr( g_attributeValue , field )
177 raiseIfError( fget( transaction._t , module , target ,
178 id , vid , g_attributeValueRef , 0 ) )
179 return post( getattr( g_attributeValue , field ) )
181 # getter for effective value
184 def getterEffective( id ) :
185 raiseIfError( fget( transaction._t , module , target ,
186 id , vid , g_attributeValueRef , 1 ) )
187 return getattr( g_attributeValue , field )
189 def getterEffective( id ) :
190 raiseIfError( fget( transaction._t , module , target ,
191 id , vid , g_attributeValueRef , 1 ) )
192 return post( getattr( g_attributeValue , field ) )
197 def setter( id , value ) :
198 setattr( g_attributeValue , field , value )
199 raiseIfError( fset( transaction._t , module , target ,
200 id , vid , g_attributeValueRef ) )
202 def setter( id , value ) :
203 setattr( g_attributeValue , field , pre( value ) )
204 raiseIfError( fset( transaction._t , module , target ,
205 id , vid , g_attributeValueRef ) )
211 return getter( self._id )
212 def mgetEffective( self ) :
213 return getterEffective( self._id )
215 if isinstance( mpost , tuple ) :
216 mpost , withSelf = mpost
221 return mpost( getter( self._id ) )
222 def mgetEffective( self ) :
223 return mpost( getterEffective( self._id ) )
226 return mpost( getter( self._id ) , self )
227 def mgetEffective( self ) :
228 return mpost( getterEffective( self._id ) , self )
230 def mset( self , value ) :
231 return setter( self._id , value )
233 if isinstance( mpre , tuple ) :
234 mpre , withSelf = mpost
238 def mset( self , value ) :
239 return setter( self._id , mpre( value ) )
241 def mset( self , value ) :
242 return setter( self._id , mpre( value , self ) )
244 attrs[ 'getter_' + name ] = staticmethod( getter )
245 attrs[ 'setter_' + name ] = staticmethod( setter )
246 attrs[ 'getter_eff_' + name ] = staticmethod( getterEffective )
248 attrs[ 'get_' + name ] = mget
249 attrs[ 'set_' + name ] = mset
250 attrs[ name ] = property( mget , mset )
252 attrs[ 'get_eff_' + name ] = mgetEffective
253 attrs[ 'eff_' + name ] = property( mgetEffective )
255 def raUnpack( value ) :
256 return tuple( map( int , value ) )
257 def raPack( value ) :
258 t = headers.rsbac_res_array_t()
262 for attribute , module , field , ctype , targets in g_attributes :
263 module = getattr( headers , 'SW_' + module )
264 attributeId = getattr( headers , 'A_' + attribute )
265 targets = [ getattr( headers , 'T_' + n ) for n in targets ]
266 if ( target in targets or realTarget in targets ) \
267 and attribute not in [ 'log_array_low' , 'log_array_high' ] :
268 attributes.append( attribute )
269 if ctype == 'rsbac_jail_ip_t' or field == 'remote_ip' :
270 mpre , mpost = ipToInt , intToIp
271 elif ctype == 'rsbac_jail_scd_vector_t' :
272 mpre , mpost = int , JailScdVector
273 elif ctype == 'rsbac_jail_id_t' :
274 mpre , mpost = int , int
275 elif ctype == 'rsbac_jail_flags_t' :
276 mpre , mpost = int , JailFlags
277 elif ctype == 'rsbac_boolean_t' :
278 mpre , mpost = int , bool
279 elif ctype == 'rsbac_rc_role_id_t' :
280 mpre , mpost = int , Role
281 elif ctype == 'rsbac_rc_type_id_t' :
282 mpre , mpost = int , lambda n : Type( realTarget , n )
283 elif ctype == 'rsbac_request_vector_t' :
284 mpre , mpost = int , RequestVector
285 elif ctype == 'rsbac_ff_flags_t' :
286 mpre , mpost = int , FileFlags
287 elif ctype == 'rsbac_uid_t' :
288 mpre , mpost = int , lambda n : User( n ) # defer, since User is not yet defined
289 elif ctype == 'rsbac_pax_flags_t' :
290 mpre , mpost = int , PaxFlags
291 elif ctype == 'rsbac_cap_vector_t' :
292 mpre , mpost = int , CapsFlags
293 elif ctype == 'rsbac_system_role_int_t' :
294 mpre , mpost = int , SystemRole
296 mpre , mpost = None , None
297 if ctype == 'rsbac_res_array_t' :
298 pre , post = raPack , raUnpack
300 pre , post = None , None
301 addAttribute( module , attributeId , attribute , field ,
302 pre , post , mpre , mpost )
304 # FIXME: remote_log_array_{high,low} too !
305 if 'log_array_low' in fields and 'log_array_high' in fields :
306 addLogArrayAttribute()
307 attributes.append( 'log_array' )
308 addAclMaskAttribute()
309 attrs[ 'type' ] = target
310 attrs[ 'attributes' ] = sorted( attributes )
311 attrs[ '_byName' ] = byName
312 return type( className , parents , attrs )
314 class Object( object ) :
315 """Base class for all RSBAC objects.
320 class ObjectWithAttributes( Object ) :
321 """Base class for objects with RSBAC attributes.
325 def getAllAttributes( self ) :
327 for name in self.attributes :
329 r[ name ] = getattr( self , name )
334 #--[ FD ]---------------------------------------------------------------------
338 class FDBase( ObjectWithAttributes ) :
339 """Base class for FD hierarchy.
342 __slots__ = ( '_id' , 'acl' , 'eff_acl' ,
343 'authCapability' , 'authEffectiveCapability' , 'authFsCapability' ,
344 'authGroupCapability' , 'authGroupEffectiveCapability' , 'authGroupFsCapability' )
346 def __new__( cls , id ) :
348 instance = _g_defaultFd.get( cls.type )
349 if instance is None :
350 instance = ObjectWithAttributes.__new__( cls )
351 instance.__init_singleton__( id )
352 _g_defaultFd[ cls.type ] = instance
354 instance = ObjectWithAttributes.__new__( cls )
355 instance.__init_singleton__( id )
357 def __init_singleton__( self , id ) :
358 if not isinstance( id , str ) and id is not None :
359 raise TypeError , 'Invalid id %r' % ( id , )
361 self.acl = acl.AclByName( self )
362 self.eff_acl = acl.EffectiveAclByName( self )
363 self.authCapability = \
364 auth.AuthCapDictProxyFd( headers.ACT_real , id )
365 self.authEffectiveCapability = \
366 auth.AuthCapDictProxyFd( headers.ACT_eff , id )
367 self.authFsCapability = \
368 auth.AuthCapDictProxyFd( headers.ACT_fs , id )
369 self.authGroupCapability = \
370 auth.AuthCapDictProxyFd( headers.ACT_group_real , id )
371 self.authGroupEffectiveCapability = \
372 auth.AuthCapDictProxyFd( headers.ACT_group_eff , id )
373 self.authGroupFsCapability = \
374 auth.AuthCapDictProxyFd( headers.ACT_group_fs , id )
375 def __eq__( self , other ) :
376 return self is other or ( isinstance( other , FDBase )
377 and self.type == other.type
378 and self._id == other._id )
379 def __str__( self ) :
381 def __repr__( self ) :
382 if self._id is None :
383 return '<Default%s>' % self.__class__.__name__
385 return '<%s %r>' % ( self.__class__.__name__ , self._id )
388 buildObjectClass( 'FD' , ( FDBase , ) ,
389 headers.T_FD , True )
391 buildObjectClass( 'File' , ( FDBase , ) ,
392 ( headers.T_FILE , headers.T_FD ) , True )
394 buildObjectClass( 'Fifo' , ( FDBase , ) ,
395 ( headers.T_FIFO , headers.T_FD ) , True )
397 buildObjectClass( 'Symlink' , ( FDBase , ) ,
398 ( headers.T_SYMLINK , headers.T_FD ) , True )
400 buildObjectClass( 'Directory' , ( FDBase , ) ,
401 ( headers.T_DIR , headers.T_FD ) , True )
403 buildObjectClass( 'Device' , ( FDBase , ) ,
404 ( headers.T_DEV , headers.T_FD ) , True )
407 buildObjectClass( 'UnixSocket' , ( FDBase , ) ,
408 ( headers.T_UNIXSOCK , headers.T_FD ) , True )
410 #--[ Device ]-----------------------------------------------------------------
412 class DeviceBase( ObjectWithAttributes ) :
414 type = headers.T_DEV # Needed for RcTypeDict
416 class BlockDeviceBase( DeviceBase ) :
417 __slots__ = ( '_dev' , '_id' , 'acl' , 'eff_acl' )
418 def __init__( self , major , minor = None ) :
419 super( BlockDeviceBase , self ).__init__()
420 self._dev = ( major , minor )
421 id = headers.rsbac_target_id_t()
422 if minor is not None :
423 id.dev.type = headers.D_block
427 id.dev.type = headers.D_block_major
429 self._id = byref( id )
430 self.acl = acl.AclById( self )
431 self.eff_acl = acl.EffectiveAclById( self )
432 def __eq__( self , other ) :
433 return self is other or ( isinstance( other , BlockDeviceBase )
434 and self._dev == other._dev )
435 def __repr__( self ) :
436 if self._dev[ 1 ] is None :
439 dev = '%d:%d' % ( self._dev )
440 return '<BlockDevice %s>' % dev
442 BlockDevice = buildObjectClass( 'BlockDevice' ,
443 ( BlockDeviceBase , ) ,
444 headers.T_DEV , False )
446 class CharacterDeviceBase( DeviceBase ) :
447 __slots__ = ( '_dev' , '_id' , 'acl' , 'eff_acl' )
448 def __init__( self , major , minor = None ) :
449 super( CharacterDeviceBase , self ).__init__()
450 self._dev = ( major , minor )
451 id = headers.rsbac_target_id_t()
452 if minor is not None :
453 id.dev.type = headers.D_char
457 id.dev.type = headers.D_char_major
459 self._id = byref( id )
460 self.acl = acl.AclById( self )
461 self.eff_acl = acl.EffectiveAclById( self )
462 def __eq__( self , other ) :
463 return self is other or ( isinstance( other , CharacterDeviceBase )
464 and self._dev == other._dev )
465 def __repr__( self ) :
466 if self._dev[ 1 ] is None :
469 dev = '%d:%d' % ( self._dev )
470 return '<CharacterDevice %s>' % dev
472 CharacterDevice = buildObjectClass( 'CharacterDevice' ,
473 ( CharacterDeviceBase , ) ,
474 headers.T_DEV , False )
476 #--[ User ]-------------------------------------------------------------------
478 _g_user_mod = headers.rsbac_uid_t( -1 ).value + 1
479 assert _g_user_mod > 0
480 _g_user_max_value = headers.rsbac_uid_t( -32 ).value # FIXME: -32?
483 if n >= _g_user_max_value :
484 return n - _g_user_mod
493 class UserBase( ObjectWithAttributes ) :
494 __slots__ = ( 'uid' , '_id' , 'acl' , 'eff_acl' )
495 def __new__( cls , user ) :
496 user = _nuser( user )
498 instance = _g_users.get( user )
499 if instance is None :
500 instance = ObjectWithAttributes.__new__( cls )
501 instance.__init_singleton__( user )
502 _g_users[ user ] = instance
505 instance = ObjectWithAttributes.__new__( cls )
506 instance.__init_singleton__( user )
508 def __init_singleton__( self , user ) :
509 ObjectWithAttributes.__init__( self )
510 id = lib.rsbac_target_id_t()
511 if isinstance( user , ( int , long ) ) :
513 elif isinstance( user , ( str , unicode ) ) :
514 uid = pwd.getpwnam( user )[ 2 ]
516 raise RuntimeError , 'Unexpected user id %r' % ( user , )
519 self._id = byref( id )
520 self.acl = acl.AclById( self )
521 self.eff_acl = acl.EffectiveAclById( self )
522 def __int__( self ) :
523 return int( self.uid )
524 def __long__( self ) :
525 return long( self.uid )
526 def __eq__( self , other ) :
527 return self is other or ( isinstance( other , UserBase )
528 and self.uid == other.uid )
529 def __repr__( self ) :
531 return '<PseudoUser %s>' % ( _g_pseudoUsers.get( self.uid , self.uid ) , )
533 return '<User %d>' % self.uid
534 def removeFromAcl( self ) :
535 return acl.aclRemoveUser( self.uid )
537 User = buildObjectClass( 'User' , ( UserBase , ) , headers.T_USER , False )
539 #--[ Group ]------------------------------------------------------------------
541 _g_group_mod = headers.rsbac_gid_t( -1 ).value + 1
542 assert _g_group_mod > 0
543 _g_group_max_value = headers.rsbac_gid_t( -32 ).value # FIXME: -32?
546 if n >= _g_group_max_value :
547 return n - _g_group_mod
556 class GroupBase( ObjectWithAttributes ) :
557 __slots__ = ( 'gid' , '_id' , 'acl' , 'eff_acl' )
558 def __new__( cls , group ) :
559 group = _ngroup( group )
561 instance = _g_groups.get( group )
562 if instance is None :
563 instance = ObjectWithAttributes.__new__( cls )
564 instance.__init_singleton__( group )
565 _g_groups[ group ] = instance
568 instance = ObjectWithAttributes.__new__( cls )
569 instance.__init_singleton__( group )
571 def __init_singleton__( self , group ) :
572 ObjectWithAttributes.__init__( group )
573 id = headers.rsbac_target_id_t()
574 if isinstance( group , ( int , long ) ) :
576 elif isinstance( group , ( str , unicode ) ) :
577 gid = grp.getgrnam( group )[ 2 ]
579 raise RuntimeError , 'Unexpected group id %r' % ( group , )
582 self._id = byref( id )
583 self.acl = acl.AclById( self )
584 self.eff_acl = acl.EffectiveAclById( self )
585 def __int__( self ) :
586 return int( self.gid )
587 def __long__( self ) :
588 return long( self.gid )
589 def __eq__( self , other ) :
590 return self is other or ( isinstance( other , GroupBase )
591 and self.gid == other.gid )
592 def __repr__( self ) :
594 return '<PseudoGroup %s>' % ( _g_pseudoGroups.get( self.gid , self.gid ) , )
596 return '<Group %d>' % self.gid
598 Group = buildObjectClass( 'Group' , ( GroupBase , ) , headers.T_GROUP , False )
600 #--[ Process ]----------------------------------------------------------------
602 class ProcessBase( ObjectWithAttributes ) :
603 __slots__ = ( 'pid' , '_id' , 'acl' , 'eff_acl' ,
604 'authCapability' , 'authEffectiveCapability' , 'authFsCapability' ,
605 'authGroupCapability' , 'authGroupEffectiveCapability' , 'authGroupFsCapability' )
606 def __init__( self , pid ) :
607 super( ProcessBase , self ).__init__()
608 id = headers.rsbac_target_id_t()
611 self._id = byref( id )
612 self.acl = acl.AclById( self )
613 self.eff_acl = acl.EffectiveAclById( self )
614 self.authCapability = \
615 auth.AuthCapDictProxyProcess( headers.ACT_real , pid )
616 self.authEffectiveCapability = \
617 auth.AuthCapDictProxyProcess( headers.ACT_eff , pid )
618 self.authFsCapability = \
619 auth.AuthCapDictProxyProcess( headers.ACT_fs , pid )
620 self.authGroupCapability = \
621 auth.AuthCapDictProxyProcess( headers.ACT_group_real , pid )
622 self.authGroupEffectiveCapability = \
623 auth.AuthCapDictProxyProcess( headers.ACT_group_eff , pid )
624 self.authGroupFsCapability = \
625 auth.AuthCapDictProxyProcess( headers.ACT_group_fs , pid )
626 def __int__( self ) :
627 return int( self.pid )
628 def __long__( self ) :
629 return long( self.pid )
630 def __eq__( self , other ) :
631 return self is other or ( isinstance( other , ProcessBase )
632 and self.pid == other.pid )
633 def __repr__( self ) :
635 return '<DefaultProcess>'
637 return '<Process %d %r>' % ( self.pid , processName( self.pid ) )
639 Process = buildObjectClass( 'Process' , ( ProcessBase , ) , headers.T_PROCESS , False )
641 #--[ IPC ]--------------------------------------------------------------------
643 class IpcBase( ObjectWithAttributes ) :
644 __slots__ = ( '_id' , 'id' , 'acl' , 'eff_acl' )
646 def __init__( self , ipcId ) :
647 super( IpcBase , self ).__init__()
648 id = headers.rsbac_target_id_t()
649 id.ipc.type = self.ipc
650 id.ipc.id.id_nr = ipcId
651 self._id = byref( id )
653 self.acl = acl.AclById( self )
654 self.eff_acl = acl.EffectiveAclById( self )
655 def __int__( self ) :
656 return int( self.id )
657 def __long__( self ) :
658 return long( self.id )
659 def __repr__( self ) :
660 if self.ipc == headers.I_none and self.id == 0 :
661 return '<DefaultIpc>'
663 return '<%s %d>' % ( self.__class__.__name__ , self.id )
665 Ipc = buildObjectClass( 'Ipc' , ( IpcBase , ) , headers.T_IPC , False )
667 class IpcSem( Ipc ) :
671 class IpcMsg( Ipc ) :
675 class IpcShm( Ipc ) :
679 class IpcAnonPipe( Ipc ) :
681 ipc = headers.I_anonpipe
683 class IpcMqueue( Ipc ) :
685 ipc = headers.I_mqueue
687 class IpcAnonUnix( Ipc ) :
689 ipc = headers.I_anonunix
691 #--[ SCD ]--------------------------------------------------------------------
695 class Scd( Object ) :
696 __slots__ = ( '_id' , 'id' , 'name' , 'acl' , 'eff_acl' )
698 def __new__( cls , target , *args , **kwargs ) :
699 instance = g_scd.get( target )
700 if instance is None :
701 instance = object.__new__( cls )
702 instance.__init_singleton__( target , *args , **kwargs )
703 g_scd[ target ] = instance
705 def __init_singleton__( self , target , name ) :
706 super( Scd , self ).__init__()
707 id = lib.rsbac_target_id_t()
709 self._id = byref( id )
712 self.acl = acl.AclById( self )
713 self.eff_acl = acl.EffectiveAclById( self )
714 def getRcType( self ) :
715 return Type( self.type , self.id )
716 rc_type = property( getRcType )
717 def __repr__( self ) :
718 if self.name is None :
719 return '<DefaultSCD>'
721 return '<SCD %s>' % self.name
723 #--[ NetworkObject ]----------------------------------------------------------
725 _g_networkObject = None
727 class NetworkObject( Object ) :
728 __slots__ = ( '_id' , 'acl' , 'eff_acl' )
729 type = headers.T_NETOBJ
731 global _g_networkObject
732 if _g_networkObject is None :
733 _g_networkObject = Object.__new__( cls )
734 _g_networkObject.__init_singleton__()
735 return _g_networkObject
736 def __init_singleton__( self ) :
737 id = headers.rsbac_target_id_t()
738 id.netobj.sock_p = None
739 id.netobj.local_addr = None
740 id.netobj.local_len = 0
741 id.netobj.remote_addr = None
742 id.netobj.remote_len = 0
743 self._id = byref( id )
744 self.acl = acl.AclById( self )
745 self.eff_acl = acl.EffectiveAclById( self )
746 def __repr__( self ) :
747 return '<NetworkObject>'
749 #--[ NetworkDevice ]----------------------------------------------------------
751 # Not exported. Included in NetworkDevice class.
752 def getAllNetworkDevice() :
753 """*Return a list of all network devices involved with RSBAC rules."""
754 arr = fetch( headers.rsbac_netdev_id_t ,
755 lambda n , a : lib.rsbac_net_list_all_netdev( transaction._t , a , n ) )
756 return sorted( map( byteArrayToString , arr ) )
758 class NetworkDeviceBase( ObjectWithAttributes ) :
759 __slots__ = ( '_name' , '_id' , 'acl' , 'eff_acl' )
760 def __init__( self , name ) :
761 super( NetworkDeviceBase , self ).__init__()
762 id = headers.rsbac_target_id_t()
763 stringToByteArray( id.netdev , name , minPadding = 1 )
765 self._id = byref( id )
766 self.acl = acl.AclById( self )
767 self.eff_acl = acl.EffectiveAclById( self )
768 def __eq__( self , other ) :
769 return self is other or ( isinstance( other , NetworkDeviceBase )
770 and self._name == other._name )
771 def __str__( self ) :
773 def __repr__( self ) :
774 if self._name == '' :
775 return '<DefaultNetworkDevice>'
777 return '<NetworkDevice %r>' % ( self._name , )
778 all = staticmethod( getAllNetworkDevice )
780 NetworkDevice = buildObjectClass( 'NetworkDeviceBase' ,
781 ( NetworkDeviceBase , ) ,
782 headers.T_NETDEV , False )
784 #--[ NetworkTemplate ]--------------------------------------------------------
787 #assert 0 <= n < 2**32
788 n , a = divmod( n , 256 )
789 n , b = divmod( n , 256 )
790 n , c = divmod( n , 256 )
792 return '.'.join( map( str , ( a , b , c , d ) ) )
794 g_reDigitsOnly = re.compile( r'^\d+$' )
799 raise RuntimeError , 'invalid IP'
801 for n in reversed( ns ) :
802 if not g_reDigitsOnly.match( n ) :
803 raise RuntimeError , 'invalid IP'
805 if not 0 <= n <= 255 :
806 raise RuntimeError , 'invalid IP'
810 def ipv4AndPrefixToInt( s ) :
814 ip , prefix = s.split( '/' , 1 )
815 if not g_reDigitsOnly.match( prefix ) :
816 raise RuntimeError, 'invalid prefix'
817 prefix = int( prefix )
819 if not 0 <= prefix <= 32 :
820 raise RuntimeError , 'invalid prefix'
823 # Not exported. Included in NetworkTemplate class.
824 def createNetworkTemplate( id , name ) :
825 data = headers.rsbac_net_temp_syscall_data_t()
826 slowButCorrectStringAssignation( data , 'name' , name )
827 raiseIfError( lib.rsbac_net_template( transaction._t ,
828 headers.NTS_new_template ,
829 id , byref( data ) ) )
830 return NetworkTemplate( id )
832 def findUndefinedNetworkTemplate( start = 1 ) :
833 """Find an undefined network template.
835 start -- Minimal Network Template ID to use, as integer.
840 data = byref( headers.rsbac_net_temp_syscall_data_t() )
841 fun = lib.rsbac_net_template
842 call = headers.NTS_check_id
844 while fun( transaction._t , call , i , data ) >= 0 :
848 def findUndefinedNetworkTemplates( n = 1 , start = 1 ) :
849 """Find a set of undefined network template.
851 n -- Number of unnnamed types to find.
852 start -- Minimal RC type id to use, as integer.
854 Return a list of integers.
859 for j in range( n ) :
860 nt = findUndefinedNetworkTemplate( i )
865 def newNetworkTemplate( name , start = 1 ) :
866 """Create a new network template.
868 name -- Name for the new network template.
870 Return a NetworkTemplate.
873 return createNetworkTemplate( findUndefinedNetworkTemplate( start ) , name )
875 # Not exported. Included in NetworkTemplate class.
876 def copyNetworkTemplate( source , dest ) :
877 data = headers.rsbac_net_temp_syscall_data_t()
879 raiseIfError( lib.rsbac_net_template( transaction._t ,
880 headers.NTS_copy_template ,
881 dest , byref( data ) ) )
882 return NetworkTemplate( dest )
884 class _NetworkTemplateSelf( object ) :
885 __slots__ = ( '_id' , 'nt' , 'acl' , 'eff_acl' )
886 type = headers.T_NETTEMP_NT
887 def __init__( self , nt ) :
888 id = headers.rsbac_target_id_t()
890 self._id = byref( id )
892 self.acl = acl.AclById( self )
893 self.eff_acl = acl.EffectiveAclById( self )
894 def __repr__( self ) :
895 return '<NetworkTemplate[Self] %d>' % self.nt
897 class NetworkTemplateBase( ObjectWithAttributes ) :
898 __slots__ = ( '_id' , 'nt' , 'acl' , 'eff_acl' , 'selfAcl' , 'eff_selfAcl' )
899 def __init__( self , nt ) :
900 super( NetworkTemplateBase , self ).__init__()
901 id = headers.rsbac_target_id_t()
903 self._id = byref( id )
905 self.acl = acl.AclById( self )
906 self.eff_acl = acl.EffectiveAclByName( self )
907 ntSelf = _NetworkTemplateSelf( nt )
908 self.selfAcl = acl.AclById( ntSelf )
909 self.eff_selfAcl = acl.EffectiveAclById( ntSelf )
910 def __repr__( self ) :
912 name = `self.getName()`
915 return '<%s [%d] %s>' % ( self.__class__.__name__ , self.nt , name )
916 def __syscall( self , syscall , data ) :
917 raiseIfError( lib.rsbac_net_template( transaction._t , syscall ,
918 self.nt , byref( data ) ) )
920 def __syscallGet( self , syscall ) :
921 # FIXME: Use a shared 'data' to prevent building this
922 # structure too much times?
923 data = headers.rsbac_net_temp_syscall_data_t()
924 return self.__syscall( syscall , data )
928 def getAddresses( self ) :
929 family = self.__syscallGet( headers.NTS_get_address_family ).address_family
930 addr = self.__syscallGet( headers.NTS_get_address ).address
931 def translate( inet ) :
933 for i in range( inet.nr_addr ) :
934 result.append( '%s/%s' % ( intToIpv4( inet.addr[ i ] ) ,
935 inet.valid_bits[ i ] ) )
937 if family == socket.AF_INET :
938 return ( family , translate( addr.inet ) )
939 elif family == socket.AF_UNIX :
940 return ( family , addr.other.addr[ : addr.other.valid_len ] )
944 #name = rsbac_get_net_family_name( family )
945 raise RuntimeError , 'address for family %s not supported' % name
947 def setAddresses( self , addresses ) :
948 if isinstance( addresses , ( int , long ) ) :
949 addresses = ( addresses , () )
950 if not isinstance( addresses , ( tuple , list ) ) \
951 or len( addresses ) != 2 :
953 family , addrs = addresses
954 if not isinstance( family , ( int , long ) ) :
956 data = headers.rsbac_net_temp_syscall_data_t()
957 data.address_family = family
958 self.__syscall( headers.NTS_set_address_family , data )
959 if family == socket.AF_INET :
960 for i , addr in enumerate( addrs ) :
961 a , n = ipv4AndPrefixToInt( addr )
963 data.address.inet.addr[ i ] = a
964 data.address.inet.valid_bits[ i ] = n
967 'only %d addresses allowed, got %d' \
968 % ( i , len( addrs ) )
969 data.address.inet.nr_addr = len( addrs )
970 self.__syscall( headers.NTS_set_address , data )
971 elif family == socket.AF_UNIX :
972 data.address.other.addr = addrs
973 data.address.other.valid_len = len( addrs )
974 self.__syscall( headers.NTS_set_address , data )
977 raise RuntimeError , \
978 'address family %s doesn\'t allows addresses (or is not yet supported)' \
980 addresses = property( getAddresses , setAddresses )
984 def getSocketType( self ) :
985 return self.__syscallGet( headers.NTS_get_type ).type
986 def setSocketType( self , type ) :
987 data = headers.rsbac_net_temp_syscall_data_t()
989 self.__syscall( headers.NTS_set_type , data )
990 socketType = property( getSocketType , setSocketType )
994 def getProtocol( self ) :
995 return self.__syscallGet( headers.NTS_get_protocol ).protocol
996 def setProtocol( self , protocol ) :
997 data = headers.rsbac_net_temp_syscall_data_t()
998 data.protocol = protocol
999 self.__syscall( headers.NTS_set_protocol , data )
1000 protocol = property( getProtocol , setProtocol )
1004 def getNetworkDevice( self ) :
1005 return byteArrayToString( self.__syscallGet( headers.NTS_get_netdev ).netdev )
1006 def setNetworkDevice( self , value ) :
1007 data = headers.rsbac_net_temp_syscall_data_t()
1008 stringToByteArray( data.netdev , str( value ) )
1009 self.__syscall( headers.NTS_set_netdev , data )
1010 def delNetworkDevice( self ) : # FIXME
1011 self.setNetworkDevice( '' )
1012 networkDevice = property( getNetworkDevice , setNetworkDevice , delNetworkDevice )
1016 def getPorts( self ) :
1017 ports = self.__syscallGet( headers.NTS_get_ports ).ports
1019 def mkPortRange( p ) :
1023 return ( p.min , p.max )
1024 return map( mkPortRange , p[ : ports.nr_ports ] )
1025 def setPorts( self , value ) :
1026 data = headers.rsbac_net_temp_syscall_data_t()
1027 p = data.ports.ports
1029 for i , range in enumerate( value ) :
1030 if not isinstance( range , ( tuple , list ) ) :
1031 min , max = range , range
1037 raise IndexError , 'only %d port ranges allowed, got %d' % ( i , len( value ) )
1038 data.ports.nr_ports = len( value )
1039 self.__syscall( headers.NTS_set_ports , data )
1040 def delPorts( self ) : # FIXME
1042 ports = property( getPorts , setPorts , delPorts )
1046 def getName( self ) :
1047 return self.__syscallGet( headers.NTS_get_name ).name
1048 def setName( self , value ) :
1049 data = headers.rsbac_net_temp_syscall_data_t()
1050 slowButCorrectStringAssignation( data , 'name' , value )
1052 raiseIfError( lib.rsbac_net_template( transaction._t ,
1053 headers.NTS_set_name ,
1054 self.nt , byref( data ) ) )
1056 if e[ 0 ] != headers.RSBAC_ENOTFOUND :
1058 self.create( self.nt , value )
1059 name = property( getName , setName )
1063 create = staticmethod( createNetworkTemplate )
1064 def checkId( self ) :
1065 data = headers.rsbac_net_temp_syscall_data_t()
1066 return self.__syscall( headers.NTS_check_id , data ).id
1067 def copyTo( self , target ) :
1068 return copyNetworkTemplate( self.nt , target )
1069 def delete( self ) :
1070 data = headers.rsbac_net_temp_syscall_data_t()
1071 self.__syscall( headers.NTS_delete_template , data )
1073 NetworkTemplate = buildObjectClass( 'NetworkTemplate' ,
1074 ( NetworkTemplateBase , ) ,
1075 headers.T_NETTEMP , False )
1077 def getAllNetworkTemplate() :
1078 arr = fetch( headers.rsbac_net_temp_id_t ,
1079 lambda n , a : lib.rsbac_net_list_all_template( transaction._t , a , n ) )
1080 return sorted( map( int , arr ) )
1082 class NetworkTemplateDict( object ) :
1084 def __repr__( self ) :
1085 return '{' + ', '.join( [ ': '.join( map( str , item ) ) for item in self.items() ] ) + '}'
1086 def __getitem__( self , nt ) :
1087 return NetworkTemplate( nt )
1088 def __delitem__( self , nt ) :
1089 NetworkTemplate( nt ).delete()
1091 return getAllNetworkTemplate()
1092 def values( self ) :
1093 return map( NetworkTemplate , self.keys() )
1095 return [ ( i , NetworkTemplate( i ) ) for i in self.keys() ]
1097 networkTemplates = NetworkTemplateDict()
1099 #-----------------------------------------------------------------------------
1101 for target in ( FDBase , User , Group , Process ,
1102 Ipc , Scd , DeviceBase ,
1103 NetworkDevice , NetworkTemplate , NetworkObject ) :
1104 target.rcTypes = RcTypeDict( target.type )
1106 def listAllDevices() :
1107 arr = fetch( headers.rsbac_dev_desc_t ,
1108 lambda n , a : lib.rsbac_list_all_dev( transaction._t , a , n ) )
1111 return ( a.type < b.type
1112 or ( a.type == b.type
1113 and ( a.major < b.major
1114 or ( a.major == b.major
1115 and a.minor < b.minor ) ) ) )
1116 for item in sorted( arr , cmp ) :
1117 if item.type == headers.D_block :
1118 dev = BlockDevice( item.major , item.minor )
1119 elif item.type == headers.D_block_major :
1120 dev = BlockDevice( item.major )
1121 elif item.type == headers.D_char :
1122 dev = CharacterDevice( item.major , item.minor )
1123 elif item.type == headers.D_char_major :
1124 dev = CharacterDevice( item.major )
1130 def listAllUsers() :
1131 arr = fetch( headers.rsbac_uid_t ,
1132 lambda n , a : lib.rsbac_list_all_user( transaction._t , a , n ) )
1133 return map( User , sorted( arr ) )
1135 def listAllGroups() :
1136 arr = fetch( headers.rsbac_gid_t ,
1137 lambda n , a : lib.rsbac_list_all_group( transaction._t , a , n ) )
1138 return map( User , sorted( arr ) )
1140 from rsbac import acl, auth
1142 defaultFd = FD( None )
1143 defaultFile = File( None )
1144 defaultFifo = Fifo( None )
1145 defaultSymlink = Symlink( None )
1146 defaultDirectory = Directory( None )
1147 defaultDevice = Device( None )
1148 defaultUnixSocket = UnixSocket( None )
1150 defaultProcess = Process( 0 )
1152 defaultIpc = Ipc( 0 )
1154 pseudoUsers = new.module( 'pseudoUsers' )
1155 for k , v in _g_pseudoUsers.items() :
1156 setattr( pseudoUsers , v , User( k ) )
1158 defaultUser = pseudoUsers.no_user
1160 pseudoGroups = new.module( 'pseudoGroups' )
1161 for k , v in _g_pseudoGroups.items() :
1162 setattr( pseudoGroups , v , Group( k ) )
1164 defaultGroup = pseudoGroups.no_group
1166 defaultNetworkDevice = NetworkDevice( '' )
1168 defaultScd = Scd( 0 , None )
1170 system = new.module( 'system' )
1172 def createScdObject() :
1174 for k , v in headers.__dict__.items() :
1175 if k.startswith( prefix ) :
1176 k = k[ len( prefix ) : ]
1178 setattr( system , k , scd )
1180 # Create SystemClock, SystemSysctl, SystemQuota,..
1183 defaultNetworkObject = NetworkObject()
1186 # indent-tabs-mode: nil