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.errors import raiseIfError
26 #--[ ctypes ]-----------------------------------------------------------------
29 """Return a pointer to base type of ctypes array 'o'."""
31 return cast( byref( o ) , POINTER( t ) )
33 def slowButCorrectStringAssignation( object , field , data , nul = 1 ) :
34 """Carefully store a Python string into a ctypes field.
36 This function is obviously a temporary solution. We should find a
37 way to correctly put a string into a c_char array field in a
38 structure (or union) with always a NUL character at the end of the
39 string. Currently, ctypes doesn't report error if the string fill
40 the array completly and if there is no room to put the NUL
41 character. Also, a NUL character is silently interpreted as the
46 raise RuntimeError , 'a string intended for ctypes cannot contains the NUL character.'
47 size = getattr( object , '_sz_' + field , None )
49 cls = object.__class__
50 for name , desc in cls._fields_ :
53 setattr( cls , '_sz_' + field , size )
56 raise RuntimeError , 'unknown field %r in object of class %r' % ( field , cls )
57 if len( data ) > size - nul :
58 raise ValueError , '[XXX] string too long (%d, maximum length %d)' % ( len( data ) , size - nul )
59 setattr( object , field , data )
61 def stringToByteArray( array , string , fill = 0 , minPadding = 1 ) :
62 """Copy a string into a ctypes array of character.
64 Copy the string 'string' into ctypes array 'array'. An error is
65 thrown if string is too long. Array if filled with 'fill' value if
68 array -- ctypes array of character
69 string -- string to store in the array
70 fill -- fill value to use if string is smaller than the array size
71 minPadding -- mininum number of fill values to store at the end of
74 Returns the first parameter.
79 if b > a - minPadding :
80 raise RuntimeError , \
81 'string of length %d cannot fit in buffer on length %d (%d)' \
82 % ( b , a - minPadding , a )
86 array[ i ] = ord( string[ i ] )
93 def byteArrayToString( array ) :
94 """Read a string from a ctypes array of character.
96 array -- ctypes array of character
102 for end in range( 0 , len( array ) ) :
103 if not array[ end ] :
108 return ''.join( map( chr , array[ : end ] ) )
110 return ''.join( map( chr , array ) )
112 #--[ rsbac ]------------------------------------------------------------------
114 # The fetch function take care of extracting all the value from a
115 # RSBAC list. Several attempts are made if the list is updated while
118 # Say that L = [a,b,d]. We ask for the length and we get 3, but in the
119 # meantime, L becomes [a,b,c,d]. Then if we ask for 3 elements, we get
120 # [a,b,c].. missing one item!
122 # Internall, RSBAC tools prevent this by adding a constant amount of
123 # place but it's not perfect.
125 # Note that if the list is updated concurrently, then we can't be sure
126 # that it's up-to-date. Transaction may helps though.
128 # So, the only thing that is guaranteed, is that the list is complete
129 # according to the state at the time the request was made.
131 # FIXME: For multiple type, allows None to don't request a particular
134 def fetch( type , fun , start = None ) :
135 """Fetch RSBAC array.
137 Fetch one or several RSBAC arrays of types specified by 'type', by
138 calling the function 'fun'. This function should takes several
139 arguments: the first argument receive the number of items to
140 retrieve, and the remaining argument are ctypes pointer to already
141 allocated arrays. This function act as a callback called by fetch,
142 and may be called an unspecified number of times.
144 type -- either a single ctypes type, or a tuple of ctypes type
145 fun -- function taking at least 2 arguments
146 start -- None or an integer
148 Returns a single list if 'type' was a ctypes type, or a tuple of
149 list if 'type' was a tuple of ctypes type.
153 if not isinstance( type , ( tuple , list ) ) :
154 n = raiseIfError( fun( 0 , None ) )
156 n = raiseIfError( fun( 0 , *( [ None ] * len( type ) ) ) )
159 if not isinstance( type , ( tuple , list ) ) :
161 # The only way to ensure that we got all the items is to ask
162 # for more and check if the result contains less than asked.
163 # If not, we increase the buffer size and we try again.
166 m = raiseIfError( fun( n , aptr( arr ) ) )
168 # If no items are created while calling rsbac_rc_get_list,
169 # then we will exit this loop at the first iteration.
171 # Exponentially raise the size of the array.
177 # The only way to ensure that we got all the items is to ask
178 # for more and check if the result contains less than asked.
179 # If not, we increase the buffer size and we try again.
181 arrs = [ ( type * n )() for type in types ]
182 m = raiseIfError( fun( n , *map( aptr , arrs ) ) )
184 # If no items are created while calling rsbac_rc_get_list,
185 # then we will exit this loop at the first iteration.
187 # Exponentially raise the size of the array.
189 return tuple( arr[ : m ] for arr in arrs )
191 def ttlToInt( ttl ) :
207 #-----------------------------------------------------------------------------
211 """Convert an IP represented as an integer to a tuple of integer.
213 intToIp(3232235821) => (192, 168, 1, 45)
216 n = socket.htonl( n )
217 return ( int( ( n >> 24 ) & 0xff ) ,
218 int( ( n >> 16 ) & 0xff ) ,
219 int( ( n >> 8 ) & 0xff ) ,
224 """Convert an IP represented as a tuple of integer to an integer.
226 ipToInt((192, 168, 1, 45)) => 3232235821
229 ip = socket.ntohl( ip )
230 if isinstance( ip , tuple ) :
231 return reduce( lambda a , b : ( a << 8 ) | b , ip , 0 )
232 elif isinstance( ip , ( int , long ) ) :
233 return ip & 0xffffffff
237 def processName( pid ) :
238 """Get the name of a process.
240 Note: Extract the process name from /proc.
242 pid -- process ID (PID)
244 Returns the name of the process as string.
247 if isinstance( pid , int ) and pid > 0 :
249 f = file( '/proc/%d/stat' % pid )
252 return line[ line.find( '(' ) + 1 : line.rfind( ')' ) ]
256 def digits( n , base = 10 , size = None ) :
257 """Extract the digits from the integer 'n'.
259 Extract all digits (unless size is not None) in base 'base' from
260 integer 'n'. If 'size' is not None, then exactly 'size' digits are
261 extracted, adding heading 0s if necessary.
264 base -- integer (>= 2)
265 size -- None or an integer
267 Returns an array of integer.
269 digits(30, 4) => (1, 3, 2) because 30 is written 132 is base 4.
271 digits(30, 4, 6) => (0, 0, 0, 1, 3, 2)
273 digits(30, 4, 2) => (3, 2) Note that a digit is missing, since we asked
281 r.append( int( n % base ) )
286 for i in range( size ) :
287 r.append( int( n % base ) )
290 r += ( 0 , ) * ( size - i - 1 )
296 # indent-tabs-mode: nil