3391c456b748da6af4ba05dc52ab1ee463218ca4
[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 #--[ Device ]-----------------------------------------------------------------
386
387 class DeviceBase( ObjectWithAttributes ) :
388     type = headers.T_DEV # Needed for RcTypeDict
389
390 class BlockDeviceBase( DeviceBase ) :
391     def __init__( self , major , minor = None ) :
392         super( BlockDeviceBase , self ).__init__()
393         self._dev = ( major , minor )
394         id = headers.rsbac_target_id_t()
395         if minor is not None :
396             id.dev.type = headers.D_block
397             id.dev.major = major
398             id.dev.minor = minor
399         else :
400             id.dev.type = headers.D_block_major
401             id.dev.major = major
402         self._id = byref( id )
403         self.acl = acl.AclById( self )
404     def __eq__( self , other ) :
405         return self is other or ( isinstance( other , BlockDeviceBase )
406                                   and self._dev == other._dev )
407     def __repr__( self ) :
408         if self._dev[ 1 ] is None :
409             dev = self._dev[ 0 ]
410         else :
411             dev = '%d:%d' % ( self._dev )
412         return '<BlockDevice %s>' % dev
413
414 BlockDevice = buildObjectClass( 'BlockDevice' ,
415                                 ( BlockDeviceBase , ) ,
416                                 headers.T_DEV , False )
417
418 class CharacterDeviceBase( DeviceBase ) :
419     def __init__( self , major , minor = None ) :
420         super( CharacterDeviceBase , self ).__init__()
421         self._dev = ( major , minor )
422         id = headers.rsbac_target_id_t()
423         if minor is not None :
424             id.dev.type = headers.D_char
425             id.dev.major = major
426             id.dev.minor = minor
427         else :
428             id.dev.type = headers.D_char_major
429             id.dev.major = major
430         self._id = byref( id )
431         self.acl = acl.AclById( self )
432     def __eq__( self , other ) :
433         return self is other or ( isinstance( other , CharacterDeviceBase )
434                                   and self._dev == other._dev )
435     def __repr__( self ) :
436         if self._dev[ 1 ] is None :
437             dev = self._dev[ 0 ]
438         else :
439             dev = '%d:%d' % ( self._dev )
440         return '<CharacterDevice %s>' % dev
441
442 CharacterDevice = buildObjectClass( 'CharacterDevice' ,
443                                     ( CharacterDeviceBase , ) ,
444                                     headers.T_DEV , False )
445
446 #--[ User ]-------------------------------------------------------------------
447
448 _g_user_mod = headers.rsbac_uid_t( -1 ).value + 1
449 assert _g_user_mod > 0
450 _g_user_max_value = headers.rsbac_uid_t( -32 ).value # FIXME: -32?
451 def _nuser( n ) :
452     n %= _g_user_mod
453     if n >= _g_user_max_value :
454         return n - _g_user_mod
455     else :
456         return n
457 _g_users = {}
458 _g_pseudoUsers = {
459     -3 : 'no_user' ,
460     -4 : 'all_users' ,
461     }
462
463 class UserBase( ObjectWithAttributes ) :
464     def __new__( cls , user ) :
465         user = _nuser( user )
466         if user < 0 :
467             instance = _g_users.get( user )
468             if instance is None :
469                 instance = ObjectWithAttributes.__new__( cls )
470                 instance.__init_singleton__( user )
471                 _g_users[ user ] = instance
472             return instance
473         else :
474             instance = ObjectWithAttributes.__new__( cls )
475             instance.__init_singleton__( user )
476             return instance
477     def __init_singleton__( self , user ) :
478         ObjectWithAttributes.__init__( self )
479         id = lib.rsbac_target_id_t()
480         if isinstance( user , ( int , long ) ) :
481             uid = user
482         elif isinstance( user , ( str , unicode ) ) :
483             uid = pwd.getpwnam( user )[ 2 ]
484         else :
485             raise RuntimeError , 'Unexpected user id %r' % ( user , )
486         id.user = uid
487         self.uid = uid
488         self._id = byref( id )
489         self.acl = acl.AclById( self )
490     def __int__( self ) :
491         return int( self.uid )
492     def __long__( self ) :
493         return long( self.uid )
494     def __eq__( self , other ) :
495         return self is other or ( isinstance( other , UserBase )
496                                   and self.uid == other.uid )
497     def __repr__( self ) :
498         if self.uid < 0 :
499             return '<PseudoUser %s>' % ( _g_pseudoUsers.get( self.uid , self.uid ) , )
500         else :
501             return '<User %d>' % self.uid
502     def removeFromAcl( self ) :
503         return acl.aclRemoveUser( self.uid )
504
505 User = buildObjectClass( 'User' , ( UserBase , ) , headers.T_USER , False )
506
507 #--[ Group ]------------------------------------------------------------------
508
509 _g_group_mod = headers.rsbac_gid_t( -1 ).value + 1
510 assert _g_group_mod > 0
511 _g_group_max_value = headers.rsbac_gid_t( -32 ).value # FIXME: -32?
512 def _ngroup( n ) :
513     n %= _g_group_mod
514     if n >= _g_group_max_value :
515         return n - _g_group_mod
516     else :
517         return n
518 _g_groups = {}
519 _g_pseudoGroups = {
520     -3 : 'no_group' ,
521     -4 : 'all_groups' ,
522     }
523
524 class GroupBase( ObjectWithAttributes ) :
525     def __new__( cls , group ) :
526         group = _ngroup( group )
527         if group < 0 :
528             instance = _g_groups.get( group )
529             if instance is None :
530                 instance = ObjectWithAttributes.__new__( cls )
531                 instance.__init_singleton__( group )
532                 _g_groups[ group ] = instance
533             return instance
534         else :
535             instance = ObjectWithAttributes.__new__( cls )
536             instance.__init_singleton__( group )
537             return instance
538     def __init_singleton__( self , group ) :
539         ObjectWithAttributes.__init__( group )
540         id = headers.rsbac_target_id_t()
541         if isinstance( group , ( int , long ) ) :
542             gid = group
543         elif isinstance( group , ( str , unicode ) ) :
544             gid = grp.getgrnam( group )[ 2 ]
545         else :
546             raise RuntimeError , 'Unexpected group id %r' % ( group , )
547         id.group = gid
548         self.gid = gid
549         self._id = byref( id )
550         self.acl = acl.AclById( self )
551     def __int__( self ) :
552         return int( self.gid )
553     def __long__( self ) :
554         return long( self.gid )
555     def __eq__( self , other ) :
556         return self is other or ( isinstance( other , GroupBase )
557                                   and self.gid == other.gid )
558     def __repr__( self ) :
559         if self.gid < 0 :
560             return '<PseudoGroup %s>' % ( _g_pseudoGroups.get( self.gid , self.gid ) , )
561         else :
562             return '<Group %d>' % self.gid
563
564 Group = buildObjectClass( 'Group' , ( GroupBase , ) , headers.T_GROUP , False )
565
566 #--[ Process ]----------------------------------------------------------------
567
568 class ProcessBase( ObjectWithAttributes ) :
569     def __init__( self , process ) :
570         super( ProcessBase , self ).__init__()
571         id = headers.rsbac_target_id_t()
572         id.process = process
573         self.pid = process
574         self._id = byref( id )
575         self.acl = acl.AclById( self )
576     def __int__( self ) :
577         return int( self.pid )
578     def __long__( self ) :
579         return long( self.pid )
580     def __eq__( self , other ) :
581         return self is other or ( isinstance( other , ProcessBase )
582                                   and self.pid == other.pid )
583     def __repr__( self ) :
584         if self.pid == 0 :
585             return '<DefaultProcess>'
586         else :
587             return '<Process %d %r>' % ( self.pid , processName( self.pid ) )
588
589 Process = buildObjectClass( 'Process' , ( ProcessBase , ) , headers.T_PROCESS , False )
590
591 #--[ IPC ]--------------------------------------------------------------------
592
593 class IpcBase( ObjectWithAttributes ) :
594     ipc = headers.I_none
595     def __init__( self , ipcId ) :
596         super( IpcBase , self ).__init__()
597         id = headers.rsbac_target_id_t()
598         id.ipc.type = self.ipc
599         id.ipc.id.id_nr = ipcId
600         self._id = byref( id )
601         self.id = ipcId
602         self.acl = acl.AclById( self )
603     def __int__( self ) :
604         return int( self.id )
605     def __long__( self ) :
606         return long( self.id )
607     def __repr__( self ) :
608         if self.ipc == headers.I_none and self.id == 0 :
609             return '<DefaultIpc>'
610         else :
611             return '<%s %d>' % ( self.__class__.__name__ , self.id )
612
613 Ipc = buildObjectClass( 'Ipc' , ( IpcBase , ) , headers.T_IPC , False )
614
615 class IpcSem( Ipc ) :
616     ipc = headers.I_sem
617
618 class IpcMsg( Ipc ) :
619     ipc = headers.I_msg
620
621 class IpcShm( Ipc ) :
622     ipc = headers.I_shm
623
624 class IpcAnonPipe( Ipc ) :
625     ipc = headers.I_anonpipe
626
627 class IpcMqueue( Ipc ) :
628     ipc = headers.I_mqueue
629
630 class IpcAnonUnix( Ipc ) :
631     ipc = headers.I_anonunix
632
633 #--[ SCD ]--------------------------------------------------------------------
634
635 g_scd = {}
636
637 class Scd( Object ) :
638     type = headers.T_SCD
639     def __new__( cls , target , *args , **kwargs ) :
640         instance = g_scd.get( target )
641         if instance is None :
642             instance = object.__new__( cls )
643             instance.__init_singleton__( target , *args , **kwargs )
644             g_scd[ target ] = instance
645         return instance
646     def __init_singleton__( self , target , name ) :
647         super( Scd , self ).__init__()
648         id = lib.rsbac_target_id_t()
649         id.scd = target
650         self._id = byref( id )
651         self.id = target
652         self.name = name
653         self.acl = acl.AclById( self )
654     def getRcType( self ) :
655         return Type( self.type , self.id )
656     rc_type = property( getRcType )
657     def __repr__( self ) :
658         if self.name is None :
659             return '<DefaultSCD>'
660         else :
661             return '<SCD %s>' % self.name
662
663 #--[ NetworkObject ]----------------------------------------------------------
664
665 _g_networkObject = None
666
667 class NetworkObject( Object ) :
668     type = headers.T_NETOBJ
669     def __new__( cls ) :
670         global _g_networkObject
671         if _g_networkObject is None :
672             _g_networkObject = Object.__new__( cls )
673             _g_networkObject.__init_singleton__()
674         return _g_networkObject
675     def __init_singleton__( self ) :
676         id = headers.rsbac_target_id_t()
677         id.netobj.sock_p = None
678         id.netobj.local_addr = None
679         id.netobj.local_len = 0
680         id.netobj.remote_addr = None
681         id.netobj.remote_len = 0
682         self._id = byref( id )
683         self.acl = acl.AclById( self )
684     def __repr__( self ) :
685         return '<NetworkObject>'
686
687 #--[ NetworkDevice ]----------------------------------------------------------
688
689 # Not exported. Included in NetworkDevice class.
690 def getAllNetworkDevice() :
691     """*Return a list of all network devices involved with RSBAC rules."""
692     arr = fetch( headers.rsbac_netdev_id_t ,
693                  lambda n , a : lib.rsbac_net_list_all_netdev( transaction._t , a , n ) )
694     return sorted( map( byteArrayToString , arr ) )
695
696 class NetworkDeviceBase( ObjectWithAttributes ) :
697     def __init__( self , name ) :
698         super( NetworkDeviceBase , self ).__init__()
699         id = headers.rsbac_target_id_t()
700         stringToByteArray( id.netdev , name , minPadding = 1 )
701         self._name = name
702         self._id = byref( id )
703         self.acl = acl.AclById( self )
704     def __eq__( self , other ) :
705         return self is other or ( isinstance( other , NetworkDeviceBase )
706                                   and self._name == other._name )
707     def __str__( self ) :
708         return self._name
709     def __repr__( self ) :
710         if self._name == '' :
711             return '<DefaultNetworkDevice>'
712         else :
713             return '<NetworkDevice %r>' % ( self._name , )
714     all = staticmethod( getAllNetworkDevice )
715
716 NetworkDevice = buildObjectClass( 'NetworkDeviceBase' ,
717                                   ( NetworkDeviceBase , ) ,
718                                   headers.T_NETDEV , False )
719
720 #--[ NetworkTemplate ]--------------------------------------------------------
721
722 def intToIpv4( n ) :
723     #assert 0 <= n < 2**32
724     n , a = divmod( n , 256 )
725     n , b = divmod( n , 256 )
726     n , c = divmod( n , 256 )
727     d = n
728     return '.'.join( map( str , ( a , b , c , d ) ) )
729
730 g_reDigitsOnly = re.compile( r'^\d+$' )
731
732 def ipv4ToInt( s ) :
733     ns = s.split( '.' )
734     if len( ns ) != 4 :
735         raise RuntimeError , 'invalid IP'
736     a = 0
737     for n in reversed( ns ) :
738         if not g_reDigitsOnly.match( n ) :
739             raise RuntimeError , 'invalid IP'
740         n = int( n )
741         if not 0 <= n <= 255 :
742             raise RuntimeError , 'invalid IP'
743         a = 256 * a + n
744     return a
745
746 def ipv4AndPrefixToInt( s ) :
747     if '/' not in s :
748         ip , prefix = s , 32
749     else :
750         ip , prefix = s.split( '/' , 1 )
751         if not g_reDigitsOnly.match( prefix ) :
752             raise RuntimeError, 'invalid prefix'
753         prefix = int( prefix )
754     ip = ipv4ToInt( ip )
755     if not 0 <= prefix <= 32 :
756         raise RuntimeError , 'invalid prefix'
757     return ip , prefix
758
759 # Not exported. Included in NetworkTemplate class.
760 def newNetworkTemplate( id , name ) :
761     data = headers.rsbac_net_temp_syscall_data_t()
762     data.name = name
763     raiseIfError( lib.rsbac_net_template( transaction._t ,
764                                           headers.NTS_new_template ,
765                                           id , byref( data ) ) )
766     nt = NetworkTemplate( id )
767     if nt.name != name :
768         raise RuntimeError , \
769             'error while constructing network template with name %r (got back %r instead)' \
770             % ( name , nt.name )
771     return nt
772
773 # Not exported. Included in NetworkTemplate class.
774 def copyNetworkTemplate( source , dest ) :
775     data = headers.rsbac_net_temp_syscall_data_t()
776     data.id = source
777     raiseIfError( lib.rsbac_net_template( transaction._t ,
778                                           headers.NTS_copy_template ,
779                                           dest , byref( data ) ) )
780     return NetworkTemplate( dest )
781
782 class NetworkTemplateBase( ObjectWithAttributes ) :
783     def __init__( self , nt ) :
784         super( NetworkTemplateBase , self ).__init__()
785         id = headers.rsbac_target_id_t()
786         id.nettemp = nt
787         self._id = byref( id )
788         self.nt = nt
789         self.acl = acl.AclById( self )
790     def __repr__( self ) :
791         try :
792             name = `self.getName()`
793         except Error :
794             name = 'undefined'
795         return '<%s [%d] %s>' % ( self.__class__.__name__ , self.nt , name )
796     def __syscall( self , syscall , data ) :
797         raiseIfError( lib.rsbac_net_template( transaction._t , syscall ,
798                                               self.nt , byref( data ) ) )
799         return data
800     def __syscallGet( self , syscall ) :
801         # FIXME: Use a shared 'data' to prevent building this
802         # structure too much times?
803         data = headers.rsbac_net_temp_syscall_data_t()
804         return self.__syscall( syscall , data )
805     #
806     # addresses
807     #
808     def getAddresses( self ) :
809         family = self.__syscallGet( headers.NTS_get_address_family ).address_family
810         addr = self.__syscallGet( headers.NTS_get_address ).address
811         def translate( inet ) :
812             result = []
813             for i in range( inet.nr_addr ) :
814                 result.append( '%s/%s' % ( intToIpv4( inet.addr[ i ] ) ,
815                                            inet.valid_bits[ i ] ) )
816             return result
817         if family == socket.AF_INET :
818             return ( family , translate( addr.inet ) )
819         elif family == socket.AF_UNIX :
820             return ( family , addr.other.addr[ : addr.other.valid_len ] )
821         else :
822             if addr.other.addr :
823                 name = str( family )
824                 #name = rsbac_get_net_family_name( family )
825                 raise RuntimeError , 'address for family %s not supported' % name
826             return ( family , )
827     def setAddresses( self , addresses ) :
828         if isinstance( addresses , ( int , long ) ) :
829             addresses = ( addresses , () )
830         if not isinstance( addresses , ( tuple , list ) ) \
831                 or len( addresses ) != 2 :
832             raise RuntimeError
833         family , addrs = addresses
834         if not isinstance( family , ( int , long ) ) :
835             raise RuntimeError
836         data = headers.rsbac_net_temp_syscall_data_t()
837         data.address_family = family
838         self.__syscall( headers.NTS_set_address_family , data )
839         if family == socket.AF_INET :
840             for i , addr in enumerate( addrs ) :
841                 a , n = ipv4AndPrefixToInt( addr )
842                 try :
843                     data.address.inet.addr[ i ] = a
844                     data.address.inet.valid_bits[ i ] = n
845                 except IndexError :
846                     raise IndexError , \
847                         'only %d addresses allowed, got %d' \
848                         % ( i , len( addrs ) )
849             data.address.inet.nr_addr = len( addrs )
850             self.__syscall( headers.NTS_set_address , data )
851         elif family == socket.AF_UNIX :
852             data.address.other.addr = addrs
853             data.address.other.valid_len = len( addrs )
854             self.__syscall( headers.NTS_set_address , data )
855         else :
856             if addrs :
857                 raise RuntimeError , \
858                     'address family %s doesn\'t allows addresses (or is not yet supported)' \
859                     % family
860     addresses = property( getAddresses , setAddresses )
861     #
862     # type
863     #
864     def getSocketType( self ) :
865         return self.__syscallGet( headers.NTS_get_type ).type
866     def setSocketType( self , type ) :
867         data = headers.rsbac_net_temp_syscall_data_t()
868         data.type = type
869         self.__syscall( headers.NTS_set_type , data )
870     socketType = property( getSocketType , setSocketType )
871     #
872     # protocol
873     #
874     def getProtocol( self ) :
875         return self.__syscallGet( headers.NTS_get_protocol ).protocol
876     def setProtocol( self , protocol ) :
877         data = headers.rsbac_net_temp_syscall_data_t()
878         data.protocol = protocol
879         self.__syscall( headers.NTS_set_protocol , data )
880     protocol = property( getProtocol , setProtocol )
881     #
882     # netdev
883     #
884     def getNetworkDevice( self ) :
885         return byteArrayToString( self.__syscallGet( headers.NTS_get_netdev ).netdev )
886     def setNetworkDevice( self , value ) :
887         data = headers.rsbac_net_temp_syscall_data_t()
888         stringToByteArray( data.netdev , str( value ) )
889         self.__syscall( headers.NTS_set_netdev , data )
890     def delNetworkDevice( self ) : # FIXME
891         self.setNetworkDevice( '' )
892     networkDevice = property( getNetworkDevice , setNetworkDevice , delNetworkDevice )
893     #
894     # ports
895     #
896     def getPorts( self ) :
897         ports = self.__syscallGet( headers.NTS_get_ports ).ports
898         p = ports.ports
899         def mkPortRange( p ) :
900             if p.min == p.max :
901                 return p.min
902             else :
903                 return ( p.min , p.max )
904         return map( mkPortRange , p[ : ports.nr_ports ] )
905     def setPorts( self , value ) :
906         data = headers.rsbac_net_temp_syscall_data_t()
907         p = data.ports.ports
908         try :
909             for i , range in enumerate( value ) :
910                 if not isinstance( range , ( tuple , list ) ) :
911                     min , max = range , range
912                 else :
913                     min , max = range
914                 p[ i ].min = min
915                 p[ i ].max = max
916         except IndexError :
917             raise IndexError , 'only %d port ranges allowed, got %d' % ( i , len( value ) )
918         data.ports.nr_ports = len( value )
919         self.__syscall( headers.NTS_set_ports , data )
920     def delPorts( self ) : # FIXME
921         self.setPorts( () )
922     ports = property( getPorts , setPorts , delPorts )
923     #
924     # name
925     #
926     def getName( self ) :
927         return self.__syscallGet( headers.NTS_get_name ).name
928     def setName( self , value ) :
929         data = headers.rsbac_net_temp_syscall_data_t()
930         slowButCorrectStringAssignation( data , 'name' , value )
931         try :
932             raiseIfError( lib.rsbac_net_template( transaction._t ,
933                                                   headers.NTS_set_name ,
934                                                   self.nt , byref( data ) ) )
935         except Error , e :
936             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
937                 raise
938             newNetworkTemplate( self.nt , value )
939     name = property( getName , setName )
940     #
941     # misc
942     #
943     create = staticmethod( newNetworkTemplate )
944     def checkId( self ) :
945         data = headers.rsbac_net_temp_syscall_data_t()
946         return self.__syscall( headers.NTS_check_id , data ).id
947     def copyTo( self , target ) :
948         return copyNetworkTemplate( self.nt , target )
949     def delete( self ) :
950         data = headers.rsbac_net_temp_syscall_data_t()
951         self.__syscall( headers.NTS_delete_template , data )
952
953 NetworkTemplate = buildObjectClass( 'NetworkTemplate' ,
954                                     ( NetworkTemplateBase , ) ,
955                                     headers.T_NETTEMP , False )
956
957 def getAllNetworkTemplate() :
958     arr = fetch( headers.rsbac_net_temp_id_t ,
959                  lambda n , a : lib.rsbac_net_list_all_template( transaction._t , a , n ) )
960     return sorted( map( int , arr ) )
961
962 class NetworkTemplateDict( object ) :
963     def __repr__( self ) :
964         return '{' + ', '.join( [ ': '.join( map( str , item ) ) for item in self.items() ] ) + '}'
965     def __getitem__( self , nt ) :
966         return NetworkTemplate( nt )
967     def __delitem__( self , nt ) :
968         NetworkTemplate( nt ).delete()
969     def keys( self ) :
970         return getAllNetworkTemplate()
971     def values( self ) :
972         return map( NetworkTemplate , self.keys() )
973     def items( self ) :
974         return [ ( i , NetworkTemplate( i ) ) for i in self.keys() ]
975
976 networkTemplates = NetworkTemplateDict()
977
978 #--[ UnixSocket ]-------------------------------------------------------------
979
980 class UnixSocket( Object ) :
981     type = headers.T_UNIXSOCK
982     def __init__( self , path ) :
983         self._id = path
984     def __repr__( self ) :
985         return '<UnixSocket %r>' % ( self._id , )
986
987 #-----------------------------------------------------------------------------
988
989 for target in ( FDBase , User , Group , Process ,
990                 Ipc , Scd , DeviceBase ,
991                 NetworkDevice , NetworkTemplate , NetworkObject ) :
992     target.rcTypes = RcTypeDict( target.type )
993
994 def listAllDevices() :
995     arr = fetch( headers.rsbac_dev_desc_t ,
996                  lambda n , a : lib.rsbac_list_all_dev( transaction._t , a , n ) )
997     r = []
998     def cmp( a , b ) :
999         return ( a.type < b.type
1000                  or ( a.type == b.type
1001                       and ( a.major < b.major
1002                             or ( a.major == b.major
1003                                  and a.minor < b.minor ) ) ) )
1004     for item in sorted( arr , cmp ) :
1005         if item.type == headers.D_block :
1006             dev = BlockDevice( item.major , item.minor )
1007         elif item.type == headers.D_block_major :
1008             dev = BlockDevice( item.major )
1009         elif item.type == headers.D_char :
1010             dev = CharacterDevice( item.major , item.minor )
1011         elif item.type == headers.D_char_major :
1012             dev = CharacterDevice( item.major )
1013         else :
1014             raise NotReached
1015         r.append( dev )
1016     return r
1017
1018 def listAllUsers() :
1019     arr = fetch( headers.rsbac_uid_t ,
1020                  lambda n , a : lib.rsbac_list_all_user( transaction._t , a , n ) )
1021     return map( User , sorted( arr ) )
1022
1023 def listAllGroups() :
1024     arr = fetch( headers.rsbac_gid_t ,
1025                  lambda n , a : lib.rsbac_list_all_group( transaction._t , a , n ) )
1026     return map( User , sorted( arr ) )
1027
1028 from rsbac import acl
1029
1030 defaultFd = FD( None )
1031 defaultFile = File( None )
1032 defaultFifo = Fifo( None )
1033 defaultSymlink = Symlink( None )
1034 defaultDirectory = Directory( None )
1035 defaultDevice = Device( None )
1036
1037 defaultProcess = Process( 0 )
1038
1039 defaultIpc = Ipc( 0 )
1040
1041 pseudoUsers = new.module( 'pseudoUsers' )
1042 for k , v in _g_pseudoUsers.items() :
1043     setattr( pseudoUsers , v , User( k ) )
1044
1045 defaultUser = pseudoUsers.no_user
1046
1047 pseudoGroups = new.module( 'pseudoGroups' )
1048 for k , v in _g_pseudoGroups.items() :
1049     setattr( pseudoGroups , v , Group( k ) )
1050
1051 defaultGroup = pseudoGroups.no_group
1052
1053 defaultNetworkDevice = NetworkDevice( '' )
1054
1055 defaultScd = Scd( 0 , None )
1056
1057 system = new.module( 'system' )
1058
1059 def createScdObject() :
1060     prefix = 'ST_'
1061     for k , v in headers.__dict__.items() :
1062         if k.startswith( prefix ) :
1063             k = k[ len( prefix ) : ]
1064             scd = Scd( v , k )
1065             setattr( system , k , scd )
1066
1067 # Create SystemClock, SystemSysctl, SystemQuota,..
1068 createScdObject()
1069
1070 defaultNetworkObject = NetworkObject()
1071
1072 # Local Variables:
1073 # indent-tabs-mode: nil
1074 # python-indent: 4
1075 # End: