d49a338dfdd515c676a0adf6aa149bfc77583932
[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 class NetworkObject( Object ) :
666     type = headers.T_NETOBJ
667     def __init__( self , *args , **kwargs ) : raise NotImplementedError
668     def __repr__( self ) :
669         return '<NetworkObject>'
670
671 #--[ NetworkDevice ]----------------------------------------------------------
672
673 # Not exported. Included in NetworkDevice class.
674 def getAllNetworkDevice() :
675     """*Return a list of all network devices involved with RSBAC rules."""
676     arr = fetch( headers.rsbac_netdev_id_t ,
677                  lambda n , a : lib.rsbac_net_list_all_netdev( transaction._t , a , n ) )
678     return sorted( map( byteArrayToString , arr ) )
679
680 class NetworkDeviceBase( ObjectWithAttributes ) :
681     def __init__( self , name ) :
682         super( NetworkDeviceBase , self ).__init__()
683         id = headers.rsbac_target_id_t()
684         stringToByteArray( id.netdev , name , minPadding = 1 )
685         self._name = name
686         self._id = byref( id )
687         self.acl = acl.AclById( self )
688     def __eq__( self , other ) :
689         return self is other or ( isinstance( other , NetworkDeviceBase )
690                                   and self._name == other._name )
691     def __str__( self ) :
692         return self._name
693     def __repr__( self ) :
694         return '<NetworkDevice %r>' % ( self._name , )
695     all = staticmethod( getAllNetworkDevice )
696
697 NetworkDevice = buildObjectClass( 'NetworkDeviceBase' ,
698                                   ( NetworkDeviceBase , ) ,
699                                   headers.T_NETDEV , False )
700
701 #--[ NetworkTemplate ]--------------------------------------------------------
702
703 def intToIpv4( n ) :
704     #assert 0 <= n < 2**32
705     n , a = divmod( n , 256 )
706     n , b = divmod( n , 256 )
707     n , c = divmod( n , 256 )
708     d = n
709     return '.'.join( map( str , ( a , b , c , d ) ) )
710
711 g_reDigitsOnly = re.compile( r'^\d+$' )
712
713 def ipv4ToInt( s ) :
714     ns = s.split( '.' )
715     if len( ns ) != 4 :
716         raise RuntimeError , 'invalid IP'
717     a = 0
718     for n in reversed( ns ) :
719         if not g_reDigitsOnly.match( n ) :
720             raise RuntimeError , 'invalid IP'
721         n = int( n )
722         if not 0 <= n <= 255 :
723             raise RuntimeError , 'invalid IP'
724         a = 256 * a + n
725     return a
726
727 def ipv4AndPrefixToInt( s ) :
728     if '/' not in s :
729         ip , prefix = s , 32
730     else :
731         ip , prefix = s.split( '/' , 1 )
732         if not g_reDigitsOnly.match( prefix ) :
733             raise RuntimeError, 'invalid prefix'
734         prefix = int( prefix )
735     ip = ipv4ToInt( ip )
736     if not 0 <= prefix <= 32 :
737         raise RuntimeError , 'invalid prefix'
738     return ip , prefix
739
740 # Not exported. Included in NetworkTemplate class.
741 def newNetworkTemplate( id , name ) :
742     data = headers.rsbac_net_temp_syscall_data_t()
743     data.name = name
744     raiseIfError( lib.rsbac_net_template( transaction._t ,
745                                           headers.NTS_new_template ,
746                                           id , byref( data ) ) )
747     nt = NetworkTemplate( id )
748     if nt.name != name :
749         raise RuntimeError , \
750             'error while constructing network template with name %r (got back %r instead)' \
751             % ( name , nt.name )
752     return nt
753
754 # Not exported. Included in NetworkTemplate class.
755 def copyNetworkTemplate( source , dest ) :
756     data = headers.rsbac_net_temp_syscall_data_t()
757     data.id = source
758     raiseIfError( lib.rsbac_net_template( transaction._t ,
759                                           headers.NTS_copy_template ,
760                                           dest , byref( data ) ) )
761     return NetworkTemplate( dest )
762
763 class NetworkTemplateBase( ObjectWithAttributes ) :
764     def __init__( self , nt ) :
765         super( NetworkTemplateBase , self ).__init__()
766         id = headers.rsbac_target_id_t()
767         id.nettemp = nt
768         self._id = byref( id )
769         self.nt = nt
770         self.acl = acl.AclById( self )
771     def __repr__( self ) :
772         try :
773             name = `self.getName()`
774         except Error :
775             name = 'undefined'
776         return '<%s [%d] %s>' % ( self.__class__.__name__ , self.nt , name )
777     def __syscall( self , syscall , data ) :
778         raiseIfError( lib.rsbac_net_template( transaction._t , syscall ,
779                                               self.nt , byref( data ) ) )
780         return data
781     def __syscallGet( self , syscall ) :
782         # FIXME: Use a shared 'data' to prevent building this
783         # structure too much times?
784         data = headers.rsbac_net_temp_syscall_data_t()
785         return self.__syscall( syscall , data )
786     #
787     # addresses
788     #
789     def getAddresses( self ) :
790         family = self.__syscallGet( headers.NTS_get_address_family ).address_family
791         addr = self.__syscallGet( headers.NTS_get_address ).address
792         def translate( inet ) :
793             result = []
794             for i in range( inet.nr_addr ) :
795                 result.append( '%s/%s' % ( intToIpv4( inet.addr[ i ] ) ,
796                                            inet.valid_bits[ i ] ) )
797             return result
798         if family == socket.AF_INET :
799             return ( family , translate( addr.inet ) )
800         elif family == socket.AF_UNIX :
801             return ( family , addr.other.addr[ : addr.other.valid_len ] )
802         else :
803             if addr.other.addr :
804                 name = str( family )
805                 #name = rsbac_get_net_family_name( family )
806                 raise RuntimeError , 'address for family %s not supported' % name
807             return ( family , )
808     def setAddresses( self , addresses ) :
809         if isinstance( addresses , ( int , long ) ) :
810             addresses = ( addresses , () )
811         if not isinstance( addresses , ( tuple , list ) ) \
812                 or len( addresses ) != 2 :
813             raise RuntimeError
814         family , addrs = addresses
815         if not isinstance( family , ( int , long ) ) :
816             raise RuntimeError
817         data = headers.rsbac_net_temp_syscall_data_t()
818         data.address_family = family
819         self.__syscall( headers.NTS_set_address_family , data )
820         if family == socket.AF_INET :
821             for i , addr in enumerate( addrs ) :
822                 a , n = ipv4AndPrefixToInt( addr )
823                 try :
824                     data.address.inet.addr[ i ] = a
825                     data.address.inet.valid_bits[ i ] = n
826                 except IndexError :
827                     raise IndexError , \
828                         'only %d addresses allowed, got %d' \
829                         % ( i , len( addrs ) )
830             data.address.inet.nr_addr = len( addrs )
831             self.__syscall( headers.NTS_set_address , data )
832         elif family == socket.AF_UNIX :
833             data.address.other.addr = addrs
834             data.address.other.valid_len = len( addrs )
835             self.__syscall( headers.NTS_set_address , data )
836         else :
837             if addrs :
838                 raise RuntimeError , \
839                     'address family %s doesn\'t allows addresses (or is not yet supported)' \
840                     % family
841     addresses = property( getAddresses , setAddresses )
842     #
843     # type
844     #
845     def getSocketType( self ) :
846         return self.__syscallGet( headers.NTS_get_type ).type
847     def setSocketType( self , type ) :
848         data = headers.rsbac_net_temp_syscall_data_t()
849         data.type = type
850         self.__syscall( headers.NTS_set_type , data )
851     socketType = property( getSocketType , setSocketType )
852     #
853     # protocol
854     #
855     def getProtocol( self ) :
856         return self.__syscallGet( headers.NTS_get_protocol ).protocol
857     def setProtocol( self , protocol ) :
858         data = headers.rsbac_net_temp_syscall_data_t()
859         data.protocol = protocol
860         self.__syscall( headers.NTS_set_protocol , data )
861     protocol = property( getProtocol , setProtocol )
862     #
863     # netdev
864     #
865     def getNetworkDevice( self ) :
866         return byteArrayToString( self.__syscallGet( headers.NTS_get_netdev ).netdev )
867     def setNetworkDevice( self , value ) :
868         data = headers.rsbac_net_temp_syscall_data_t()
869         stringToByteArray( data.netdev , str( value ) )
870         self.__syscall( headers.NTS_set_netdev , data )
871     def delNetworkDevice( self ) : # FIXME
872         self.setNetworkDevice( '' )
873     networkDevice = property( getNetworkDevice , setNetworkDevice , delNetworkDevice )
874     #
875     # ports
876     #
877     def getPorts( self ) :
878         ports = self.__syscallGet( headers.NTS_get_ports ).ports
879         p = ports.ports
880         def mkPortRange( p ) :
881             if p.min == p.max :
882                 return p.min
883             else :
884                 return ( p.min , p.max )
885         return map( mkPortRange , p[ : ports.nr_ports ] )
886     def setPorts( self , value ) :
887         data = headers.rsbac_net_temp_syscall_data_t()
888         p = data.ports.ports
889         try :
890             for i , range in enumerate( value ) :
891                 if not isinstance( range , ( tuple , list ) ) :
892                     min , max = range , range
893                 else :
894                     min , max = range
895                 p[ i ].min = min
896                 p[ i ].max = max
897         except IndexError :
898             raise IndexError , 'only %d port ranges allowed, got %d' % ( i , len( value ) )
899         data.ports.nr_ports = len( value )
900         self.__syscall( headers.NTS_set_ports , data )
901     def delPorts( self ) : # FIXME
902         self.setPorts( () )
903     ports = property( getPorts , setPorts , delPorts )
904     #
905     # name
906     #
907     def getName( self ) :
908         return self.__syscallGet( headers.NTS_get_name ).name
909     def setName( self , value ) :
910         data = headers.rsbac_net_temp_syscall_data_t()
911         slowButCorrectStringAssignation( data , 'name' , value )
912         try :
913             raiseIfError( lib.rsbac_net_template( transaction._t ,
914                                                   headers.NTS_set_name ,
915                                                   self.nt , byref( data ) ) )
916         except Error , e :
917             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
918                 raise
919             newNetworkTemplate( self.nt , value )
920     name = property( getName , setName )
921     #
922     # misc
923     #
924     create = staticmethod( newNetworkTemplate )
925     def checkId( self ) :
926         data = headers.rsbac_net_temp_syscall_data_t()
927         return self.__syscall( headers.NTS_check_id , data ).id
928     def copyTo( self , target ) :
929         return copyNetworkTemplate( self.nt , target )
930     def delete( self ) :
931         data = headers.rsbac_net_temp_syscall_data_t()
932         self.__syscall( headers.NTS_delete_template , data )
933
934 NetworkTemplate = buildObjectClass( 'NetworkTemplate' ,
935                                     ( NetworkTemplateBase , ) ,
936                                     headers.T_NETTEMP , False )
937
938 def getAllNetworkTemplate() :
939     arr = fetch( headers.rsbac_net_temp_id_t ,
940                  lambda n , a : lib.rsbac_net_list_all_template( transaction._t , a , n ) )
941     return sorted( map( int , arr ) )
942
943 class NetworkTemplateDict( object ) :
944     def __repr__( self ) :
945         return '{' + ', '.join( [ ': '.join( map( str , item ) ) for item in self.items() ] ) + '}'
946     def __getitem__( self , nt ) :
947         return NetworkTemplate( nt )
948     def __delitem__( self , nt ) :
949         NetworkTemplate( nt ).delete()
950     def keys( self ) :
951         return getAllNetworkTemplate()
952     def values( self ) :
953         return map( NetworkTemplate , self.keys() )
954     def items( self ) :
955         return [ ( i , NetworkTemplate( i ) ) for i in self.keys() ]
956
957 networkTemplates = NetworkTemplateDict()
958
959 #--[ UnixSocket ]-------------------------------------------------------------
960
961 class UnixSocket( Object ) :
962     type = headers.T_UNIXSOCK
963     def __init__( self , path ) :
964         self._id = path
965     def __repr__( self ) :
966         return '<UnixSocket %r>' % ( self._id , )
967
968 #-----------------------------------------------------------------------------
969
970 for target in ( FDBase , User , Group , Process ,
971                 Ipc , Scd , DeviceBase ,
972                 NetworkDevice , NetworkTemplate , NetworkObject ) :
973     target.rcTypes = RcTypeDict( target.type )
974
975 def listAllDevices() :
976     arr = fetch( headers.rsbac_dev_desc_t ,
977                  lambda n , a : lib.rsbac_list_all_dev( transaction._t , a , n ) )
978     r = []
979     def cmp( a , b ) :
980         return ( a.type < b.type
981                  or ( a.type == b.type
982                       and ( a.major < b.major
983                             or ( a.major == b.major
984                                  and a.minor < b.minor ) ) ) )
985     for item in sorted( arr , cmp ) :
986         if item.type == headers.D_block :
987             dev = BlockDevice( item.major , item.minor )
988         elif item.type == headers.D_block_major :
989             dev = BlockDevice( item.major )
990         elif item.type == headers.D_char :
991             dev = CharacterDevice( item.major , item.minor )
992         elif item.type == headers.D_char_major :
993             dev = CharacterDevice( item.major )
994         else :
995             raise NotReached
996         r.append( dev )
997     return r
998
999 def listAllUsers() :
1000     arr = fetch( headers.rsbac_uid_t ,
1001                  lambda n , a : lib.rsbac_list_all_user( transaction._t , a , n ) )
1002     return map( User , sorted( arr ) )
1003
1004 def listAllGroups() :
1005     arr = fetch( headers.rsbac_gid_t ,
1006                  lambda n , a : lib.rsbac_list_all_group( transaction._t , a , n ) )
1007     return map( User , sorted( arr ) )
1008
1009 from rsbac import acl
1010
1011 defaultFd = FD( None )
1012 defaultFile = File( None )
1013 defaultFifo = Fifo( None )
1014 defaultSymlink = Symlink( None )
1015 defaultDirectory = Directory( None )
1016 defaultDevice = Device( None )
1017
1018 defaultProcess = Process( 0 )
1019
1020 defaultIpc = Ipc( 0 )
1021
1022 pseudoUsers = new.module( 'pseudoUsers' )
1023 for k , v in _g_pseudoUsers.items() :
1024     setattr( pseudoUsers , v , User( k ) )
1025
1026 defaultUser = pseudoUsers.no_user
1027
1028 pseudoGroups = new.module( 'pseudoGroups' )
1029 for k , v in _g_pseudoGroups.items() :
1030     setattr( pseudoGroups , v , Group( k ) )
1031
1032 defaultGroup = pseudoGroups.no_group
1033
1034 defaultScd = Scd( 0 , None )
1035
1036 system = new.module( 'system' )
1037
1038 def createScdObject() :
1039     prefix = 'ST_'
1040     for k , v in headers.__dict__.items() :
1041         if k.startswith( prefix ) :
1042             k = k[ len( prefix ) : ]
1043             scd = Scd( v , k )
1044             setattr( system , k , scd )
1045
1046 # Create SystemClock, SystemSysctl, SystemQuota,..
1047 createScdObject()
1048
1049 # Local Variables:
1050 # indent-tabs-mode: nil
1051 # python-indent: 4
1052 # End: