Ejemplo n.º 1
0
 def _connect(self):
     host_id = self._host_cfg['host_id']
     host, port = self._host_cfg[host_id, 'host']
     user = self._host_cfg[host_id, 'user']
     passwd = self._host_cfg[host_id, 'password']
     timeout = self._host_cfg[host_id, 'timeout'] or None
     known_hosts = self._host_cfg[host_id, 'known_hosts']
     key_type = self._host_cfg[host_id, 'key_type']
     key_file = self._host_cfg[host_id, 'key_file']
     key_pass = self._host_cfg[host_id, 'key_pass']
     try:
         if key_type:
             key = _KEY_TYPES[key_type](filename=key_file,
                                        password=key_pass)
             _logger.debug('private key: %s', key.get_name())
         else:
             key = None
         hostname = utils.format_knownhost(host, port)
         hostkeys = HostKeys(known_hosts)
         transport = Transport((host, port))
         transport.start_client(timeout=timeout)
         hostkey = transport.get_remote_server_key()
         if not hostkeys.check(hostname, hostkey):
             raise SSHException('Incorrect hostkey')
         if key:
             transport.auth_publickey(user, key)
         else:
             transport.auth_password(user, passwd)
         client = transport.open_sftp_client()
         client.get_channel().settimeout(timeout)
         _logger.debug('client for %s created', hostname)
         return client
     except (OSError, SSHException) as ex:
         raise ConnectError(f'Connection to server "{host}:{port}"'
                            f' failed: {ex.args!s}')
Ejemplo n.º 2
0
 def add_from_paramiko_host_keys(self, host_keys: paramiko.HostKeys):
     for host_entry in host_keys.keys():
         for key_type, key in host_keys.lookup(host_entry).items():
             self.add(
                 HostKeyEntry.from_paramiko_entry(host_entry=host_entry,
                                                  key_type=key_type,
                                                  key=key))
Ejemplo n.º 3
0
def _add_keys_to_known_hosts(server_keys, host_keys_file):
    try:
        if not os.path.isfile(host_keys_file):
            host_keys = HostKeys()
        else:
            host_keys = HostKeys(filename=host_keys_file)

        for hostname, key_list in server_keys.items():
            try:
                for key_tuple in key_list:
                    key = RSAKey(data=base64.b64decode(key_tuple[0]))
                    host_keys.add(hostname=hostname,
                                  key=key,
                                  keytype=key_tuple[1])
                    host_keys.add(hostname=hostname + ".*",
                                  key=key,
                                  keytype=key_tuple[1])
                    logging.info(
                        "Adding keys to known hosts file '{0}' for host '{1}'".
                        format(host_keys_file, hostname))
                    host_keys.save(filename=host_keys_file)
            except Exception as e:
                logging.error(
                    "Failed adding keys to known hosts file for host '{0}', with exception: {1}"
                    .format(hostname, e))
    except Exception as e:
        logging.error(
            "Failed adding keys to known hosts file '{0}', with exception: {1}"
            .format(host_keys_file, e))
Ejemplo n.º 4
0
 def get_client(self):
     client = paramiko.SSHClient()
     host_keys = HostKeys()
     host_keys.add(hostname=self.host.address,
                   keytype=self.config['host_key_type'],
                   key=self.get_host_key())
     client._host_keys = host_keys  # If you not a better way than accessing a private member I am all ears
     return client
Ejemplo n.º 5
0
 def _ssh_authentication_input_loop(self, hostkeys: paramiko.HostKeys,
                                    key: paramiko.PKey) -> None:
     # Ask user for permission to continue
     # let it look like openssh
     sha64_fingerprint = base64.b64encode(
         hashlib.sha256(base64.b64decode(
             key.get_base64())).digest()).decode("utf-8")[:-1]
     key_type = key.get_name().replace("ssh-", "").upper()
     print(f"The authenticity of host '{self.hostname}' can't "
           "be established.")
     print(f"{key_type} key fingerprint is {sha64_fingerprint}.")
     print("Are you sure you want to continue connecting (yes/no)? ",
           end="")
     add = input()
     while True:
         if add == "yes":
             hostkeys.add(self.hostname, key.get_name(), key)
             # ask user if the key should be added permanently
             print(
                 f"Do you want to add {self.hostname} "
                 "to known_hosts (yes/no)? ",
                 end="",
             )
             save = input()
             while True:
                 if save == "yes":
                     try:
                         hostkeys.save(filename=self.known_hosts_file)
                     except OSError as e:
                         raise GvmError(
                             "Something went wrong with writing "
                             f"the known_hosts file: {e}") from None
                     logger.info(
                         "Warning: Permanently added '%s' (%s) to "
                         "the list of known hosts.",
                         self.hostname,
                         key_type,
                     )
                     break
                 elif save == "no":
                     logger.info(
                         "Warning: Host '%s' (%s) not added to "
                         "the list of known hosts.",
                         self.hostname,
                         key_type,
                     )
                     break
                 else:
                     print("Please type 'yes' or 'no': ", end="")
                     save = input()
             break
         elif add == "no":
             return sys.exit(
                 "User denied key. Host key verification failed.")
         else:
             print("Please type 'yes' or 'no': ", end="")
             add = input()
Ejemplo n.º 6
0
def readHostKey(host):
    """Read a host key from the known hosts file"""
    from paramiko import HostKeys
    global hostKeys
    if(hostKeys is None):
        hostKeys = HostKeys(config.KNOWN_HOSTS_FILE)

    try:
        k = hostKeys.lookup(host)['ssh-rsa']
        return(k.get_base64())
    except TypeError:
        return None
Ejemplo n.º 7
0
def readHostKey(host):
    """Read a host key from the known hosts file"""
    from paramiko import HostKeys
    global hostKeys
    if (hostKeys is None):
        hostKeys = HostKeys(config.KNOWN_HOSTS_FILE)

    try:
        k = hostKeys.lookup(host)['ssh-rsa']
        return (k.get_base64())
    except TypeError:
        return None
Ejemplo n.º 8
0
def get_host_keys(filename):
    with HOST_KEYS_LOCK:
        host_keys = HostKeys()

        try:
            host_keys.load(filename)
        # When paramiko encounters a bad host keys line it sometimes bails the
        # entire load incorrectly.
        # See: https://github.com/paramiko/paramiko/pull/1990
        except Exception as e:
            logger.warning("Failed to load host keys from {0}: {1}".format(filename, e))

        return host_keys
Ejemplo n.º 9
0
	def verify(self, path):
		if self.knownfile == '':
			error('No known_hosts file to check against.')

		args = {'path': path}
		try:
			f = open(path + '.ssh-signed', 'r')
			for line in f:
				[k, v] = line.replace('\n', '').split();
				args[k] = v
		except:
			error('Not able to open signature file for verifying.')
		f.close()
		if not 'signature' in args:
			error('Missing signature-tag in signature file.')
		if not 'host' in args:
			error('Missing host-tag in signature file.')
		if not 'keytype' in args:
			error('Missing keytype-tag in signature file.')

		if self.host != '' and self.host != args['host']:
			error('Given host does not match host from signature blob.')

		self.host = args['host']
		self.hhost = HostKeys.hash_host(self.host)
		self.keytype = args['keytype']
		self.__load_hk()
		print "Found Host: '" + self.host + "' and Keytype: '" + self.keytype + "'."
		return self.__verify(args)
Ejemplo n.º 10
0
 def init_host_key(self):
     if self._host_key and isinstance(self._host_key,
                                      KEYTYPES.get(self.host_key_type, ())):
         return
     if self.host_keys_file:
         try:
             known_hosts = HostKeys(self.host_keys_file)
         except FileNotFoundError:
             raise SFTPURLError(
                 f'The given host key file {self.host_keys_file} could not be found'
             )
         hostkeys = known_hosts.lookup(self.hostname)
         if not hostkeys:
             raise SFTPURLError('There are no host keys associated with'
                                f' {self.hostname}')
         if self.host_key_type:
             try:
                 keys = KNOWN_HOSTS_KEY_TYPE_MAP[self.host_key_type.upper()]
                 for k in keys:
                     pkey = hostkeys.get(k)
                     if pkey:
                         break
                 else:  # no break
                     raise SFTPURLError(
                         f'There are no host keys with the given type {self.host_key_type}'
                     )
             except KeyError:
                 raise SFTPURLError(
                     ('Unrecognized key type {}.'
                      ' Recognized key types: {}').format(
                          self.host_key_type,
                          ', '.join(KNOWN_HOSTS_KEY_TYPE_MAP)))
         else:
             for pkey in hostkeys.values():
                 break
         self._host_key = pkey
Ejemplo n.º 11
0
def _del_hostkey(args):
    host = args['HOST']
    file = args['FILE']
    try:
        port = strings.str2port(args['--port'])
        hostname = utils.format_knownhost(host, port)
        hostkeys = HostKeys()
        hostkeys.load(file)
        if hostkeys.lookup(hostname):
            del hostkeys[hostname]
            hostkeys.save(file)
            print(f'Key for "{hostname}" deleted in file "{file}"')
        else:
            print(f'Key for "{hostname}" not found in file "{file}"')
    except (FileNotFoundError, ConfigError) as ex:
        print(ex, file=sys.stderr)
        return ConfigError.code
    except Exception as ex:
        print(repr(ex), file=sys.stderr)
        return ExitCodes.FAILURE.code
    return ExitCodes.SUCCESS.code
Ejemplo n.º 12
0
def _validate_key(host: str, server_key: PKey):
    known_hosts_file = '~/.ssh/known_hosts'
    host_keys = HostKeys()
    host_keys.load(os.path.expanduser(known_hosts_file))
    known_server_keys = host_keys.get(host)
    add_host_key_instructions = 'You can add the host key with `\n' \
        f'ssh-keyscan -H {host} >> {known_hosts_file}\n`'
    if known_server_keys is None:
        raise SSHAuthenticationError(
            f'plz host is not known. {add_host_key_instructions}')
    known_server_keys = host_keys.get(host)
    if known_server_keys.get(server_key.get_name()) is None:
        raise SSHAuthenticationError(
            f'No key found for host {host} with name '
            f'{server_key.get_name()}. {add_host_key_instructions}')
    if server_key != known_server_keys.get(server_key.get_name()):
        raise SSHAuthenticationError(
            f'Bad host key for `{host}`. Fix your `{known_hosts_file}` file')
Ejemplo n.º 13
0
 def connectionError(self, e):
     self.viewer.setWindowTitle("rMview - Could not connect!")
     log.error(e)
     mbox = QMessageBox(QMessageBox.NoIcon,
                        'Connection error',
                        "Connection attempt failed",
                        parent=self.viewer)
     icon = QPixmap(":/assets/dead.svg")
     icon.setDevicePixelRatio(self.devicePixelRatio())
     mbox.setIconPixmap(icon)
     mbox.addButton("Settings...", QMessageBox.ResetRole)
     mbox.addButton(QMessageBox.Cancel)
     if isinstance(e, BadHostKeyException):
         mbox.setDetailedText(str(e))
         mbox.setInformativeText(
             "<big>The host at %s has the wrong key.<br>"
             "This usually happens just after a software update on the tablet.</big><br><br>"
             "You have three options to fix this permanently:"
             "<ol><li>"
             "Press Update to replace the old key with the new."
             "<br></li><li>"
             "Change your <code>~/.ssh/known_hosts</code> file to match the new fingerprint.<br>"
             "The easiest way to do this is connecting manually via ssh and follow the instructions."
             "<br></li><li>"
             "Set <code>\"host_key_policy\": \"ignore_new\"</code> in the <code>ssh</code> section of rmView\'s settings.<br>"
             "This is not recommended unless you are in a trusted network."
             "<br></li><ol>" % (e.hostname))
         mbox.addButton("Ignore", QMessageBox.NoRole)
         mbox.addButton("Update", QMessageBox.YesRole)
     elif isinstance(e, UnknownHostKeyException):
         mbox.setDetailedText(str(e))
         mbox.setInformativeText(
             "<big>The host at %s is unknown.<br>"
             "This usually happens if this is the first time you use ssh with your tablet.</big><br><br>"
             "You have three options to fix this permanently:"
             "<ol><li>"
             "Press Add to add the key to the known hosts."
             "<br></li><li>"
             "Change your <code>~/.ssh/known_hosts</code> file to match the new fingerprint.<br>"
             "The easiest way to do this is connecting manually via ssh and follow the instructions."
             "<br></li><li>"
             "Set <code>\"host_key_policy\": \"ignore_new\"</code> in the <code>ssh</code> section of rmView\'s settings.<br>"
             "This is not recommended unless you are in a trusted network."
             "<br></li><ol>" % (e.hostname))
         mbox.addButton("Ignore", QMessageBox.NoRole)
         mbox.addButton("Add", QMessageBox.YesRole)
     else:
         mbox.setInformativeText(
             "I could not connect to the reMarkable at %s:\n%s." %
             (self.config.get('ssh').get('address'), e))
         mbox.addButton(QMessageBox.Retry)
         mbox.setDefaultButton(QMessageBox.Retry)
     answer = mbox.exec()
     if answer == QMessageBox.Retry:
         self.requestConnect()
     elif answer == QMessageBox.Cancel:
         self.quit()
     elif answer == 1:  # Ignore
         self.requestConnect(host_key_policy="ignore_all")
     elif answer == 2:  # Add/Update
         if not os.path.isfile(self.LOCAL_KNOWN_HOSTS):
             open(self.LOCAL_KNOWN_HOSTS, 'a').close()
         hk = HostKeys(self.LOCAL_KNOWN_HOSTS)
         hk.add(e.hostname, e.key.get_name(), e.key)
         hk.save(self.LOCAL_KNOWN_HOSTS)
         log.info("Saved host key in %s", self.LOCAL_KNOWN_HOSTS)
         self.requestConnect()
     else:
         self.openSettings(prompt=False)
         self.quit()
Ejemplo n.º 14
0
 def add_to_paramiko_host_keys(self, host_keys: paramiko.HostKeys):
     for key_type, host_key in self.host_keys.items():
         host_keys.add(hostname=host_key.paramiko_host_entry,
                       keytype=host_key.paramiko_key_type,
                       key=host_key.paramiko_key)
Ejemplo n.º 15
0
def ssh_connect(openstack_properties):
    """Create a connection to a server via SSH.

    Args:
        openstack_properties (dict): OpenStack facts and variables from Ansible
            which can be used to manipulate OpenStack objects.

    Returns:
        def: A factory function object.
    """

    connections = []  # Track inventory of SSH connections for teardown.

    def _factory(hostname,
                 username,
                 retries=10,
                 key_filename=None,
                 auth_timeout=180):
        """Connect to a server via SSH.

        Note: this function uses an exponential back-off for retries which means
        the more retries specified the longer the wait between each retry. The
        total wait time is on the fibonacci sequence. (https://bit.ly/1ee23o9)

        Args:
            hostname (str): The server to connect to.
            username (str): The username to authenticate as.
                (defaults to the current local username)
            retries (int): The maximum number of validation retry attempts.
            key_filename (str): The filename, or list of filenames, of optional
                private key(s) and/or certs to try for authentication. (Default
                is to use the 'rpc_support' key.
            auth_timeout (float): An optional timeout (in seconds) to wait for
                an authentication response.

        Returns:
            paramiko.client.SSHClient: A client already connected to the target
                server.

        Raises:
            paramiko.BadHostKeyException: If the server’s host key could not be
                verified.
            paramiko.AuthenticationException: If authentication failed.
            paramiko.SSHException: If there was any other error connecting or
                establishing an SSH session.
            paramiko.ssh_exception.NoValidConnectionsError: Connection refused
                by host. (SSH service is probably not running or host is not
                fully booted)
            socket.error: If a socket error occurred while connecting.
        """

        temp_connection = SSHClient()
        temp_connection.set_missing_host_key_policy(AutoAddPolicy())

        for attempt in range(1, retries + 1):
            try:
                temp_connection.connect(
                    hostname=hostname,
                    username=username,
                    key_filename=(
                        key_filename or openstack_properties['private_key_path']
                    ),
                    auth_timeout=auth_timeout
                )
            except NoValidConnectionsError:
                if attempt != retries + 1:
                    sleep(attempt)
                else:
                    raise   # Re-raise

        connections.append(temp_connection)

        return temp_connection

    yield _factory

    # Teardown
    for connection in connections:
        connection.close()

    HostKeys().clear()  # Clear the 'known_hosts' file.
Ejemplo n.º 16
0
Archivo: app.py Proyecto: benneti/remy
 def retryInit(self, e):
   log.error('RETRY? [%s]', e)
   mbox = QMessageBox(QMessageBox.NoIcon, 'Connection error', "Connection attempt failed")
   mbox.addButton("Settings…", QMessageBox.ResetRole)
   mbox.addButton(QMessageBox.Cancel)
   if isinstance(e, BadHostKeyException):
     mbox.setIconPixmap(_mkIcon(":/assets/128/security-low.svg"))
     mbox.setDetailedText(str(e))
     mbox.setInformativeText(
       "<big>The host at %s has the wrong key.<br>"
       "This usually happens just after a software update on the tablet.</big><br><br>"
       "You have three options to fix this permanently:"
       "<ol><li>"
       "Press Update to replace the old key with the new."
       "<br></li><li>"
       "Change your <code>~/.ssh/known_hosts</code> file to match the new fingerprint.<br>"
       "The easiest way to do this is connecting manually via ssh and follow the instructions."
       "<br></li><li>"
       "Set <code>\"host_key_policy\": \"ignore_new\"</code> in the appropriate source of Remy\'s settings.<br>"
       "This is not recommended unless you are in a trusted network."
       "<br></li><ol>" % (e.hostname)
     )
     mbox.addButton("Ignore", QMessageBox.NoRole)
     mbox.addButton("Update", QMessageBox.YesRole)
   elif isinstance(e, UnknownHostKeyException):
     mbox.setIconPixmap(_mkIcon(":/assets/128/security-high.svg"))
     mbox.setDetailedText(str(e))
     mbox.setInformativeText(
       "<big>The host at %s is unknown.<br>"
       "This usually happens if this is the first time you use ssh with your tablet.</big><br><br>"
       "You have three options to fix this permanently:"
       "<ol><li>"
       "Press Add to add the key to the known hosts."
       "<br></li><li>"
       "Change your <code>~/.ssh/known_hosts</code> file to match the new fingerprint.<br>"
       "The easiest way to do this is connecting manually via ssh and follow the instructions."
       "<br></li><li>"
       "Set <code>\"host_key_policy\": \"ignore_new\"</code> in the appropriate source of Remy\'s settings.<br>"
       "This is not recommended unless you are in a trusted network."
       "<br></li><ol>" % (e.hostname)
     )
     mbox.addButton("Ignore", QMessageBox.NoRole)
     mbox.addButton("Add", QMessageBox.YesRole)
   else:
     mbox.setIconPixmap(_mkIcon(":/assets/dead.svg"))
     mbox.setInformativeText("I could not connect to the reMarkable at %s:\n%s." % (self.config.get('host', '[no source selected]'), e))
     d=mbox.addButton(QMessageBox.Discard)
     d.setText("Source…")
     mbox.addButton(QMessageBox.Retry)
     mbox.setDefaultButton(QMessageBox.Retry)
   answer = mbox.exec()
   log.info(answer)
   if answer == QMessageBox.Retry:
     self.requestInit()
   elif answer == QMessageBox.Cancel:
     self.quit()
   elif answer == QMessageBox.Discard: # Sources selection
     source, ok = self.sourceSelectionBox()
     if not ok:
       self.quit()
     else:
       self.config.selectSource(source)
       self.requestInit()
   elif answer == 1: # Ignore
     self.requestInit(host_key_policy="ignore_all")
   elif answer == 2: # Add/Update
     local_kh = self.paths.known_hosts
     if not local_kh.is_file():
       open(local_kh, 'a').close()
     from paramiko import HostKeys
     hk = HostKeys(local_kh)
     hk.add(e.hostname, e.key.get_name(), e.key)
     hk.save(local_kh)
     log.info("Saved host key in %s", local_kh)
     self.requestInit()
   else:
     self.openSettings(prompt=False)
     self.quit()
Ejemplo n.º 17
0
def _get_hostkey(args):
    host = args['HOST']
    file = args['FILE']
    hash_ = args['--hash']
    try:
        port = strings.str2port(args['--port'])
        with Transport((host, port)) as transport:
            transport.start_client()
            hostkey = transport.get_remote_server_key()
            name = hostkey.get_name().split('-', 1)[1].upper()
            # same fingerprints as the OpenSSH commands generate
            print(f'{name} ({hostkey.get_bits()}) Fingerprints:')
            fp_md5 = hashlib.md5()
            fp_md5.update(hostkey.asbytes())
            fp_md5_dig = strings.insert_separator(fp_md5.hexdigest(), ':', 2)
            print(f' MD5: {fp_md5_dig}')
            fp_sha = hashlib.sha256()
            fp_sha.update(hostkey.asbytes())
            fp_sha_dig = base64.b64encode(fp_sha.digest()).decode().strip('=')
            print(f' SHA256: {fp_sha_dig}')
            while True:
                a = input(f'Save this key to file "{file}" (yes/no)? ').lower()
                if a in ('yes', 'no'):
                    break
                print('Type "yes" or "no"!')
            if a != 'no':
                hostname = utils.format_knownhost(host, port)
                hostkeys = HostKeys()
                addkey = True
                if os.path.exists(file):
                    hostkeys.load(file)
                    if hostkeys.lookup(hostname):
                        if hostkeys.check(hostname, hostkey):
                            print(f'Key for "{hostname}" exists'
                                  f' in file "{file}"')
                            addkey = False
                        else:
                            del hostkeys[hostname]
                            print(f'Key for "{hostname}" replaced'
                                  f' in file "{file}"')
                    else:
                        print(f'Key for "{hostname}" added in file "{file}"')
                else:
                    print(f'Key for "{hostname}" added in new file "{file}"')
                if addkey:
                    if hash_:
                        hostname = HostKeys.hash_host(hostname)
                    hostkeys.add(hostname, hostkey.get_name(), hostkey)
                    hostkeys.save(file)
    except ConfigError as ex:
        print(ex, file=sys.stderr)
        return ConfigError.code
    except (OSError, SSHException) as ex:
        print(ex, file=sys.stderr)
        return ConnectError.code
    except Exception as ex:
        print(repr(ex), file=sys.stderr)
        return ExitCodes.FAILURE.code
    return ExitCodes.SUCCESS.code