Added "selfAcl" attribute to NetworkTemplate.
[py-rsbac] / rsbac / objects.py
1 # -*- coding:utf-8 -*-
2
3 # py-rsbac - RSBAC Python bindings
4 # Copyright (C) 2006  Frederic Jolliton <pyrsbac@tuxee.net>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 __all__ = [
21     'Object' ,
22     'FD' , 'File' , 'Fifo' , 'Symlink' , 'Directory' , 'Device' ,
23     'User' , 'Group' , 'Process' ,
24     'Ipc' , 'IpcSem' , 'IpcMsg' , 'IpcShm' ,
25     'IpcAnonPipe' , 'IpcMqueue' , 'IpcAnonUnix' ,
26     'NetworkDevice' , 'NetworkTemplate'
27     ]
28
29 import sys
30 import new
31 import pwd, grp
32 import socket
33 import re
34 import operator
35 from ctypes import byref
36
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, ttlToInt, intToTtl
44 from rsbac._utils import processName, digits
45
46 # Singleton. Obviously bad for MT. But good for performance..
47 g_attributeValue = headers.rsbac_attribute_value_t()
48 g_attributeValueRef = byref( g_attributeValue )
49
50 from rsbac_auto import g_attributes
51
52 from rsbac.rc import RcTypeDict, Role, Type
53
54 def buildObjectClass( className , parents , target , byName ) :
55     if isinstance( target , tuple ) :
56         target , realTarget = target
57     else :
58         target , realTarget = target , target
59     attrs = {}
60     if byName :
61         fget = lib.rsbac_get_attr_n
62         fset = lib.rsbac_set_attr_n
63         frem = lib.rsbac_remove_target_n
64         amget = lib.rsbac_acl_get_mask_n
65         amset = lib.rsbac_acl_n
66     else :
67         fget = lib.rsbac_get_attr
68         fset = lib.rsbac_set_attr
69         frem = lib.rsbac_remove_target
70         amget = lib.rsbac_acl_get_mask
71         amset = lib.rsbac_acl
72     def remover( id ) :
73         raiseIfError( frem( transaction._t , target , id ) )
74     def mremove( self ) :
75         return remover( self._id )
76     attrs[ 'remover' ] = staticmethod( remover )
77     attrs[ 'remove' ] = mremove
78     def addAclMaskAttribute() :
79         rights = headers.rsbac_acl_rights_vector_t()
80         rightsRef = byref( rights )
81         sm = headers.ACLC_set_mask
82         def getter( id ) :
83             raiseIfError( amget( transaction._t , target , id , rightsRef ) )
84             return rights.value
85         if byName :
86             arg = headers.rsbac_acl_syscall_n_arg_t()
87         else :
88             arg = headers.rsbac_acl_syscall_arg_t()
89         arg.type = target
90         argRef = byref( arg )
91         if byName :
92             def setter( id , mask ) :
93                 arg.name = id
94                 arg.rights = mask
95                 raiseIfError( amset( transaction._t , sm , argRef ) )
96         else :
97             def setter( id , mask ) :
98                 arg.tid = id
99                 arg.rights = mask
100                 raiseIfError( amset( transaction._t , sm , argRef ) )
101         def mget( self ) :
102             return AclRequestVector( getter( self._id ) )
103         def mset( self , value ) :
104             return setter( self._id , int( value ) )
105         attrs[ 'getter_acl_mask' ] = staticmethod( getter )
106         attrs[ 'setter_acl_mask' ] = staticmethod( setter )
107         attrs[ 'get_acl_mask' ] = mget
108         attrs[ 'set_acl_mask' ] = mset
109         attrs[ 'acl_mask' ] = property( mget , mset )
110     def addLogArrayAttribute() :
111         module = headers.SW_GEN
112         attr1 = headers.A_log_array_low
113         attr2 = headers.A_log_array_high
114         def getter( id ) :
115             raiseIfError( fget( transaction._t , module , target , id , attr1 , g_attributeValueRef , 0 ) )
116             v1 = g_attributeValue.log_array_low
117             raiseIfError( fget( transaction._t , module , target , id , attr2 , g_attributeValueRef , 0 ) )
118             v2 = g_attributeValue.log_array_high
119             return tuple( [ int( item[ 0 ] + 2 * item[ 1 ] )
120                             for item in zip( digits( v1 , 2 , 64 ) ,
121                                              digits( v2 , 2 , 64 ) ) ] )
122         def getterEffective( id ) :
123             raiseIfError( fget( transaction._t , module , target ,
124                                 id , attr1 , g_attributeValueRef , 1 ) )
125             v1 = g_attributeValue.log_array_low
126             raiseIfError( fget( transaction._t , module , target ,
127                                 id , attr2 , g_attributeValueRef , 1 ) )
128             v2 = g_attributeValue.log_array_high
129             return tuple( [ int( item[ 0 ] + 2 * item[ 1 ] )
130                             for item in zip( digits( v1 , 2 , 64 ) ,
131                                              digits( v2 , 2 , 64 ) ) ] )
132         def setter( id , value ) :
133             if not isinstance( value , ( tuple , list ) ) or len( value ) != 64 :
134                 raise RuntimeError , 'expected a sequence of 64 elements'
135             v1 , v2 = 0 , 0
136             mask = 1 << 63
137             for item in value :
138                 if item & 1 :
139                     v1 |= mask
140                 if item & 2 :
141                     v2 |= mask
142                 mask >>= 1
143             g_attributeValue.log_array_low = v1
144             raiseIfError( fset( transaction._t , module , target ,
145                                 id , attr1 , g_attributeValueRef , 0 ) )
146             g_attributeValue.log_array_high = v2
147             raiseIfError( fset( transaction._t , module , target ,
148                                 id , attr2 , g_attributeValueRef , 0 ) )
149         def mget( self ) :
150             return getter( self._id )
151         def mgetEffective( self ) :
152             return getterEffective( self._id )
153         def mset( self , value ) :
154             setter( self._id , value )
155         attrs[ 'getter_log_array' ] = staticmethod( getter )
156         attrs[ 'getter_eff_log_array' ] = staticmethod( getterEffective )
157         attrs[ 'setter_log_array' ] = staticmethod( setter )
158         attrs[ 'get_log_array' ] = mget
159         attrs[ 'get_eff_log_array' ] = mgetEffective
160         attrs[ 'set_log_array' ] = mset
161         attrs[ 'log_array' ] = property( mget , mset )
162         attrs[ 'eff_log_array' ] = property( mgetEffective )
163     def addAttribute( module , vid , name , field ,
164                       pre = None , post = None ,
165                       mpre = None , mpost = None ) :
166         #
167         # getter for real value
168         #
169         if post is None :
170             def getter( id ) :
171                 raiseIfError( fget( transaction._t , module , target ,
172                                     id , vid , g_attributeValueRef , 0 ) )
173                 return getattr( g_attributeValue , field )
174         else :
175             def getter( id ) :
176                 raiseIfError( fget( transaction._t , module , target ,
177                                     id , vid , g_attributeValueRef , 0 ) )
178                 return post( getattr( g_attributeValue , field ) )
179         #
180         # getter for effective value
181         #
182         if post is None :
183             def getterEffective( id ) :
184                 raiseIfError( fget( transaction._t , module , target ,
185                                     id , vid , g_attributeValueRef , 1 ) )
186                 return getattr( g_attributeValue , field )
187         else :
188             def getterEffective( id ) :
189                 raiseIfError( fget( transaction._t , module , target ,
190                                     id , vid , g_attributeValueRef , 1 ) )
191                 return post( getattr( g_attributeValue , field ) )
192         #
193         # setter
194         #
195         if pre is None :
196             def setter( id , value ) :
197                 setattr( g_attributeValue , field , value )
198                 raiseIfError( fset( transaction._t , module , target ,
199                                     id , vid , g_attributeValueRef ) )
200         else :
201             def setter( id , value ) :
202                 setattr( g_attributeValue , field , pre( value ) )
203                 raiseIfError( fset( transaction._t , module , target ,
204                                     id , vid , g_attributeValueRef ) )
205         #
206         # member functions
207         #
208         if mpost is None :
209             def mget( self ) :
210                 return getter( self._id )
211             def mgetEffective( self ) :
212                 return getterEffective( self._id )
213         else :
214             if isinstance( mpost , tuple ) :
215                 mpost , withSelf = mpost
216             else :
217                 withSelf = False
218             if not withSelf :
219                 def mget( self ) :
220                     return mpost( getter( self._id ) )
221                 def mgetEffective( self ) :
222                     return mpost( getterEffective( self._id ) )
223             else :
224                 def mget( self ) :
225                     return mpost( getter( self._id ) , self )
226                 def mgetEffective( self ) :
227                     return mpost( getterEffective( self._id ) , self )
228         if mpre is None :
229             def mset( self , value ) :
230                 return setter( self._id , value )
231         else :
232             if isinstance( mpre , tuple ) :
233                 mpre , withSelf = mpost
234             else :
235                 withSelf = False
236             if not withSelf :
237                 def mset( self , value ) :
238                     return setter( self._id , mpre( value ) )
239             else :
240                 def mset( self , value ) :
241                     return setter( self._id , mpre( value , self ) )
242         #
243         attrs[ 'getter_' + name ] = staticmethod( getter )
244         attrs[ 'setter_' + name ] = staticmethod( setter )
245         attrs[ 'getter_eff_' + name ] = staticmethod( getterEffective )
246         #
247         attrs[ 'get_' + name ] = mget
248         attrs[ 'set_' + name ] = mset
249         attrs[ name ] = property( mget , mset )
250         #
251         attrs[ 'get_eff_' + name ] = mgetEffective
252         attrs[ 'eff_' + name ] = property( mgetEffective )
253     attributes = []
254     def raUnpack( value ) :
255         return tuple( map( int , value ) )
256     def raPack( value ) :
257         t = headers.rsbac_res_array_t()
258         t[ : ] = value
259         return t
260     fields = set()
261     for attribute , module , field , ctype , targets in g_attributes :
262         module = getattr( headers , 'SW_' + module )
263         attributeId = getattr( headers , 'A_' + attribute )
264         targets = [ getattr( headers , 'T_' + n ) for n in targets ]
265         if ( target in targets or realTarget in targets ) \
266                 and attribute not in [ 'log_array_low' , 'log_array_high' ] :
267             attributes.append( attribute )
268             if ctype == 'rsbac_jail_ip_t' or field == 'remote_ip' :
269                 mpre , mpost = ipToInt , intToIp
270             elif ctype == 'rsbac_jail_scd_vector_t' :
271                 mpre , mpost = int , JailScdVector
272             elif ctype == 'rsbac_jail_id_t' :
273                 mpre , mpost = int , int
274             elif ctype == 'rsbac_jail_flags_t' :
275                 mpre , mpost = int , JailFlags
276             elif ctype == 'rsbac_boolean_t' :
277                 mpre , mpost = int , bool
278             elif ctype == 'rsbac_rc_role_id_t' :
279                 mpre , mpost = int , Role
280             elif ctype == 'rsbac_rc_type_id_t' :
281                 mpre , mpost = int , lambda n : Type( realTarget , n )
282             elif ctype == 'rsbac_request_vector_t' :
283                 mpre , mpost = int , RequestVector
284             elif ctype == 'rsbac_ff_flags_t' :
285                 mpre , mpost = int , FileFlags
286             elif ctype == 'rsbac_uid_t' :
287                 mpre , mpost = int , lambda n : User( n ) # defer, since User is not yet defined
288             elif ctype == 'rsbac_pax_flags_t' :
289                 mpre , mpost = int , PaxFlags
290             elif ctype == 'rsbac_cap_vector_t' :
291                 mpre , mpost = int , CapsFlags
292             else :
293                 mpre , mpost = None , None
294             if ctype == 'rsbac_res_array_t' :
295                 pre , post = raPack , raUnpack
296             else :
297                 pre , post = None , None
298             addAttribute( module , attributeId , attribute , field ,
299                           pre , post , mpre , mpost )
300         fields.add( field )
301     if 'log_array_low' in fields and 'log_array_high' in fields :
302         addLogArrayAttribute()
303         attributes.append( 'log_array' )
304     addAclMaskAttribute()
305     attrs[ 'type' ] = target
306     attrs[ 'attributes' ] = sorted( attributes )
307     attrs[ '_byName' ] = byName
308     return type( className , parents , attrs )
309
310 class Object( object ) :
311     """Base class for all RSBAC objects.
312
313     """
314     pass
315
316 class ObjectWithAttributes( Object ) :
317     """Base class for objects with RSBAC attributes.
318
319     """
320     def getAllAttributes( self ) :
321         r = {}
322         for name in self.attributes :
323             try :
324                 r[ name ] = getattr( self , name )
325             except Error :
326                 pass
327         return r
328
329 #--[ FD ]---------------------------------------------------------------------
330
331 _g_defaultFd = {}
332
333 class FDBase( ObjectWithAttributes ) :
334     """Base class for FD hierarchy.
335
336     """
337     type = headers.T_FD
338     def __new__( cls , id ) :
339         if id is None :
340             instance = _g_defaultFd.get( cls.type )
341             if instance is None :
342                 instance = ObjectWithAttributes.__new__( cls )
343                 instance.__init_singleton__( id )
344                 _g_defaultFd[ cls.type ] = instance
345         else :
346             instance = ObjectWithAttributes.__new__( cls )
347             instance.__init_singleton__( id )
348         return instance
349     def __init_singleton__( self , id ) :
350         if not isinstance( id , str ) and id is not None :
351             raise TypeError , 'Invalid id %r' % ( id , )
352         self._id = id
353         self.acl = acl.AclByName( self )
354     def __eq__( self , other ) :
355         return self is other or ( isinstance( other , FDBase )
356                                   and self.type == other.type
357                                   and self._id == other._id )
358     def __str__( self ) :
359         return self._id
360     def __repr__( self ) :
361         if self._id is None :
362             return '<Default%s>' % self.__class__.__name__
363         else :
364             return '<%s %r>' % ( self.__class__.__name__ , self._id )
365
366 FD = \
367     buildObjectClass( 'FD' , ( FDBase , ) ,
368                       headers.T_FD , True )
369 File = \
370     buildObjectClass( 'File' , ( FDBase , ) ,
371                       ( headers.T_FILE , headers.T_FD ) , True )
372 Fifo = \
373     buildObjectClass( 'Fifo' , ( FDBase , ) ,
374                       ( headers.T_FIFO , headers.T_FD ) , True )
375 Symlink = \
376     buildObjectClass( 'Symlink' , ( FDBase , ) ,
377                       ( headers.T_SYMLINK , headers.T_FD ) , True )
378 Directory = \
379     buildObjectClass( 'Directory' , ( FDBase , ) ,
380                       ( headers.T_DIR , headers.T_FD ) , True )
381 Device = \
382     buildObjectClass( 'Device' , ( FDBase , ) ,
383                       ( headers.T_DEV , headers.T_FD ) , True )
384
385 UnixSocket = \
386     buildObjectClass( 'UnixSocket' , ( FDBase , ) ,
387                       ( headers.T_UNIXSOCK , headers.T_FD ) , True )
388
389 #--[ Device ]-----------------------------------------------------------------
390
391 class DeviceBase( ObjectWithAttributes ) :
392     type = headers.T_DEV # Needed for RcTypeDict
393
394 class BlockDeviceBase( DeviceBase ) :
395     def __init__( self , major , minor = None ) :
396         super( BlockDeviceBase , self ).__init__()
397         self._dev = ( major , minor )
398         id = headers.rsbac_target_id_t()
399         if minor is not None :
400             id.dev.type = headers.D_block
401             id.dev.major = major
402             id.dev.minor = minor
403         else :
404             id.dev.type = headers.D_block_major
405             id.dev.major = major
406         self._id = byref( id )
407         self.acl = acl.AclById( self )
408     def __eq__( self , other ) :
409         return self is other or ( isinstance( other , BlockDeviceBase )
410                                   and self._dev == other._dev )
411     def __repr__( self ) :
412         if self._dev[ 1 ] is None :
413             dev = self._dev[ 0 ]
414         else :
415             dev = '%d:%d' % ( self._dev )
416         return '<BlockDevice %s>' % dev
417
418 BlockDevice = buildObjectClass( 'BlockDevice' ,
419                                 ( BlockDeviceBase , ) ,
420                                 headers.T_DEV , False )
421
422 class CharacterDeviceBase( DeviceBase ) :
423     def __init__( self , major , minor = None ) :
424         super( CharacterDeviceBase , self ).__init__()
425         self._dev = ( major , minor )
426         id = headers.rsbac_target_id_t()
427         if minor is not None :
428             id.dev.type = headers.D_char
429             id.dev.major = major
430             id.dev.minor = minor
431         else :
432             id.dev.type = headers.D_char_major
433             id.dev.major = major
434         self._id = byref( id )
435         self.acl = acl.AclById( self )
436     def __eq__( self , other ) :
437         return self is other or ( isinstance( other , CharacterDeviceBase )
438                                   and self._dev == other._dev )
439     def __repr__( self ) :
440         if self._dev[ 1 ] is None :
441             dev = self._dev[ 0 ]
442         else :
443             dev = '%d:%d' % ( self._dev )
444         return '<CharacterDevice %s>' % dev
445
446 CharacterDevice = buildObjectClass( 'CharacterDevice' ,
447                                     ( CharacterDeviceBase , ) ,
448                                     headers.T_DEV , False )
449
450 #--[ User ]-------------------------------------------------------------------
451
452 _g_user_mod = headers.rsbac_uid_t( -1 ).value + 1
453 assert _g_user_mod > 0
454 _g_user_max_value = headers.rsbac_uid_t( -32 ).value # FIXME: -32?
455 def _nuser( n ) :
456     n %= _g_user_mod
457     if n >= _g_user_max_value :
458         return n - _g_user_mod
459     else :
460         return n
461 _g_users = {}
462 _g_pseudoUsers = {
463     -3 : 'no_user' ,
464     -4 : 'all_users' ,
465     }
466
467 class UserBase( ObjectWithAttributes ) :
468     def __new__( cls , user ) :
469         user = _nuser( user )
470         if user < 0 :
471             instance = _g_users.get( user )
472             if instance is None :
473                 instance = ObjectWithAttributes.__new__( cls )
474                 instance.__init_singleton__( user )
475                 _g_users[ user ] = instance
476             return instance
477         else :
478             instance = ObjectWithAttributes.__new__( cls )
479             instance.__init_singleton__( user )
480             return instance
481     def __init_singleton__( self , user ) :
482         ObjectWithAttributes.__init__( self )
483         id = lib.rsbac_target_id_t()
484         if isinstance( user , ( int , long ) ) :
485             uid = user
486         elif isinstance( user , ( str , unicode ) ) :
487             uid = pwd.getpwnam( user )[ 2 ]
488         else :
489             raise RuntimeError , 'Unexpected user id %r' % ( user , )
490         id.user = uid
491         self.uid = uid
492         self._id = byref( id )
493         self.acl = acl.AclById( self )
494     def __int__( self ) :
495         return int( self.uid )
496     def __long__( self ) :
497         return long( self.uid )
498     def __eq__( self , other ) :
499         return self is other or ( isinstance( other , UserBase )
500                                   and self.uid == other.uid )
501     def __repr__( self ) :
502         if self.uid < 0 :
503             return '<PseudoUser %s>' % ( _g_pseudoUsers.get( self.uid , self.uid ) , )
504         else :
505             return '<User %d>' % self.uid
506     def removeFromAcl( self ) :
507         return acl.aclRemoveUser( self.uid )
508
509 User = buildObjectClass( 'User' , ( UserBase , ) , headers.T_USER , False )
510
511 #--[ Group ]------------------------------------------------------------------
512
513 _g_group_mod = headers.rsbac_gid_t( -1 ).value + 1
514 assert _g_group_mod > 0
515 _g_group_max_value = headers.rsbac_gid_t( -32 ).value # FIXME: -32?
516 def _ngroup( n ) :
517     n %= _g_group_mod
518     if n >= _g_group_max_value :
519         return n - _g_group_mod
520     else :
521         return n
522 _g_groups = {}
523 _g_pseudoGroups = {
524     -3 : 'no_group' ,
525     -4 : 'all_groups' ,
526     }
527
528 class GroupBase( ObjectWithAttributes ) :
529     def __new__( cls , group ) :
530         group = _ngroup( group )
531         if group < 0 :
532             instance = _g_groups.get( group )
533             if instance is None :
534                 instance = ObjectWithAttributes.__new__( cls )
535                 instance.__init_singleton__( group )
536                 _g_groups[ group ] = instance
537             return instance
538         else :
539             instance = ObjectWithAttributes.__new__( cls )
540             instance.__init_singleton__( group )
541             return instance
542     def __init_singleton__( self , group ) :
543         ObjectWithAttributes.__init__( group )
544         id = headers.rsbac_target_id_t()
545         if isinstance( group , ( int , long ) ) :
546             gid = group
547         elif isinstance( group , ( str , unicode ) ) :
548             gid = grp.getgrnam( group )[ 2 ]
549         else :
550             raise RuntimeError , 'Unexpected group id %r' % ( group , )
551         id.group = gid
552         self.gid = gid
553         self._id = byref( id )
554         self.acl = acl.AclById( self )
555     def __int__( self ) :
556         return int( self.gid )
557     def __long__( self ) :
558         return long( self.gid )
559     def __eq__( self , other ) :
560         return self is other or ( isinstance( other , GroupBase )
561                                   and self.gid == other.gid )
562     def __repr__( self ) :
563         if self.gid < 0 :
564             return '<PseudoGroup %s>' % ( _g_pseudoGroups.get( self.gid , self.gid ) , )
565         else :
566             return '<Group %d>' % self.gid
567
568 Group = buildObjectClass( 'Group' , ( GroupBase , ) , headers.T_GROUP , False )
569
570 #--[ Process ]----------------------------------------------------------------
571
572 class ProcessBase( ObjectWithAttributes ) :
573     def __init__( self , process ) :
574         super( ProcessBase , self ).__init__()
575         id = headers.rsbac_target_id_t()
576         id.process = process
577         self.pid = process
578         self._id = byref( id )
579         self.acl = acl.AclById( self )
580     def __int__( self ) :
581         return int( self.pid )
582     def __long__( self ) :
583         return long( self.pid )
584     def __eq__( self , other ) :
585         return self is other or ( isinstance( other , ProcessBase )
586                                   and self.pid == other.pid )
587     def __repr__( self ) :
588         if self.pid == 0 :
589             return '<DefaultProcess>'
590         else :
591             return '<Process %d %r>' % ( self.pid , processName( self.pid ) )
592
593 Process = buildObjectClass( 'Process' , ( ProcessBase , ) , headers.T_PROCESS , False )
594
595 #--[ IPC ]--------------------------------------------------------------------
596
597 class IpcBase( ObjectWithAttributes ) :
598     ipc = headers.I_none
599     def __init__( self , ipcId ) :
600         super( IpcBase , self ).__init__()
601         id = headers.rsbac_target_id_t()
602         id.ipc.type = self.ipc
603         id.ipc.id.id_nr = ipcId
604         self._id = byref( id )
605         self.id = ipcId
606         self.acl = acl.AclById( self )
607     def __int__( self ) :
608         return int( self.id )
609     def __long__( self ) :
610         return long( self.id )
611     def __repr__( self ) :
612         if self.ipc == headers.I_none and self.id == 0 :
613             return '<DefaultIpc>'
614         else :
615             return '<%s %d>' % ( self.__class__.__name__ , self.id )
616
617 Ipc = buildObjectClass( 'Ipc' , ( IpcBase , ) , headers.T_IPC , False )
618
619 class IpcSem( Ipc ) :
620     ipc = headers.I_sem
621
622 class IpcMsg( Ipc ) :
623     ipc = headers.I_msg
624
625 class IpcShm( Ipc ) :
626     ipc = headers.I_shm
627
628 class IpcAnonPipe( Ipc ) :
629     ipc = headers.I_anonpipe
630
631 class IpcMqueue( Ipc ) :
632     ipc = headers.I_mqueue
633
634 class IpcAnonUnix( Ipc ) :
635     ipc = headers.I_anonunix
636
637 #--[ SCD ]--------------------------------------------------------------------
638
639 g_scd = {}
640
641 class Scd( Object ) :
642     type = headers.T_SCD
643     def __new__( cls , target , *args , **kwargs ) :
644         instance = g_scd.get( target )
645         if instance is None :
646             instance = object.__new__( cls )
647             instance.__init_singleton__( target , *args , **kwargs )
648             g_scd[ target ] = instance
649         return instance
650     def __init_singleton__( self , target , name ) :
651         super( Scd , self ).__init__()
652         id = lib.rsbac_target_id_t()
653         id.scd = target
654         self._id = byref( id )
655         self.id = target
656         self.name = name
657         self.acl = acl.AclById( self )
658     def getRcType( self ) :
659         return Type( self.type , self.id )
660     rc_type = property( getRcType )
661     def __repr__( self ) :
662         if self.name is None :
663             return '<DefaultSCD>'
664         else :
665             return '<SCD %s>' % self.name
666
667 #--[ NetworkObject ]----------------------------------------------------------
668
669 _g_networkObject = None
670
671 class NetworkObject( Object ) :
672     type = headers.T_NETOBJ
673     def __new__( cls ) :
674         global _g_networkObject
675         if _g_networkObject is None :
676             _g_networkObject = Object.__new__( cls )
677             _g_networkObject.__init_singleton__()
678         return _g_networkObject
679     def __init_singleton__( self ) :
680         id = headers.rsbac_target_id_t()
681         id.netobj.sock_p = None
682         id.netobj.local_addr = None
683         id.netobj.local_len = 0
684         id.netobj.remote_addr = None
685         id.netobj.remote_len = 0
686         self._id = byref( id )
687         self.acl = acl.AclById( self )
688     def __repr__( self ) :
689         return '<NetworkObject>'
690
691 #--[ NetworkDevice ]----------------------------------------------------------
692
693 # Not exported. Included in NetworkDevice class.
694 def getAllNetworkDevice() :
695     """*Return a list of all network devices involved with RSBAC rules."""
696     arr = fetch( headers.rsbac_netdev_id_t ,
697                  lambda n , a : lib.rsbac_net_list_all_netdev( transaction._t , a , n ) )
698     return sorted( map( byteArrayToString , arr ) )
699
700 class NetworkDeviceBase( ObjectWithAttributes ) :
701     def __init__( self , name ) :
702         super( NetworkDeviceBase , self ).__init__()
703         id = headers.rsbac_target_id_t()
704         stringToByteArray( id.netdev , name , minPadding = 1 )
705         self._name = name
706         self._id = byref( id )
707         self.acl = acl.AclById( self )
708     def __eq__( self , other ) :
709         return self is other or ( isinstance( other , NetworkDeviceBase )
710                                   and self._name == other._name )
711     def __str__( self ) :
712         return self._name
713     def __repr__( self ) :
714         if self._name == '' :
715             return '<DefaultNetworkDevice>'
716         else :
717             return '<NetworkDevice %r>' % ( self._name , )
718     all = staticmethod( getAllNetworkDevice )
719
720 NetworkDevice = buildObjectClass( 'NetworkDeviceBase' ,
721                                   ( NetworkDeviceBase , ) ,
722                                   headers.T_NETDEV , False )
723
724 #--[ NetworkTemplate ]--------------------------------------------------------
725
726 def intToIpv4( n ) :
727     #assert 0 <= n < 2**32
728     n , a = divmod( n , 256 )
729     n , b = divmod( n , 256 )
730     n , c = divmod( n , 256 )
731     d = n
732     return '.'.join( map( str , ( a , b , c , d ) ) )
733
734 g_reDigitsOnly = re.compile( r'^\d+$' )
735
736 def ipv4ToInt( s ) :
737     ns = s.split( '.' )
738     if len( ns ) != 4 :
739         raise RuntimeError , 'invalid IP'
740     a = 0
741     for n in reversed( ns ) :
742         if not g_reDigitsOnly.match( n ) :
743             raise RuntimeError , 'invalid IP'
744         n = int( n )
745         if not 0 <= n <= 255 :
746             raise RuntimeError , 'invalid IP'
747         a = 256 * a + n
748     return a
749
750 def ipv4AndPrefixToInt( s ) :
751     if '/' not in s :
752         ip , prefix = s , 32
753     else :
754         ip , prefix = s.split( '/' , 1 )
755         if not g_reDigitsOnly.match( prefix ) :
756             raise RuntimeError, 'invalid prefix'
757         prefix = int( prefix )
758     ip = ipv4ToInt( ip )
759     if not 0 <= prefix <= 32 :
760         raise RuntimeError , 'invalid prefix'
761     return ip , prefix
762
763 # Not exported. Included in NetworkTemplate class.
764 def newNetworkTemplate( id , name ) :
765     data = headers.rsbac_net_temp_syscall_data_t()
766     data.name = name
767     raiseIfError( lib.rsbac_net_template( transaction._t ,
768                                           headers.NTS_new_template ,
769                                           id , byref( data ) ) )
770     nt = NetworkTemplate( id )
771     if nt.name != name :
772         raise RuntimeError , \
773             'error while constructing network template with name %r (got back %r instead)' \
774             % ( name , nt.name )
775     return nt
776
777 # Not exported. Included in NetworkTemplate class.
778 def copyNetworkTemplate( source , dest ) :
779     data = headers.rsbac_net_temp_syscall_data_t()
780     data.id = source
781     raiseIfError( lib.rsbac_net_template( transaction._t ,
782                                           headers.NTS_copy_template ,
783                                           dest , byref( data ) ) )
784     return NetworkTemplate( dest )
785
786 class _NetworkTemplateSelf( object ) :
787     type = headers.T_NETTEMP_NT
788     def __init__( self , nt ) :
789         id = headers.rsbac_target_id_t()
790         id.nettemp = nt
791         self._id = byref( id )
792         self.nt = nt
793         self.acl = acl.AclById( self )
794     def __repr__( self ) :
795         return '<NetworkTemplate[Self] %d>' % self.nt
796
797 class NetworkTemplateBase( ObjectWithAttributes ) :
798     def __init__( self , nt ) :
799         super( NetworkTemplateBase , self ).__init__()
800         id = headers.rsbac_target_id_t()
801         id.nettemp = nt
802         self._id = byref( id )
803         self.nt = nt
804         self.acl = acl.AclById( self )
805         self.selfAcl = acl.AclById( _NetworkTemplateSelf( nt ) )
806     def __repr__( self ) :
807         try :
808             name = `self.getName()`
809         except Error :
810             name = 'undefined'
811         return '<%s [%d] %s>' % ( self.__class__.__name__ , self.nt , name )
812     def __syscall( self , syscall , data ) :
813         raiseIfError( lib.rsbac_net_template( transaction._t , syscall ,
814                                               self.nt , byref( data ) ) )
815         return data
816     def __syscallGet( self , syscall ) :
817         # FIXME: Use a shared 'data' to prevent building this
818         # structure too much times?
819         data = headers.rsbac_net_temp_syscall_data_t()
820         return self.__syscall( syscall , data )
821     #
822     # addresses
823     #
824     def getAddresses( self ) :
825         family = self.__syscallGet( headers.NTS_get_address_family ).address_family
826         addr = self.__syscallGet( headers.NTS_get_address ).address
827         def translate( inet ) :
828             result = []
829             for i in range( inet.nr_addr ) :
830                 result.append( '%s/%s' % ( intToIpv4( inet.addr[ i ] ) ,
831                                            inet.valid_bits[ i ] ) )
832             return result
833         if family == socket.AF_INET :
834             return ( family , translate( addr.inet ) )
835         elif family == socket.AF_UNIX :
836             return ( family , addr.other.addr[ : addr.other.valid_len ] )
837         else :
838             if addr.other.addr :
839                 name = str( family )
840                 #name = rsbac_get_net_family_name( family )
841                 raise RuntimeError , 'address for family %s not supported' % name
842             return ( family , )
843     def setAddresses( self , addresses ) :
844         if isinstance( addresses , ( int , long ) ) :
845             addresses = ( addresses , () )
846         if not isinstance( addresses , ( tuple , list ) ) \
847                 or len( addresses ) != 2 :
848             raise RuntimeError
849         family , addrs = addresses
850         if not isinstance( family , ( int , long ) ) :
851             raise RuntimeError
852         data = headers.rsbac_net_temp_syscall_data_t()
853         data.address_family = family
854         self.__syscall( headers.NTS_set_address_family , data )
855         if family == socket.AF_INET :
856             for i , addr in enumerate( addrs ) :
857                 a , n = ipv4AndPrefixToInt( addr )
858                 try :
859                     data.address.inet.addr[ i ] = a
860                     data.address.inet.valid_bits[ i ] = n
861                 except IndexError :
862                     raise IndexError , \
863                         'only %d addresses allowed, got %d' \
864                         % ( i , len( addrs ) )
865             data.address.inet.nr_addr = len( addrs )
866             self.__syscall( headers.NTS_set_address , data )
867         elif family == socket.AF_UNIX :
868             data.address.other.addr = addrs
869             data.address.other.valid_len = len( addrs )
870             self.__syscall( headers.NTS_set_address , data )
871         else :
872             if addrs :
873                 raise RuntimeError , \
874                     'address family %s doesn\'t allows addresses (or is not yet supported)' \
875                     % family
876     addresses = property( getAddresses , setAddresses )
877     #
878     # type
879     #
880     def getSocketType( self ) :
881         return self.__syscallGet( headers.NTS_get_type ).type
882     def setSocketType( self , type ) :
883         data = headers.rsbac_net_temp_syscall_data_t()
884         data.type = type
885         self.__syscall( headers.NTS_set_type , data )
886     socketType = property( getSocketType , setSocketType )
887     #
888     # protocol
889     #
890     def getProtocol( self ) :
891         return self.__syscallGet( headers.NTS_get_protocol ).protocol
892     def setProtocol( self , protocol ) :
893         data = headers.rsbac_net_temp_syscall_data_t()
894         data.protocol = protocol
895         self.__syscall( headers.NTS_set_protocol , data )
896     protocol = property( getProtocol , setProtocol )
897     #
898     # netdev
899     #
900     def getNetworkDevice( self ) :
901         return byteArrayToString( self.__syscallGet( headers.NTS_get_netdev ).netdev )
902     def setNetworkDevice( self , value ) :
903         data = headers.rsbac_net_temp_syscall_data_t()
904         stringToByteArray( data.netdev , str( value ) )
905         self.__syscall( headers.NTS_set_netdev , data )
906     def delNetworkDevice( self ) : # FIXME
907         self.setNetworkDevice( '' )
908     networkDevice = property( getNetworkDevice , setNetworkDevice , delNetworkDevice )
909     #
910     # ports
911     #
912     def getPorts( self ) :
913         ports = self.__syscallGet( headers.NTS_get_ports ).ports
914         p = ports.ports
915         def mkPortRange( p ) :
916             if p.min == p.max :
917                 return p.min
918             else :
919                 return ( p.min , p.max )
920         return map( mkPortRange , p[ : ports.nr_ports ] )
921     def setPorts( self , value ) :
922         data = headers.rsbac_net_temp_syscall_data_t()
923         p = data.ports.ports
924         try :
925             for i , range in enumerate( value ) :
926                 if not isinstance( range , ( tuple , list ) ) :
927                     min , max = range , range
928                 else :
929                     min , max = range
930                 p[ i ].min = min
931                 p[ i ].max = max
932         except IndexError :
933             raise IndexError , 'only %d port ranges allowed, got %d' % ( i , len( value ) )
934         data.ports.nr_ports = len( value )
935         self.__syscall( headers.NTS_set_ports , data )
936     def delPorts( self ) : # FIXME
937         self.setPorts( () )
938     ports = property( getPorts , setPorts , delPorts )
939     #
940     # name
941     #
942     def getName( self ) :
943         return self.__syscallGet( headers.NTS_get_name ).name
944     def setName( self , value ) :
945         data = headers.rsbac_net_temp_syscall_data_t()
946         slowButCorrectStringAssignation( data , 'name' , value )
947         try :
948             raiseIfError( lib.rsbac_net_template( transaction._t ,
949                                                   headers.NTS_set_name ,
950                                                   self.nt , byref( data ) ) )
951         except Error , e :
952             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
953                 raise
954             newNetworkTemplate( self.nt , value )
955     name = property( getName , setName )
956     #
957     # misc
958     #
959     create = staticmethod( newNetworkTemplate )
960     def checkId( self ) :
961         data = headers.rsbac_net_temp_syscall_data_t()
962         return self.__syscall( headers.NTS_check_id , data ).id
963     def copyTo( self , target ) :
964         return copyNetworkTemplate( self.nt , target )
965     def delete( self ) :
966         data = headers.rsbac_net_temp_syscall_data_t()
967         self.__syscall( headers.NTS_delete_template , data )
968
969 NetworkTemplate = buildObjectClass( 'NetworkTemplate' ,
970                                     ( NetworkTemplateBase , ) ,
971                                     headers.T_NETTEMP , False )
972
973 def getAllNetworkTemplate() :
974     arr = fetch( headers.rsbac_net_temp_id_t ,
975                  lambda n , a : lib.rsbac_net_list_all_template( transaction._t , a , n ) )
976     return sorted( map( int , arr ) )
977
978 class NetworkTemplateDict( object ) :
979     def __repr__( self ) :
980         return '{' + ', '.join( [ ': '.join( map( str , item ) ) for item in self.items() ] ) + '}'
981     def __getitem__( self , nt ) :
982         return NetworkTemplate( nt )
983     def __delitem__( self , nt ) :
984         NetworkTemplate( nt ).delete()
985     def keys( self ) :
986         return getAllNetworkTemplate()
987     def values( self ) :
988         return map( NetworkTemplate , self.keys() )
989     def items( self ) :
990         return [ ( i , NetworkTemplate( i ) ) for i in self.keys() ]
991
992 networkTemplates = NetworkTemplateDict()
993
994 #-----------------------------------------------------------------------------
995
996 for target in ( FDBase , User , Group , Process ,
997                 Ipc , Scd , DeviceBase ,
998                 NetworkDevice , NetworkTemplate , NetworkObject ) :
999     target.rcTypes = RcTypeDict( target.type )
1000
1001 def listAllDevices() :
1002     arr = fetch( headers.rsbac_dev_desc_t ,
1003                  lambda n , a : lib.rsbac_list_all_dev( transaction._t , a , n ) )
1004     r = []
1005     def cmp( a , b ) :
1006         return ( a.type < b.type
1007                  or ( a.type == b.type
1008                       and ( a.major < b.major
1009                             or ( a.major == b.major
1010                                  and a.minor < b.minor ) ) ) )
1011     for item in sorted( arr , cmp ) :
1012         if item.type == headers.D_block :
1013             dev = BlockDevice( item.major , item.minor )
1014         elif item.type == headers.D_block_major :
1015             dev = BlockDevice( item.major )
1016         elif item.type == headers.D_char :
1017             dev = CharacterDevice( item.major , item.minor )
1018         elif item.type == headers.D_char_major :
1019             dev = CharacterDevice( item.major )
1020         else :
1021             raise NotReached
1022         r.append( dev )
1023     return r
1024
1025 def listAllUsers() :
1026     arr = fetch( headers.rsbac_uid_t ,
1027                  lambda n , a : lib.rsbac_list_all_user( transaction._t , a , n ) )
1028     return map( User , sorted( arr ) )
1029
1030 def listAllGroups() :
1031     arr = fetch( headers.rsbac_gid_t ,
1032                  lambda n , a : lib.rsbac_list_all_group( transaction._t , a , n ) )
1033     return map( User , sorted( arr ) )
1034
1035 from rsbac import acl
1036
1037 defaultFd = FD( None )
1038 defaultFile = File( None )
1039 defaultFifo = Fifo( None )
1040 defaultSymlink = Symlink( None )
1041 defaultDirectory = Directory( None )
1042 defaultDevice = Device( None )
1043 defaultUnixSocket = UnixSocket( None )
1044
1045 defaultProcess = Process( 0 )
1046
1047 defaultIpc = Ipc( 0 )
1048
1049 pseudoUsers = new.module( 'pseudoUsers' )
1050 for k , v in _g_pseudoUsers.items() :
1051     setattr( pseudoUsers , v , User( k ) )
1052
1053 defaultUser = pseudoUsers.no_user
1054
1055 pseudoGroups = new.module( 'pseudoGroups' )
1056 for k , v in _g_pseudoGroups.items() :
1057     setattr( pseudoGroups , v , Group( k ) )
1058
1059 defaultGroup = pseudoGroups.no_group
1060
1061 defaultNetworkDevice = NetworkDevice( '' )
1062
1063 defaultScd = Scd( 0 , None )
1064
1065 system = new.module( 'system' )
1066
1067 def createScdObject() :
1068     prefix = 'ST_'
1069     for k , v in headers.__dict__.items() :
1070         if k.startswith( prefix ) :
1071             k = k[ len( prefix ) : ]
1072             scd = Scd( v , k )
1073             setattr( system , k , scd )
1074
1075 # Create SystemClock, SystemSysctl, SystemQuota,..
1076 createScdObject()
1077
1078 defaultNetworkObject = NetworkObject()
1079
1080 # Local Variables:
1081 # indent-tabs-mode: nil
1082 # python-indent: 4
1083 # End: