159e8a27ac793200b28ecb9582ce998932b79429
[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 NetworkTemplateBase( ObjectWithAttributes ) :
787     def __init__( self , nt ) :
788         super( NetworkTemplateBase , self ).__init__()
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         try :
796             name = `self.getName()`
797         except Error :
798             name = 'undefined'
799         return '<%s [%d] %s>' % ( self.__class__.__name__ , self.nt , name )
800     def __syscall( self , syscall , data ) :
801         raiseIfError( lib.rsbac_net_template( transaction._t , syscall ,
802                                               self.nt , byref( data ) ) )
803         return data
804     def __syscallGet( self , syscall ) :
805         # FIXME: Use a shared 'data' to prevent building this
806         # structure too much times?
807         data = headers.rsbac_net_temp_syscall_data_t()
808         return self.__syscall( syscall , data )
809     #
810     # addresses
811     #
812     def getAddresses( self ) :
813         family = self.__syscallGet( headers.NTS_get_address_family ).address_family
814         addr = self.__syscallGet( headers.NTS_get_address ).address
815         def translate( inet ) :
816             result = []
817             for i in range( inet.nr_addr ) :
818                 result.append( '%s/%s' % ( intToIpv4( inet.addr[ i ] ) ,
819                                            inet.valid_bits[ i ] ) )
820             return result
821         if family == socket.AF_INET :
822             return ( family , translate( addr.inet ) )
823         elif family == socket.AF_UNIX :
824             return ( family , addr.other.addr[ : addr.other.valid_len ] )
825         else :
826             if addr.other.addr :
827                 name = str( family )
828                 #name = rsbac_get_net_family_name( family )
829                 raise RuntimeError , 'address for family %s not supported' % name
830             return ( family , )
831     def setAddresses( self , addresses ) :
832         if isinstance( addresses , ( int , long ) ) :
833             addresses = ( addresses , () )
834         if not isinstance( addresses , ( tuple , list ) ) \
835                 or len( addresses ) != 2 :
836             raise RuntimeError
837         family , addrs = addresses
838         if not isinstance( family , ( int , long ) ) :
839             raise RuntimeError
840         data = headers.rsbac_net_temp_syscall_data_t()
841         data.address_family = family
842         self.__syscall( headers.NTS_set_address_family , data )
843         if family == socket.AF_INET :
844             for i , addr in enumerate( addrs ) :
845                 a , n = ipv4AndPrefixToInt( addr )
846                 try :
847                     data.address.inet.addr[ i ] = a
848                     data.address.inet.valid_bits[ i ] = n
849                 except IndexError :
850                     raise IndexError , \
851                         'only %d addresses allowed, got %d' \
852                         % ( i , len( addrs ) )
853             data.address.inet.nr_addr = len( addrs )
854             self.__syscall( headers.NTS_set_address , data )
855         elif family == socket.AF_UNIX :
856             data.address.other.addr = addrs
857             data.address.other.valid_len = len( addrs )
858             self.__syscall( headers.NTS_set_address , data )
859         else :
860             if addrs :
861                 raise RuntimeError , \
862                     'address family %s doesn\'t allows addresses (or is not yet supported)' \
863                     % family
864     addresses = property( getAddresses , setAddresses )
865     #
866     # type
867     #
868     def getSocketType( self ) :
869         return self.__syscallGet( headers.NTS_get_type ).type
870     def setSocketType( self , type ) :
871         data = headers.rsbac_net_temp_syscall_data_t()
872         data.type = type
873         self.__syscall( headers.NTS_set_type , data )
874     socketType = property( getSocketType , setSocketType )
875     #
876     # protocol
877     #
878     def getProtocol( self ) :
879         return self.__syscallGet( headers.NTS_get_protocol ).protocol
880     def setProtocol( self , protocol ) :
881         data = headers.rsbac_net_temp_syscall_data_t()
882         data.protocol = protocol
883         self.__syscall( headers.NTS_set_protocol , data )
884     protocol = property( getProtocol , setProtocol )
885     #
886     # netdev
887     #
888     def getNetworkDevice( self ) :
889         return byteArrayToString( self.__syscallGet( headers.NTS_get_netdev ).netdev )
890     def setNetworkDevice( self , value ) :
891         data = headers.rsbac_net_temp_syscall_data_t()
892         stringToByteArray( data.netdev , str( value ) )
893         self.__syscall( headers.NTS_set_netdev , data )
894     def delNetworkDevice( self ) : # FIXME
895         self.setNetworkDevice( '' )
896     networkDevice = property( getNetworkDevice , setNetworkDevice , delNetworkDevice )
897     #
898     # ports
899     #
900     def getPorts( self ) :
901         ports = self.__syscallGet( headers.NTS_get_ports ).ports
902         p = ports.ports
903         def mkPortRange( p ) :
904             if p.min == p.max :
905                 return p.min
906             else :
907                 return ( p.min , p.max )
908         return map( mkPortRange , p[ : ports.nr_ports ] )
909     def setPorts( self , value ) :
910         data = headers.rsbac_net_temp_syscall_data_t()
911         p = data.ports.ports
912         try :
913             for i , range in enumerate( value ) :
914                 if not isinstance( range , ( tuple , list ) ) :
915                     min , max = range , range
916                 else :
917                     min , max = range
918                 p[ i ].min = min
919                 p[ i ].max = max
920         except IndexError :
921             raise IndexError , 'only %d port ranges allowed, got %d' % ( i , len( value ) )
922         data.ports.nr_ports = len( value )
923         self.__syscall( headers.NTS_set_ports , data )
924     def delPorts( self ) : # FIXME
925         self.setPorts( () )
926     ports = property( getPorts , setPorts , delPorts )
927     #
928     # name
929     #
930     def getName( self ) :
931         return self.__syscallGet( headers.NTS_get_name ).name
932     def setName( self , value ) :
933         data = headers.rsbac_net_temp_syscall_data_t()
934         slowButCorrectStringAssignation( data , 'name' , value )
935         try :
936             raiseIfError( lib.rsbac_net_template( transaction._t ,
937                                                   headers.NTS_set_name ,
938                                                   self.nt , byref( data ) ) )
939         except Error , e :
940             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
941                 raise
942             newNetworkTemplate( self.nt , value )
943     name = property( getName , setName )
944     #
945     # misc
946     #
947     create = staticmethod( newNetworkTemplate )
948     def checkId( self ) :
949         data = headers.rsbac_net_temp_syscall_data_t()
950         return self.__syscall( headers.NTS_check_id , data ).id
951     def copyTo( self , target ) :
952         return copyNetworkTemplate( self.nt , target )
953     def delete( self ) :
954         data = headers.rsbac_net_temp_syscall_data_t()
955         self.__syscall( headers.NTS_delete_template , data )
956
957 NetworkTemplate = buildObjectClass( 'NetworkTemplate' ,
958                                     ( NetworkTemplateBase , ) ,
959                                     headers.T_NETTEMP , False )
960
961 def getAllNetworkTemplate() :
962     arr = fetch( headers.rsbac_net_temp_id_t ,
963                  lambda n , a : lib.rsbac_net_list_all_template( transaction._t , a , n ) )
964     return sorted( map( int , arr ) )
965
966 class NetworkTemplateDict( object ) :
967     def __repr__( self ) :
968         return '{' + ', '.join( [ ': '.join( map( str , item ) ) for item in self.items() ] ) + '}'
969     def __getitem__( self , nt ) :
970         return NetworkTemplate( nt )
971     def __delitem__( self , nt ) :
972         NetworkTemplate( nt ).delete()
973     def keys( self ) :
974         return getAllNetworkTemplate()
975     def values( self ) :
976         return map( NetworkTemplate , self.keys() )
977     def items( self ) :
978         return [ ( i , NetworkTemplate( i ) ) for i in self.keys() ]
979
980 networkTemplates = NetworkTemplateDict()
981
982 #-----------------------------------------------------------------------------
983
984 for target in ( FDBase , User , Group , Process ,
985                 Ipc , Scd , DeviceBase ,
986                 NetworkDevice , NetworkTemplate , NetworkObject ) :
987     target.rcTypes = RcTypeDict( target.type )
988
989 def listAllDevices() :
990     arr = fetch( headers.rsbac_dev_desc_t ,
991                  lambda n , a : lib.rsbac_list_all_dev( transaction._t , a , n ) )
992     r = []
993     def cmp( a , b ) :
994         return ( a.type < b.type
995                  or ( a.type == b.type
996                       and ( a.major < b.major
997                             or ( a.major == b.major
998                                  and a.minor < b.minor ) ) ) )
999     for item in sorted( arr , cmp ) :
1000         if item.type == headers.D_block :
1001             dev = BlockDevice( item.major , item.minor )
1002         elif item.type == headers.D_block_major :
1003             dev = BlockDevice( item.major )
1004         elif item.type == headers.D_char :
1005             dev = CharacterDevice( item.major , item.minor )
1006         elif item.type == headers.D_char_major :
1007             dev = CharacterDevice( item.major )
1008         else :
1009             raise NotReached
1010         r.append( dev )
1011     return r
1012
1013 def listAllUsers() :
1014     arr = fetch( headers.rsbac_uid_t ,
1015                  lambda n , a : lib.rsbac_list_all_user( transaction._t , a , n ) )
1016     return map( User , sorted( arr ) )
1017
1018 def listAllGroups() :
1019     arr = fetch( headers.rsbac_gid_t ,
1020                  lambda n , a : lib.rsbac_list_all_group( transaction._t , a , n ) )
1021     return map( User , sorted( arr ) )
1022
1023 from rsbac import acl
1024
1025 defaultFd = FD( None )
1026 defaultFile = File( None )
1027 defaultFifo = Fifo( None )
1028 defaultSymlink = Symlink( None )
1029 defaultDirectory = Directory( None )
1030 defaultDevice = Device( None )
1031 defaultUnixSocket = UnixSocket( None )
1032
1033 defaultProcess = Process( 0 )
1034
1035 defaultIpc = Ipc( 0 )
1036
1037 pseudoUsers = new.module( 'pseudoUsers' )
1038 for k , v in _g_pseudoUsers.items() :
1039     setattr( pseudoUsers , v , User( k ) )
1040
1041 defaultUser = pseudoUsers.no_user
1042
1043 pseudoGroups = new.module( 'pseudoGroups' )
1044 for k , v in _g_pseudoGroups.items() :
1045     setattr( pseudoGroups , v , Group( k ) )
1046
1047 defaultGroup = pseudoGroups.no_group
1048
1049 defaultNetworkDevice = NetworkDevice( '' )
1050
1051 defaultScd = Scd( 0 , None )
1052
1053 system = new.module( 'system' )
1054
1055 def createScdObject() :
1056     prefix = 'ST_'
1057     for k , v in headers.__dict__.items() :
1058         if k.startswith( prefix ) :
1059             k = k[ len( prefix ) : ]
1060             scd = Scd( v , k )
1061             setattr( system , k , scd )
1062
1063 # Create SystemClock, SystemSysctl, SystemQuota,..
1064 createScdObject()
1065
1066 defaultNetworkObject = NetworkObject()
1067
1068 # Local Variables:
1069 # indent-tabs-mode: nil
1070 # python-indent: 4
1071 # End: