def _receive( self, socket ): """Signal callback: Handles incoming data. Processes SSL events and parses the incoming data. If a vaild UMCP was found it is passed to _handle. :param fd socket: file descriptor or socket object that reported incoming data """ state = self.__states[ socket ] data = '' try: data = socket.recv( RECV_BUFFER_SIZE ) except SSL.WantReadError: # this error can be ignored (SSL need to do something) return True except ( SSL.SysCallError, SSL.Error ), error: statistics.connections.inactive() if self.__states[ socket ].username in statistics.users: statistics.users.remove( self.__states[ socket ].username ) CRYPT.warn( 'SSL error: %s. Probably the socket was closed by the client.' % str( error ) ) if self.__states[ socket ].processor is not None: self.__states[ socket ].processor.shutdown() notifier.socket_remove( socket ) del self.__states[ socket ] socket.close() return False
def _do_send( self, socket ): state = self.__states[ socket ] id, first = state.resend_queue.pop( 0 ) try: ret = socket.send( first ) if ret < len( first ): state.resend_queue.insert( 0, ( id, first[ ret : ] ) ) else: if id != -1: del state.requests[ id ] except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError): CRYPT.info( 'UMCP: SSL error during re-send' ) state.resend_queue.insert( 0, ( id, first ) ) return True except ( SSL.SysCallError, SSL.Error ), error: statistics.connections.inactive() if self.__states[ socket ].username in statistics.users: statistics.users.remove( self.__states[ socket ].username ) CRYPT.warn( 'SSL error: %s. Probably the socket was closed by the client.' % str( error ) ) if self.__states[ socket ].processor is not None: self.__states[ socket ].processor.shutdown() notifier.socket_remove( socket ) del self.__states[ socket ] socket.close() return False
def close( self ): """ Close the IO to the child. """ notifier.socket_remove( self.fp ) self.fp.close() self.signal_emit( 'closed', self.name )
def exit( self ): '''Closes all open connections.''' # remove all sockets for sock, state in self.__states.items(): CORE.info( 'Shutting down connection %s' % sock ) if state.processor is not None: state.processor.shutdown() notifier.socket_remove( sock ) statistics.connections.inactive() # delete states for state in self.__states.values(): del state self.__states = {}
def _cleanup(self, socket): state = self.__states.pop(socket, None) if state is None: return state.session.close_session() notifier.socket_remove(socket) try: socket.close() except Exception: pass state.session.signal_disconnect('success', self._response)
def exit(self): '''Shuts down all open connections.''' CORE.warn('Shutting down all open connections') if self.__ssl and not self.__unix: notifier.socket_remove(self.connection) self.connection.close() else: notifier.socket_remove(self.__realsocket) self.__realsocket.close() if self.__unix: os.unlink(self.__unix) if self.__magic: self.__bucket.exit()
def _cleanup(self, socket): if socket not in self.__states: return self.__states[socket].session.shutdown() notifier.socket_remove(socket) self.__states[socket].session.__del__() del self.__states[socket] try: socket.close() except: pass
def exit( self ): '''Shuts down all open connections.''' CORE.warn( 'Shutting down all open connections' ) if self.__ssl and not self.__unix: notifier.socket_remove( self.connection ) self.connection.close() else: notifier.socket_remove( self.__realsocket ) self.__realsocket.close() if self.__unix: os.unlink( self.__unix ) if self.__magic: self.__bucket.exit()
def _recv(self, sock): try: recv = '' while True: recv += sock.recv(RECV_BUFFER_SIZE) if self.__ssl and not self.__unix: if not sock.pending(): break else: break except socket.error as exc: CORE.warn('Client: _recv: error on socket: %s' % (exc, )) recv = None except SSL.SysCallError: # lost connection or any other unfixable error recv = None except SSL.Error: error = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) # lost connection: UMC daemon died probably if error == errno.EPIPE: recv = None else: return True if not recv: self.signal_emit('closed') try: sock.close() except: pass notifier.socket_remove(sock) return False if self.__buffer: recv = self.__buffer + recv self.__buffer = '' try: while recv: response = Response() recv = response.parse(recv) self._handle(response) except IncompleteMessageError: self.__buffer = recv # waiting for the rest except ParseError as exc: CORE.warn('Client: _recv: error parsing message: %s' % (exc, )) self.signal_emit('error', exc) return True
def _init_socket(self): if self.__unix: self.__realsocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) else: self.__realsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.__realsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) fcntl.fcntl(self.__realsocket.fileno(), fcntl.F_SETFD, 1) if self.__ssl and not self.__unix: self.__socket = SSL.Connection(self.__crypto_context, self.__realsocket) else: if self.__socket: notifier.socket_remove(self.__socket) self.__socket.close() self.__socket = None
def _response( self, msg, state ): ''' Send UMCP response to client. If the status code is 250 the module process is asking for exit. This method forfills the request.''' # FIXME: error handling is missing!! if not msg.id in state.requests and msg.id != -1: CORE.info( 'The given response is invalid or not known (%s)' % msg.id ) return try: statistics.requests.inactive() data = str( msg ) # there is not data from another request in the send queue if not state.resend_queue: ret = state.socket.send( data ) else: ret = 0 # not all data could be send; retry later if ret < len( data ): if not state.resend_queue: notifier.socket_add( state.socket, self._do_send, notifier.IO_WRITE ) state.resend_queue.append( ( msg.id, data[ ret : ] ) ) except ( SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError ): CRYPT.info( 'UMCP: SSL error need to re-send chunk' ) notifier.socket_add( state.socket, self._do_send, notifier.IO_WRITE ) state.resend_queue.append( data ) except ( SSL.SysCallError, SSL.Error, socket.error ), error: statistics.connections.inactive() # clean up if not already done if state.socket in self.__states: if state.username in statistics.users: statistics.users.remove( state.username ) CRYPT.warn( 'SSL error: %s. Probably the socket was closed by the client.' % str( error ) ) if state.processor is not None: state.processor.shutdown() notifier.socket_remove( state.socket ) del self.__states[ state.socket ] try: state.socket.close() except: pass return
def exit(self): '''Shuts down all open connections.''' CORE.warn('Shutting down all open connections') if self.__bucket: self.__bucket.exit() if self.__ssl and not self.__unix: notifier.socket_remove(self.connection) self.connection.close() elif self.__realsocket: notifier.socket_remove(self.__realsocket) self.__realsocket.close() self.__realsocket = None if self.__unix: if os.path.exists(self.__unix): os.unlink(self.__unix) self.__unix = None self.__bucket = None
def exit(self): '''Shuts down all open connections.''' CORE.warn('Shutting down all open connections') if self.__bucket: self.__bucket.exit() if self._child_number is not None: self._children.pop(self._child_number, None) if self.__ssl and self.__port: notifier.socket_remove(self.connection) self.connection.close() elif not self.__ssl and self.__port and self.__realtcpsocket: notifier.socket_remove(self.__realtcpsocket) self.__realtcpsocket.close() self.__realtcpsocket = None if self.__unix: if self.__realunixsocket is not None: notifier.socket_remove(self.__realunixsocket) self.__realunixsocket.close() self.__realunixsocket = None if self._child_number is None and os.path.exists(self.__unix): os.unlink(self.__unix) self.__unix = None self.__bucket = None
def _receive_data( self, sock ): debug( LOGDEBUG, 'GOT NEW DATA' ) if not self._connectionstates.has_key( sock ): debug( LOGERROR, 'unknown socket' ) return True state = self._connectionstates[ sock ] data = '' try: data = sock.recv( 16384 ) except SSL.WantReadError: # this error can be ignored (SSL need to do something) debug(LOGDEBUG, 'SSL.WantReadError') return True except ( SSL.SysCallError, SSL.Error ), error: debug( LOGINFO, 'SSL error: %s. Probably the socket was closed by the client.' % str( error ) ) notifier.socket_remove( sock ) del self._connectionstates[ sock ] sock.close() return False
def _receive_data(self, sock): debug(LOGDEBUG, "GOT NEW DATA") if not self._connectionstates.has_key(sock): debug(LOGERROR, "unknown socket") return True state = self._connectionstates[sock] data = "" try: data = sock.recv(16384) except SSL.WantReadError: # this error can be ignored (SSL need to do something) debug(LOGDEBUG, "SSL.WantReadError") return True except (SSL.SysCallError, SSL.Error), error: debug(LOGINFO, "SSL error: %s. Probably the socket was closed by the client." % str(error)) notifier.socket_remove(sock) del self._connectionstates[sock] sock.close() return False
def _stdin( fd ): print 'read: ' + os.read( fd, 512 ) notifier.socket_remove( 0 ) return False
recv = sock.recv(16384) except SSL.SysCallError, e: # lost connection or any other unfixable error recv = None except SSL.Error: error = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) if error == errno.EPIPE: # lost connection: server died probably debug(LOGDEBUG, 'EPIPE') recv = None else: return True if not recv: sock.close() notifier.socket_remove(sock) notifier.socket_remove(sock, condition=notifier.IO_WRITE) self._socket = None notifier.timer_add(1000, notifier.Callback(self.reconnect)) return False self._inbuffer += recv debug( LOGDEBUG, 'BUFFER: len=%d got %d bytes' % (len(self._inbuffer), len(recv))) # repeat while enough data is present while len(self._inbuffer) > 4: # get length of pickle object plen = struct.unpack('!I', self._inbuffer[0:4])[0]
def _stdin(fd): notifier.socket_remove(0) return False
class MagicBucket( object ): '''Manages a connection (session) to the UMC server. Therefore it ensures that without successful authentication no other command is accepted. After the user has authenticated the commands are passed on to the Processor.''' def __init__( self ): self.__states = {} def __del__( self ): self.exit() def new( self, client, socket ): """Is called by the Server object to annouce a new incoming connection. :param str client: IP address + port :param fd socket: a file descriptor or socket object """ CORE.info( 'Established connection: %s' % client ) state = State( client, socket ) state.signal_connect( 'authenticated', self._authenticated ) self.__states[ socket ] = state notifier.socket_add( socket , self._receive ) statistics.connections.new() def exit( self ): '''Closes all open connections.''' # remove all sockets for sock, state in self.__states.items(): CORE.info( 'Shutting down connection %s' % sock ) if state.processor is not None: state.processor.shutdown() notifier.socket_remove( sock ) statistics.connections.inactive() # delete states for state in self.__states.values(): del state self.__states = {} def _authenticated( self, success, state ): """Signal callback: Invoked when a authentication has been tried. This function generates the UMCP response. :param bool success: True if the authentication was successful :param State state: the state object for the connection (see also :class:`~univention.management.console.protocol.session.State`) """ if success: statistics.users.add( state.username ) state.authResponse.status = SUCCESS else: state.authResponse.status = BAD_REQUEST_AUTH_FAILED state.authenticated = success self._response( state.authResponse, state ) state.authResponse = None def _receive( self, socket ): """Signal callback: Handles incoming data. Processes SSL events and parses the incoming data. If a vaild UMCP was found it is passed to _handle. :param fd socket: file descriptor or socket object that reported incoming data """ state = self.__states[ socket ] data = '' try: data = socket.recv( RECV_BUFFER_SIZE ) except SSL.WantReadError: # this error can be ignored (SSL need to do something) return True except ( SSL.SysCallError, SSL.Error ), error: statistics.connections.inactive() if self.__states[ socket ].username in statistics.users: statistics.users.remove( self.__states[ socket ].username ) CRYPT.warn( 'SSL error: %s. Probably the socket was closed by the client.' % str( error ) ) if self.__states[ socket ].processor is not None: self.__states[ socket ].processor.shutdown() notifier.socket_remove( socket ) del self.__states[ socket ] socket.close() return False if not len( data ): notifier.socket_remove( socket ) del self.__states[ socket ] socket.close() return False state.buffer += data msg = None try: while state.buffer: msg = Message() state.buffer = msg.parse( state.buffer ) self._handle( state, msg ) except IncompleteMessageError, e: CORE.info( 'MagicBucket: incomplete message: %s' % str( e ) )
def _stdin( fd ): notifier.socket_remove( 0 ) return False
recv = sock.recv( 16384 ) except SSL.SysCallError, e: # lost connection or any other unfixable error recv = None except SSL.Error: error = sock.getsockopt( socket.SOL_SOCKET, socket.SO_ERROR ) if error == errno.EPIPE: # lost connection: server died probably debug( LOGDEBUG, 'EPIPE' ) recv = None else: return True if not recv: sock.close() notifier.socket_remove( sock ) notifier.socket_remove( sock, condition = notifier.IO_WRITE ) self._socket = None notifier.timer_add( 1000, notifier.Callback( self.reconnect ) ) return False self._inbuffer += recv debug( LOGDEBUG, 'BUFFER: len=%d got %d bytes' % (len(self._inbuffer), len(recv))) # repeat while enough data is present while len(self._inbuffer) > 4: # get length of pickle object plen = struct.unpack('!I', self._inbuffer[0:4])[0] if plen+4 <= len(self._inbuffer): # unpickle data
class LogCollectorServer( object ): def __init__( self, port = 7450 ): self._port = port self._connectionstates = {} self._ack_queue = [] self._targetdir = '/root/log/' if baseconfig.has_key('logcollector/targetdir'): self._targetdir = baseconfig[ 'logcollector/targetdir' ] else: debug( LOGERROR, 'WARNING: baseconfig variable "logcollector/targetdir" is not set' ) debug( LOGERROR, 'WARNING: using "logcollector/targetdir=%s" as default' % self._targetdir ) self._logrot_keepcnt = 99 if baseconfig.has_key('logcollector/logrotation/keepcount'): try: self._logrot_keepcnt = int(baseconfig[ 'logcollector/logrotation/keepcount' ]) except: debug( LOGERROR, 'WARNING: baseconfig variable "logcollector/logrotation/keepcount" contains invalid value' ) sys.exit(1) else: debug( LOGERROR, 'WARNING: baseconfig variable "logcollector/logrotation/keepcount" is not set' ) debug( LOGERROR, 'WARNING: using "logcollector/logrotation/keepcount=%s" as default' % self._logrot_keepcnt ) self._logrot_maxsize = '' if baseconfig.has_key('logcollector/logrotation/maxsize'): try: self._logrot_maxsize = baseconfig[ 'logcollector/logrotation/maxsize' ] except: pass if not self._logrot_maxsize: self._logrot_maxsize = '10M' debug( LOGERROR, 'WARNING: baseconfig variable "logcollector/logrotation/maxsize" is not set' ) debug( LOGERROR, 'WARNING: using "logcollector/logrotation/maxsize=%s" as default' % self._logrot_maxsize ) multi = '' if self._logrot_maxsize[-1].upper() in 'KMG': multi = self._logrot_maxsize[-1].upper() self._logrot_maxsize = self._logrot_maxsize[:-1] try: val = int(self._logrot_maxsize[:-1]) except: val = 10 multi = 'M' if multi == 'K': val *= 1024 elif multi == 'M': val *= 1024 * 1024 elif multi == 'G': val *= 1024 * 1024 * 1024 self._logrot_maxsize = val self._realsocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) self._realsocket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) self._realsocket.setblocking( 0 ) fcntl.fcntl(self._realsocket.fileno(), fcntl.F_SETFD, 1) self.crypto_context = SSL.Context( SSL.SSLv23_METHOD ) self.crypto_context.set_cipher_list('DEFAULT') self.crypto_context.set_options( SSL.OP_NO_SSLv2 ) self.crypto_context.set_verify( SSL.VERIFY_PEER, self._verify_cert_cb ) dir = '/etc/univention/ssl/%s' % baseconfig[ 'hostname' ] self.crypto_context.use_privatekey_file( os.path.join( dir, 'private.key' ) ) self.crypto_context.use_certificate_file( os.path.join( dir, 'cert.pem' ) ) self.crypto_context.load_verify_locations( os.path.join( dir, '/etc/univention/ssl/ucsCA', 'CAcert.pem' ) ) self.connection = SSL.Connection( self.crypto_context , self._realsocket ) self.connection.setblocking(0) self.connection.bind( ( '', self._port ) ) debug( LOGDEBUG, 'Server listening to SSL connects' ) self.connection.listen( 20 ) notifier.socket_add( self.connection, self._incoming_connection ) def _verify_cert_cb( self, conn, cert, errnum, depth, ok ): debug( LOGDEBUG, 'Got certificate: %s' % cert.get_subject() ) debug( LOGDEBUG, 'Got certificate issuer: %s' % cert.get_issuer() ) debug( LOGDEBUG, 'errnum=%d depth=%d ok=%d' % (errnum, depth, ok) ) return ok def _incoming_connection( self, socket ): socket, addr = socket.accept() socket.setblocking( 0 ) if addr: client = '%s:%d' % ( addr[ 0 ], addr[ 1 ] ) else: client = '' debug( LOGERROR, 'incoming connection: %s' % client ) # create new state state = { 'clientaddr': client, 'nextId': 1, 'inbuffer': '', 'outbuffer': '', 'targetdir': '', 'filelist': {} } self._connectionstates[ socket ] = state notifier.socket_add( socket , self._receive_data ) return True def _receive_data( self, sock ): debug( LOGDEBUG, 'GOT NEW DATA' ) if not self._connectionstates.has_key( sock ): debug( LOGERROR, 'unknown socket' ) return True state = self._connectionstates[ sock ] data = '' try: data = sock.recv( 16384 ) except SSL.WantReadError: # this error can be ignored (SSL need to do something) debug(LOGDEBUG, 'SSL.WantReadError') return True except ( SSL.SysCallError, SSL.Error ), error: debug( LOGINFO, 'SSL error: %s. Probably the socket was closed by the client.' % str( error ) ) notifier.socket_remove( sock ) del self._connectionstates[ sock ] sock.close() return False if not len( data ): notifier.socket_remove( sock ) del self._connectionstates[ sock ] sock.close() return False state[ 'inbuffer' ] += data debug( LOGDEBUG, 'BUFFER: len=%d got %d bytes' % (len(state['inbuffer']), len(data))) # repeat while enough data is present while len(state['inbuffer']) > 4: # get length of pickle object plen = struct.unpack('!I', state['inbuffer'][0:4])[0] if plen+4 <= len(state['inbuffer']): # unpickle data packet = cPickle.loads( state['inbuffer'][4:4+plen] ) # remove data from buffer state['inbuffer'] = state['inbuffer'][4+plen:] # handle packet if type(packet) == type({}): if packet.has_key('action'): if packet['action'] == 'SETUP': self._handle_packet_setup( sock, state, packet ) elif packet['action'] == 'DATA': self._handle_packet_data( sock, state, packet ) else: # not enough data break # send ACKs if self._ack_queue: packet = { 'id': 0, 'action': 'ACK', 'data': self._ack_queue } self._send_pickled( sock, packet ) self._ack_queue = [] return True
def _stdin(fd): print 'read: ' + os.read(fd, 512) notifier.socket_remove(0) return False
recv = None except SSL.Error: error = sock.getsockopt( socket.SOL_SOCKET, socket.SO_ERROR ) # lost connection: UMC daemon died probably if error == errno.EPIPE: recv = None else: return True if not recv: self.signal_emit( 'closed' ) try: sock.close() except: pass notifier.socket_remove( sock ) return False if self.__buffer: recv = self.__buffer + recv self.__buffer = '' try: while recv: response = Response() recv = response.parse( recv ) self._handle( response ) except IncompleteMessageError: self.__buffer = recv # waiting for the rest except ( ParseError, UnknownCommandError ), e: self.signal_emit( 'error', e )