3 # py-rsbac - RSBAC Python bindings
4 # Copyright (C) 2006 Frederic Jolliton <pyrsbac@tuxee.net>
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.
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.
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
22 from ctypes import byref, cast, POINTER
24 from rsbac import headers
25 from rsbac.errors import raiseIfError
27 #--[ ctypes ]-----------------------------------------------------------------
30 """Return a pointer to base type of ctypes array 'o'."""
32 return cast( byref( o ) , POINTER( t ) )
34 def slowButCorrectStringAssignation( object , field , data , nul = 1 ) :
35 """Carefully store a Python string into a ctypes field.
37 This function is obviously a temporary solution. We should find a
38 way to correctly put a string into a c_char array field in a
39 structure (or union) with always a NUL character at the end of the
40 string. Currently, ctypes doesn't report error if the string fill
41 the array completly and if there is no room to put the NUL
42 character. Also, a NUL character is silently interpreted as the
45 This function take cares of these points.
49 raise RuntimeError , 'a string intended for ctypes cannot contains the NUL character.'
50 size = getattr( object , '_sz_' + field , None )
52 cls = object.__class__
53 for name , desc in cls._fields_ :
56 setattr( cls , '_sz_' + field , size )
59 raise RuntimeError , 'unknown field %r in object of class %r' % ( field , cls )
60 if len( data ) > size - nul :
61 raise ValueError , '[XXX] string too long (%d, maximum length %d)' % ( len( data ) , size - nul )
62 setattr( object , field , data )
64 def stringToByteArray( array , string , fill = 0 , minPadding = 1 ) :
65 """Copy a string into a ctypes array of character.
67 Copy the string 'string' into ctypes array 'array'. An error is
68 thrown if string is too long. Array if filled with 'fill' value if
71 array -- ctypes array of character
72 string -- string to store in the array
73 fill -- fill value to use if string is smaller than the array size
74 minPadding -- mininum number of fill values to store at the end of
77 Returns the first parameter.
82 if b > a - minPadding :
83 raise RuntimeError , \
84 'string of length %d cannot fit in buffer on length %d (%d)' \
85 % ( b , a - minPadding , a )
89 array[ i ] = ord( string[ i ] )
96 def byteArrayToString( array ) :
97 """Read a string from a ctypes array of character.
99 array -- ctypes array of character
105 for end in range( 0 , len( array ) ) :
106 if not array[ end ] :
111 return ''.join( map( chr , array[ : end ] ) )
113 return ''.join( map( chr , array ) )
115 #--[ rsbac ]------------------------------------------------------------------
117 # The fetch function take care of extracting all the value from a
118 # RSBAC list. Several attempts are made if the list is updated while
121 # Say that L = [a,b,d]. We ask for the length and we get 3, but in the
122 # meantime, L becomes [a,b,c,d]. Then if we ask for 3 elements, we get
123 # [a,b,c].. missing one item!
125 # Internall, RSBAC tools prevent this by adding a constant amount of
126 # place but it's not perfect.
128 # Note that if the list is updated concurrently, then we can't be sure
129 # that it's up-to-date. Transaction may helps though.
131 # So, the only thing that is guaranteed, is that the list is complete
132 # according to the state at the time the request was made.
134 # FIXME: For multiple type, allows None to don't request a particular
137 def fetch( type , fun , start = None ) :
138 """Fetch RSBAC array.
140 Fetch one or several RSBAC arrays of types specified by 'type', by
141 calling the function 'fun'. This function should takes several
142 arguments: the first argument receive the number of items to
143 retrieve and the remaining argument are ctypes pointer to already
144 allocated arrays. This function act as a callback called by fetch,
145 and may be called an unspecified number of times.
147 type -- either a single ctypes type, or a tuple of ctypes type
148 fun -- function taking at least 2 arguments
149 start -- None or an integer
151 Returns a single list if 'type' was a ctypes type, or a tuple of
152 list if 'type' was a tuple of ctypes type.
156 if not isinstance( type , ( tuple , list ) ) :
157 n = raiseIfError( fun( 0 , None ) )
159 n = raiseIfError( fun( 0 , *( [ None ] * len( type ) ) ) )
162 if not isinstance( type , ( tuple , list ) ) :
164 # The only way to ensure that we got all the items is to ask
165 # for more and check if the result contains less than asked.
166 # If not, we increase the buffer size and we try again.
169 m = raiseIfError( fun( n , aptr( arr ) ) )
171 # If no items are created while calling rsbac_rc_get_list,
172 # then we will exit this loop at the first iteration.
174 # Exponentially raise the size of the array.
180 # The only way to ensure that we got all the items is to ask
181 # for more and check if the result contains less than asked.
182 # If not, we increase the buffer size and we try again.
184 arrs = [ ( type * n )() for type in types ]
185 m = raiseIfError( fun( n , *map( aptr , arrs ) ) )
187 # If no items are created while calling rsbac_rc_get_list,
188 # then we will exit this loop at the first iteration.
190 # Exponentially raise the size of the array.
192 return tuple( arr[ : m ] for arr in arrs )
194 #--[ TTL ]--------------------------------------------------------------------
196 undefinedTtl = False # nothing
197 unlimitedTtl = True # map to 0
198 unchangedTtl = None # map to (rsbac_time_t)-1
200 _ttlMax = int( headers.rsbac_time_t( -1 ).value )
203 def ttlToInt( ttl ) :
208 else : # include False
210 raise RuntimeError , 'TTL must be below %d seconds' % _ttlMax
223 def ttlToTuple( ttl ) :
224 if ttl is False or ttl < 1 :
231 def tupleToTtl( t ) :
240 #-----------------------------------------------------------------------------
244 """Convert an IP represented as an integer to a tuple of integer.
246 intToIp(3232235821) => (192, 168, 1, 45)
249 n = socket.htonl( n )
250 return ( int( ( n >> 24 ) & 0xff ) ,
251 int( ( n >> 16 ) & 0xff ) ,
252 int( ( n >> 8 ) & 0xff ) ,
257 """Convert an IP represented as a tuple of integer to an integer.
259 ipToInt((192, 168, 1, 45)) => 3232235821
262 ip = socket.ntohl( ip )
263 if isinstance( ip , tuple ) :
264 return reduce( lambda a , b : ( a << 8 ) | b , ip , 0 )
265 elif isinstance( ip , ( int , long ) ) :
266 return ip & 0xffffffff
270 def processName( pid ) :
271 """Get the name of a process.
273 Note: Extract the process name from /proc.
275 pid -- process ID (PID)
277 Returns the name of the process as string.
280 if isinstance( pid , int ) and pid > 0 :
282 f = file( '/proc/%d/stat' % pid )
285 return line[ line.find( '(' ) + 1 : line.rfind( ')' ) ]
289 def digits( n , base = 10 , size = None ) :
290 """Extract the digits from the integer 'n'.
292 Extract all digits (unless size is not None) in base 'base' from
293 integer 'n'. If 'size' is not None, then exactly 'size' digits are
294 extracted, adding heading 0s if necessary.
297 base -- integer (>= 2)
298 size -- None or an integer
300 Returns an array of integer.
302 digits(30, 4) => (1, 3, 2) because 30 is written 132 is base 4.
304 digits(30, 4, 6) => (0, 0, 0, 1, 3, 2)
306 digits(30, 4, 2) => (3, 2) Note that a digit is missing, since we asked
314 r.append( int( n % base ) )
319 for i in range( size ) :
320 r.append( int( n % base ) )
323 r += ( 0 , ) * ( size - i - 1 )
329 # indent-tabs-mode: nil