def _send_all(self, data): while data: sent = self._stdin.channel.send(data) if not sent: # Connection was closed by server raise GvmError("Remote closed the connection") data = data[sent:]
def _feed_xml(self, data): try: self._parser.feed(data) except etree.ParseError as e: raise GvmError( "Cannot parse XML response. Response data " "read {0}".format(data), e, )
def connect(self): """Connect to the UNIX socket """ self._socket = socketlib.socket(socketlib.AF_UNIX, socketlib.SOCK_STREAM) self._socket.settimeout(self._timeout) try: self._socket.connect(self.path) except FileNotFoundError: raise GvmError('Socket {path} does not exist'.format( path=self.path)) from None
def read(self) -> str: """Read data from the remote server Returns: str: data as utf-8 encoded string """ response = "" self._start_xml() if self._timeout is not None: now = time.time() break_timeout = now + self._timeout while True: data = self._read() if not data: # Connection was closed by server raise GvmError("Remote closed the connection") clean_data = data.decode("utf-8", errors="ignore") clean_data = clean_data.replace('&#', '') self._parser.feed(clean_data.encode()) #self._feed_xml(data) response += data.decode("utf-8", errors="ignore") if self._is_end_xml(): break if self._timeout is not None: now = time.time() if now > break_timeout: raise GvmError("Timeout while reading the response") return response
def _check_command_status(root: etree.Element): status = root.get("status") if status is None: raise GvmServerError("No status in response.", root) if status[0] == "4": raise GvmResponseError(status=status, message=root.get("status_text")) elif status[0] == "5": raise GvmServerError(status=status, message=root.get("status_text")) elif status[0] != "2": raise GvmError( "Error in response. {0}".format(root.get("status_text")), root)
def determine_remote_gmp_version(self) -> str: """Determine the supported GMP version of the remote daemon""" self.connect() resp = self._send_xml_command(XmlCommand("get_version")) self.disconnect() version_el = resp.find('version') if version_el is None: raise GvmError( 'Invalid response from manager daemon while requesting the ' 'version information.') return version_el.text
def validate_xml_string(xml_string): """Checks if the passed string contains valid XML Raises a GvmError if the XML is invalid. Otherwise the function just returns. Raises: GvmError: The xml string did contain invalid XML """ try: secET.fromstring(xml_string) except (DefusedXmlException, etree.LxmlError) as e: raise GvmError('Invalid XML', e) from e
def send(self, data: Union[bytes, str]): """Send data to the connected remote server Arguments: data: Data to be send to the server. Either utf-8 encoded string or bytes. """ if self._socket is None: raise GvmError("Socket is not connected") if isinstance(data, str): self._socket.sendall(data.encode()) else: self._socket.sendall(data)
def _get_remote_host_key(self): """Get the remote host key for ssh connection""" try: tmp_socket = socketlib.socket() tmp_socket.connect((self.hostname, self.port)) except OSError as e: raise GvmError("Couldn't establish a connection to fetch the" f" remote server key: {e}") from None trans = paramiko.transport.Transport(tmp_socket) try: trans.start_client() except paramiko.SSHException as e: raise GvmError( f"Couldn't fetch the remote server key: {e}") from None key = trans.get_remote_server_key() try: trans.close() except paramiko.SSHException as e: raise GvmError( f"Couldn't close the connection to the remote server key: {e}" ) from None return key
def _read(self): """Read a command response from gvmd Returns: str: Response from server. """ response = self._connection.read() logger.debug('read() %i Bytes response: %s', len(response), response) if response is None or len(str(response)) == 0: raise GvmError('Connection was closed by remote server') return response
def _send_all(self, data) -> int: """Returns the sum of sent bytes if success""" sent_sum = 0 while data: sent = self._stdin.channel.send(data) if not sent: # Connection was closed by server raise GvmError("Remote closed the connection") sent_sum += sent data = data[sent:] return sent_sum
def read(self): """Read data from the remote server Returns: str: data as utf-8 encoded string """ response = '' self._start_xml() if self._timeout is not None: now = time.time() break_timeout = now + self._timeout while True: data = self._read() if not data: # Connection was closed by server raise GvmError('Remote closed the connection') self._feed_xml(data) response += data.decode('utf-8', errors='ignore') if self._is_end_xml(): break if self._timeout is not None: now = time.time() if now > break_timeout: raise GvmError('Timeout while reading the response') return response
def determine_supported_gmp(self) -> SUPPORTED_GMP_VERSIONS: """Determine supported GMP version of the remote daemon and return a corresponding Gmp class instance """ version = self.determine_remote_gmp_version() major_version = int(version.split('.')[0]) if major_version == 20: gmp_class = Gmpv208 elif major_version == 21: gmp_class = Gmpv214 else: raise GvmError( 'Remote manager daemon uses an unsupported version of GMP. ' 'The GMP version was {}.'.format(version)) return gmp_class(self._connection, transform=self._gmp_transform)
def validate_xml_string(xml_string: str): """Checks if the passed string contains valid XML Raises a GvmError if the XML is invalid. Otherwise the function just returns. Arguments: xml_string: XML string to validate Raises: GvmError: The xml string did contain invalid XML """ try: secET.fromstring(xml_string) except (DefusedXmlException, LxmlError) as e: raise GvmError("Invalid XML", e) from e
def determine_supported_gmp(self) -> SUPPORTED_GMP_VERSIONS: """Determine supported GMP version of the remote daemon and return a corresponding Gmp class instance """ version_str = self.determine_remote_gmp_version().split(".", 1) major_version = int(version_str[0]) minor_version = int(version_str[1]) if major_version == 20: gmp_class = Gmpv208 elif major_version == 21 and minor_version == 4: gmp_class = Gmpv214 elif major_version == 22 and minor_version == 4: gmp_class = Gmpv224 else: raise GvmError( "Remote manager daemon uses an unsupported version of GMP. " f"The GMP version was {major_version}.{minor_version}") return gmp_class(self._connection, transform=self._gmp_transform)
def determine_supported_gmp(self) -> SupportedGmpVersion: """ Determine supported GMP version of the remote deamon and return a corresponding Gmp class instance """ version = self.determine_remote_gmp_version() major_version = int(version[0]) if major_version == 7: gmp_class = Gmpv7 elif major_version == 8: gmp_class = Gmpv8 elif major_version >= 9: gmp_class = Gmpv9 else: raise GvmError( 'Remote manager daemon uses an unsupported version of GMP. ' 'The GMP version was {}.'.format(version) ) return gmp_class(self._connection, transform=self._gmp_transform)
def _ssh_authentication(self) -> None: """Search/add/save the servers key for the SSH authentication process""" # set to reject policy (avoid MITM attacks) self._socket.set_missing_host_key_policy(paramiko.RejectPolicy()) # openssh is posix, so this might only a posix approach # https://stackoverflow.com/q/32945533 try: # load the keys into paramiko and check if remote is in the list self._socket.load_host_keys(filename=self.known_hosts_file) except OSError as e: if e.errno != errno.ENOENT: raise GvmError("Something went wrong with reading " f"the known_hosts file: {e}") from None hostkeys = self._socket.get_host_keys() if not hostkeys.lookup(self.hostname): # Key not found, so connect to remote and fetch the key # with the paramiko Transport protocol key = self._get_remote_host_key() self._ssh_authentication_input_loop(hostkeys=hostkeys, key=key)
def connect(self): """ Connect to the SSH server and authenticate to it """ self._socket = paramiko.SSHClient() self._socket.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: self._socket.connect(hostname=self.hostname, username=self.username, password=self.password, timeout=self._timeout, port=int(self.port), allow_agent=False, look_for_keys=False) self._stdin, self._stdout, self._stderr = self._socket.exec_command( "", get_pty=False) except ( paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, ) as e: raise GvmError('SSH Connection failed', e)
def my_authenticate(username, password): raise GvmError('foo')