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