def executeMT(self, execOnMT, ipToCon): host = ipToCon user = self.loginSsh passwd = self.passwdSsh port = int(self.portSsh) timeout = self.timeoutSsh i = 0 while (True): if i < 3: try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) sock.connect((host, port)) session = Session() session.handshake(sock) session.userauth_password(user, passwd) channel = session.open_session() channel.execute(execOnMT) channel.wait_eof() channel.close() channel.wait_closed() except Exception as e: logging.warn('deamonMT: %s', (e)) else: logging.info('deamonMT: ssh commands has been sent, SUCCESS') break finally: sock.close() time.sleep(1) i += 1 else: logging.info("deamonMT: ssh can't connect to host: %s", (host)) break
def _connect(self): """create a connection for this thread""" self._abort = False size_bk = 0 if self.parent_ui: size_bk += self.parent_ui.progress["maximum"] self.parent_ui.progress.configure(mode="indeterminate", maximum=100) self.parent_ui.progress.start() if self._mode == "SFTP": try: sock = socket(AF_INET, SOCK_STREAM) sock.settimeout(10) sock.connect((self._host, self._port)) cli = Session() cli.set_timeout(10000) cli.handshake(sock) cli.userauth_password(self._name, self._passwd) cli.set_timeout(0) self._connection = cli.sftp_init() except Timeout: self._abort = True messagebox.showerror("Connection Error", "Connection timeout on login.") except AuthenticationError as e: self._abort = True messagebox.showerror("Authentication Error", "Wrong login credentials.") except Exception as e: print(type(e), e.args, str(e)) self._abort = True messagebox.showerror( "Connection Error", "Could not establish a connection.\n%s" % e) finally: if self.parent_ui: self.parent_ui.progress.stop() self.parent_ui.progress.configure(value=0, mode="determinate", maximum=size_bk) else: # FTP try: ftp = FTP() ftp.encoding = self._enc ftp.connect(self._host, self._port, 10) ftp.login(self._name, self._passwd) self._connection = ftp except Exception as e: self._abort = True messagebox.showerror("Connection Error", str(e)) finally: if self.parent_ui: self.parent_ui.progress.stop() self.parent_ui.progress.configure(value=0, mode="determinate", maximum=size_bk)
def main(): args = parser.parse_args() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((args.host, args.port)) s = Session() s.handshake(sock) print(args.user) print(args.host) print(args.port) #s.userauth_publickey_fromfile(args.user, "~/.ssh/id_rsa") passwd = input('Enter your password: '******'rb') as local_fh: for data in local_fh: chan.write(data) taken = datetime.now() - now rate = (fileinfo.st_size / (1024000.0)) / taken.total_seconds() print("Finished writing remote file in %s, transfer rate %s MB/s" % (taken, rate))
class SSH2TestCase(unittest.TestCase): @classmethod def setUpClass(cls): _mask = int('0600') if version_info <= (2, ) else 0o600 os.chmod(PKEY_FILENAME, _mask) cls.server = OpenSSHServer() cls.server.start_server() @classmethod def tearDownClass(cls): cls.server.stop() del cls.server def setUp(self): self.host = '127.0.0.1' self.port = 2222 self.cmd = 'echo me' self.resp = u'me' self.user_key = PKEY_FILENAME self.user_pub_key = PUB_FILE self.user = pwd.getpwuid(os.geteuid()).pw_name sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.host, self.port)) self.sock = sock self.session = Session() self.session.handshake(self.sock) def tearDown(self): del self.session del self.sock def _auth(self): return self.session.userauth_publickey_fromfile( self.user, self.user_pub_key, self.user_key, '')
def ssh_login(ip, username, password): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) is_ipv4_timeout = False is_ipv6_timeout = False while True: try: if not is_ipv4_timeout: print('[+]Try to connect to {}:22'.format(ip['v4'])) sock.connect((ip['v4'], 22)) elif not is_ipv6_timeout: sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) print('[+]Try to connect to {}:22'.format(ip['v6'])) sock.connect((ip['v6'], 22)) else: print( '[-]Cannot connect to host, rerun this script and try again' ) exit(0) break except TimeoutError as ex: print(ex) if not is_ipv4_timeout: is_ipv4_timeout = True elif not is_ipv6_timeout: is_ipv6_timeout = True except ConnectionRefusedError as ex: print(ex) print('[+] Sleep 5s and then retry ...') time.sleep(5) print('[+]Connect success') session = Session() session.handshake(sock) session.userauth_password(username, password) return session
def test_callback_set(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.host, self.port)) session = Session() # These variables have to be attached to the class scope # in order to be modified inside the callback. Local scope # is not passed into the callback. self.send_called = False self.recv_called = False def _send_callback(fd, buf, flags): self.send_called = True return sock.sendall(buf, flags) def _recv_callback(fd, length, flags): self.recv_called = True return sock.recv(length, flags) session.set_recv_callback(_recv_callback) session.set_send_callback(_send_callback) session.handshake(sock) self.assertTrue(self.send_called) self.assertTrue(self.recv_called)
def main(): args = parser.parse_args() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((args.host, args.port)) s = Session() s.handshake(sock) # Agent connections cannot be used as non-blocking s.agent_auth(args.user) # Now we can set non-blocking mode s.set_blocking(False) chan = s.open_session() while chan == LIBSSH2_ERROR_EAGAIN: print("Would block on session open, waiting for socket to be ready") wait_socket(sock, s) chan = s.open_session() while chan.execute(args.cmd) == LIBSSH2_ERROR_EAGAIN: print("Would block on channel execute, waiting for socket to be ready") wait_socket(sock, s) while chan.wait_eof() == LIBSSH2_ERROR_EAGAIN: print("Waiting for command to finish") wait_socket(sock, s) size, data = chan.read() while size == LIBSSH2_ERROR_EAGAIN: print("Waiting to read data from channel") wait_socket(sock, s) size, data = chan.read() while size > 0: print(data) size, data = chan.read()
def ssh2_ssh(host, port=22, user='******', password='******'): global command # Make socket, connect sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) # Initialise session = Session() session.handshake(sock) session.userauth_password(user, password) # Public key blob available as identities[0].blob # Channel initialise, exec and wait for end channel = session.open_session() channel.execute(command) channel.wait_eof() channel.close() channel.wait_closed() # Print output output = b'' size, data = channel.read() while size > 0: output += data size, data = channel.read() # Get exit status output = output.decode("utf-8").strip()
def DOS_attack_SSH(): host = TARGET password = input('enter password > ') usr = os.getlogin() try: while True: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TARGET, PORT)) print(f'ssh connected: {TARGER} on PORT {PORT}') # SSH exclusive msg sending session = Session() session.handshake(s) session.agent_auth(usr) # trying an ssh session try: channel = session.open_session() channel.execute('echo "u heb bin heked";') channel.close() except: pass global Breach_count Breach_count += 1 print(Breach_count) s.close() except Exception as e: print(e)
def main(): print('asdfasdf') sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('reports.paypal.com', 22)) s = Session() s.handshake(sock) s.userauth_password(USERID, PASSWORD) chan = s.open_session() print('connected') sftp = s.sftp_init() print('sftp done') now = datetime.now() outf = open(RESULTFILE, "w+") filelist = getNames(YEAR, MONTH) with open(FILEOUT, 'w+') as f: for fileName in filelist: with sftp.open('/pptransfers/outgoing/' + fileName, LIBSSH2_FXF_READ, LIBSSH2_SFTP_S_IRUSR) as fh: print('sftp done') for size, data in fh: f.write(data) f.close() f = open(FILEOUT, 'r') for row in f: if row.startswith("SB") or row.startswith('"SB'): outf.write(row) outf.close() print("Finished file read in %s" % (datetime.now() - now, )) f.close()
class SSH2CertTestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls.user = getpass.getuser() cls.user_key = os.path.join(BASE_PATH, 'signed_key_ecdsa') cls.user_pub_key = f"{cls.user_key}.pub" cls.user_cert = f"{cls.user_key}-cert.pub" cls.server = OpenSSHServer() cls.server.sign_key(cls.user) cls.server.start_server() @classmethod def tearDownClass(cls): cls.server.stop() del cls.server def setUp(self): self.host = '127.0.0.1' self.port = 2222 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.host, self.port)) self.sock = sock self.session = Session() self.session.handshake(self.sock) def tearDown(self): del self.session self.sock.close() del self.sock
def configure_server(): """ Function to configure servers :param : """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((listToString(SERVER[0]), 22)) # assign to session class session = Session() # set up 3 way handshake logging.info('Setting up 3-way handshake') session.handshake(sock) logging.debug('Username is %s', USERNAME) logging.debug('password %s', PASSWORD) session.userauth_password(USERNAME, PASSWORD) channel = session.open_session() channel.execute( "apt-get update -y; apt-get install apache2 -y; systemctl start apache2.service" ) size, data = channel.read() # while (size > 0): # print(data.decode()) # size, data = channel.read() channel.close() print("Exit status : {0}", format(channel.get_exit_status()))
def _establish_ssh_session(self): # Connect to remote host. try: sock = socket.create_connection( (str(self._ssh_host), self._ssh_port)) except Exception: log.error("Cannot connect to host '%s' (%s, %d).", self.name, self._ssh_host, self._ssh_port) raise # SSH handshake. ssh_session = Session() ssh_session.handshake(sock) # Verify host key. Accept keys from previously unknown hosts on first connection. hosts = ssh_session.knownhost_init() testbed_root = os.path.dirname(os.path.abspath(inspect.stack()[-1][1])) known_hosts_path = os.path.join(testbed_root, KNOWN_HOSTS_FILE) try: hosts.readfile(known_hosts_path) except ssh2.exceptions.KnownHostReadFileError: pass # ignore, file is created/overwritten later host_key, key_type = ssh_session.hostkey() server_type = None if key_type == LIBSSH2_HOSTKEY_TYPE_RSA: server_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA else: server_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS type_mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | server_type try: hosts.checkp( str(self._ssh_host).encode('utf-8'), self._ssh_port, host_key, type_mask) except ssh2.exceptions.KnownHostCheckNotFoundError: log.warn("Host key of '%s' (%s, %d) added to known hosts.", self.name, self._ssh_host, self._ssh_port) hosts.addc( str(self._ssh_host).encode('utf-8'), host_key, type_mask) hosts.writefile(known_hosts_path) except ssh2.exceptions.KnownHostCheckMisMatchError: log.error("Host key of '%s' (%s, %d) does not match known key.", self.name, self._ssh_host, self._ssh_port) raise # Authenticate at remote host. try: if self._identity_file is None: ssh_session.agent_auth(self._username) else: ssh_session.userauth_publickey_fromfile( self._username, self._identity_file) except Exception: log.error("Authentication at host '%s' (%s, %d) failed.", self.name, self._ssh_host, self._ssh_port) ssh_session.disconnect() raise return ssh_session
def connect(self, privatekey_file="~/.ssh/id_rsa", passphrase='', open_channel=True): """Connect active host and open a session Args: privatekey_file: a string representing the path to the private key file passphrase: a string representing the password open_channel: if `True`, open the SSH channel Returns: None """ privatekey_file = os.path.expanduser(privatekey_file) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.active_host[2], self.active_host[3])) s = Session() s.handshake(sock) try: # Try using private key file first s.userauth_publickey_fromfile(self.active_host[1], privatekey_file, passphrase) except: # Use password to auth passwd = getpass( 'No private key found.\nEnter your password for %s: ' % self.active_host[1]) s.userauth_password(self.active_host[1], passwd) self.session = s if open_channel: self.channel = self.session.open_session() return
def host_scp_send(self, local_file, remote_file): assert self.operation_system == 'Linux', "[Assert Error] Only Linux OS is supported!" file_stat = os.stat(local_file) # Make socket, connect sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.host_ip, self.port)) # Initialise session = Session() session.handshake(sock) userauth_list = session.userauth_list(self.username) self.LOG.print_log( 'DEBUG', "In host {}, user {} authentication list is: {}.".format( self.host_ip, self.username, userauth_list)) session.userauth_password(self.username, self.password) # Channel initialise, exec and wait for end self.LOG.print_log( 'INFO', "Send local file {} to Host {} at {}.".format( local_file, self.host_ip, remote_file)) try: channel = session.scp_send(remote_file, file_stat.st_mode & 777, file_stat.st_size) with open(local_file, 'rb') as local_fh: for data in local_fh: channel.write(data) channel.send_eof() channel.wait_eof() channel.wait_closed() except Exception as err: self.LOG.print_log('ERROR', str(err)) assert False, "[Assert Error] Something wrong during scp send!"
def ssh_login3(user): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) sock.setblocking(1) session = Session() session.handshake(sock) try: session.userauth_password(user, '123456') except AuthenticationError: return print(user)
def start_session(self, hostname, username): sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) sock.connect((hostname, 22)) s = Session() s.handshake(sock) auth_methods = s.userauth_list(username) if 'publickey' in auth_methods: s.agent_auth(username) return s else: # print("Available authentiation methods: %s" % auth_methods) sys.exit("Only publickey is supported now!")
def _make_session(self) -> Session: """Makes SSH connection and handshake. Returns: Session: Succesfully connected Session object. """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.host, self.port)) session = Session() session.handshake(sock) session.userauth_publickey_fromfile(self.user, self.key) return session
class _SSHClient(SSHClient): def __init__(self, host, port, num_retries): super(SSHClient, self).__init__(host, port=port, num_retries=2, allow_agent=True) def _init(self): self.session = Session() if self.timeout: self.session.set_timeout(self.timeout * 1000) self.session.handshake(self.sock)
def main(): args = parser.parse_args() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((args.host, args.port)) s = Session() s.handshake(sock) s.userauth_password(args.user, args.password) chan = s.open_session() chan.execute(args.cmd) size, data = chan.read() while size > 0: print(data) size, data = chan.read()
def main(): args = parser.parse_args() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((args.host, args.port)) s = Session() s.handshake(sock) s.agent_auth(args.user) sftp = s.sftp_init() now = datetime.now() print("Starting read for remote file %s" % (args.file, )) with sftp.open(args.file, 0, 0) as fh: for size, data in fh: pass print("Finished file read in %s" % (datetime.now() - now, ))
def conexionSSH(dest_host, comando): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((dest_host, 22)) session = Session() session.handshake(sock) session.userauth_password(ciscoUser, ciscoPass) channel = session.open_session() channel.execute(comando) size, data = channel.read() if size > 0: comandoOut = data.decode('utf-8') channel.close() return comandoOut
def test_non_blocking_handshake(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.host, self.port)) session = Session() session.set_blocking(0) while session.handshake(sock) == LIBSSH2_ERROR_EAGAIN: continue
class _SSHClient(SSHClient): def __init__(self, host, port, num_retries): self.keepalive_seconds = None super(SSHClient, self).__init__(host, port=port, num_retries=2, allow_agent=True) def _init_session(self): self.session = Session() if self.timeout: self.session.set_timeout(self.timeout * 1000) self.session.handshake(self.sock) def _auth_retry(self): pass
class SSH(object): socket = None session = None channel = None def __init__(self, hostname, port, username, password): self.hostname = hostname self.port = port self.username = username self.password = password def full_init(self): self.create_socket() if self.create_session(): return 1 self.create_channel() return 0 def create_socket(self): self.socket = socket(AF_INET, SOCK_STREAM) self.socket.connect((self.hostname, self.port)) def create_session(self): self.session = Session() self.session.set_timeout(0.5) self.session.handshake(self.socket) return self.session.userauth_password(self.username, self.password) def create_channel(self): self.channel = self.session.open_session() def execute_command(self, command): self.channel.execute(command) ret_data = "" size = 1 while size > 0: size, data = self.channel.read() ret_data = ret_data + data return ret_data def destroy(self): if self.channel != None: self.channel.close() if self.socket != None: self.socket.close()
def notify_finished_ssh(self): ''' Connect to yannics PC via ssh and make popup''' host = '134.95.66.248' user = '******' sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, 22)) session = Session() session.handshake(sock) session.userauth_password(user, self.ssh_password) channel = session.open_session() now = datetime.datetime.now().time() channel.execute( 'export DISPLAY=:0; notify-send -t 100000 "Heating Finished" "Finished at time: {}"' .format(now)) channel.close()
def perform_ssh_request(username, password): host = '127.0.0.1' print("try", username, password) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, 3222)) session = Session() session.handshake(sock) try: session.userauth_password(username, password) channel = session.open_session() channel.close() print("found correct username: %s password: %s" % username, password) exit() except AuthenticationError: pass
def main(): args = parser.parse_args() if not os.path.isfile(args.privatekey): print("No such private key %s" % (args.privatekey, )) sys.exit(1) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((args.host, args.port)) s = Session() s.handshake(sock) s.userauth_publickey_fromfile(args.user, args.privatekey, passphrase=args.passphrase) chan = s.open_session() chan.execute(args.cmd) size, data = chan.read() while size > 0: print(data) size, data = chan.read()
def gethostname(ip): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, 22)) session = Session() session.handshake(sock) session.userauth_password(DOCKER_DAEMON_HOST_USR, DOCKER_DAEMON_HOST_PWD) channel = session.open_session() channel.execute(r'hostname') size, data = channel.read() while size > 0: hostname = data.decode('utf-8').split('\n')[0] size, data = channel.read() channel.close() return hostname
def __init__(self, address, username, password, port, timeout): logging.info("ssh: connecting to server: %s " % (address)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) try: sock.connect((address, port)) except: self.status = False logging.warn("ssh: can't connect to server: %s " % (address)) else: s = Session() s.handshake(sock) try: s.userauth_password(username, password) except: self.status = False logging.warn("ssh: bad login or password: %s " % (address)) else: self.client = s.open_session() self.status = True
class IrmaSFTPv2(FTPInterface): """Irma SFTPv2 handler This class handles the connection with a sftp server functions for interacting with it. """ _Exception = IrmaSFTPv2Error # ================================== # Constructor and Destructor stuff # ================================== def __init__(self, host, port, auth, key_path, user, passwd, dst_user=None, upload_path='uploads', hash_check=False, autoconnect=True): self._sess = None self._client = None super().__init__(host, port, auth, key_path, user, passwd, dst_user, upload_path, hash_check, autoconnect) def connected(self): return self._sess is not None # ============================ # Overridden private methods # ============================ def _connect(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self._host, self._port)) self._sess = Session() self._sess.handshake(sock) if self._auth == 'key': # self._pubkey_path must be generated from private key # s.userauth_publickey_fromfile(self._user, self._pubkey_path, # self._key_path, '') raise IrmaSFTPv2Error("Pub key authentication not implemented") else: self._sess.userauth_password(self._user, self._passwd) self._client = self._sess.sftp_init() def _disconnect(self, *, force=False): self._client = None if not force: self._sess.disconnect() self._sess = None def _upload(self, remote, fobj): mode = LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | \ LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH opt = LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE with self._client.open(remote, opt, mode) as rfh: for chunk in iter(lambda: fobj.read(1024*1024), b""): rfh.write(chunk) def _download(self, remote, fobj): with self._client.open(remote, 0, 0) as rfh: for size, data in rfh: fobj.write(data) def _ls(self, remote): with self._client.opendir(remote) as rfh: paths = (p[1].decode('utf-8') for p in rfh.readdir()) return [p for p in paths if p not in ['.', '..']] def _is_file(self, remote): return not self._is_dir(remote) def _is_dir(self, remote): st = self._client.stat(remote) return stat.S_ISDIR(st.st_mode) def _rm(self, remote): self._client.unlink(remote) def _rmdir(self, remote): self._client.rmdir(remote) def _mkdir(self, remote): mode = LIBSSH2_SFTP_S_IRUSR | \ LIBSSH2_SFTP_S_IWUSR | \ LIBSSH2_SFTP_S_IXUSR self._client.mkdir(remote, mode) def _mv(self, oldremote, newremote): self._client.rename(oldremote, newremote)
class SSHClient(object): """ssh2-python (libssh2) based non-blocking SSH client.""" IDENTITIES = ( os.path.expanduser('~/.ssh/id_rsa'), os.path.expanduser('~/.ssh/id_dsa'), os.path.expanduser('~/.ssh/identity'), os.path.expanduser('~/.ssh/id_ecdsa'), ) def __init__(self, host, user=None, password=None, port=None, pkey=None, num_retries=DEFAULT_RETRIES, retry_delay=RETRY_DELAY, allow_agent=True, timeout=None, forward_ssh_agent=False, proxy_host=None, _auth_thread_pool=True, keepalive_seconds=60): """:param host: Host name or IP to connect to. :type host: str :param user: User to connect as. Defaults to logged in user. :type user: str :param password: Password to use for password authentication. :type password: str :param port: SSH port to connect to. Defaults to SSH default (22) :type port: int :param pkey: Private key file path to use for authentication. Path must be either absolute path or relative to user home directory like ``~/<path>``. :type pkey: str :param num_retries: (Optional) Number of connection and authentication attempts before the client gives up. Defaults to 3. :type num_retries: int :param retry_delay: Number of seconds to wait between retries. Defaults to :py:class:`pssh.constants.RETRY_DELAY` :type retry_delay: int :param timeout: SSH session timeout setting in seconds. This controls timeout setting of authenticated SSH sessions. :type timeout: int :param allow_agent: (Optional) set to False to disable connecting to the system's SSH agent :type allow_agent: bool :param forward_ssh_agent: (Optional) Turn on SSH agent forwarding - equivalent to `ssh -A` from the `ssh` command line utility. Defaults to True if not set. :type forward_ssh_agent: bool :param proxy_host: Connection to host is via provided proxy host and client should use self.proxy_host for connection attempts. :type proxy_host: str :param keepalive_seconds: Interval of keep alive messages being sent to server. Set to ``0`` or ``False`` to disable. :raises: :py:class:`pssh.exceptions.PKeyFileError` on errors finding provided private key. """ self.host = host self.user = user if user else None if self.user is None and not WIN_PLATFORM: self.user = pwd.getpwuid(os.geteuid()).pw_name elif self.user is None and WIN_PLATFORM: raise ValueError("Must provide user parameter on Windows") self.password = password self.port = port if port else 22 self.num_retries = num_retries self.sock = None self.timeout = timeout self.retry_delay = retry_delay self.allow_agent = allow_agent self.forward_ssh_agent = forward_ssh_agent self._forward_requested = False self.session = None self.keepalive_seconds = keepalive_seconds self._keepalive_greenlet = None self._host = proxy_host if proxy_host else host self.pkey = _validate_pkey_path(pkey, self.host) self._connect(self._host, self.port) if _auth_thread_pool: THREAD_POOL.apply(self._init) else: self._init() def disconnect(self): """Disconnect session, close socket if needed.""" if self.session is not None: try: self._eagain(self.session.disconnect) except Exception: pass if self.sock is not None and not self.sock.closed: self.sock.close() def __del__(self): self.disconnect() def __enter__(self): return self def __exit__(self, *args): self.disconnect() def spawn_send_keepalive(self): """Spawns a new greenlet that sends keep alive messages every self.keepalive_seconds""" return spawn(self._send_keepalive) def _send_keepalive(self): while True: sleep(self._eagain(self.session.keepalive_send)) def configure_keepalive(self): self.session.keepalive_config(False, self.keepalive_seconds) def _connect_init_retry(self, retries): retries += 1 self.session = None if not self.sock.closed: self.sock.close() sleep(self.retry_delay) self._connect(self._host, self.port, retries=retries) return self._init(retries=retries) def _init(self, retries=1): self.session = Session() if self.timeout: # libssh2 timeout is in ms self.session.set_timeout(self.timeout * 1000) try: self.session.handshake(self.sock) except Exception as ex: while retries < self.num_retries: return self._connect_init_retry(retries) msg = "Error connecting to host %s:%s - %s" logger.error(msg, self.host, self.port, ex) if isinstance(ex, SSH2Timeout): raise Timeout(msg, self.host, self.port, ex) raise try: self.auth() except Exception as ex: while retries < self.num_retries: return self._connect_init_retry(retries) msg = "Authentication error while connecting to %s:%s - %s" raise AuthenticationException(msg, self.host, self.port, ex) self.session.set_blocking(0) if self.keepalive_seconds: self.configure_keepalive() self._keepalive_greenlet = self.spawn_send_keepalive() def _connect(self, host, port, retries=1): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.timeout: self.sock.settimeout(self.timeout) logger.debug("Connecting to %s:%s", host, port) try: self.sock.connect((host, port)) except sock_gaierror as ex: logger.error("Could not resolve host '%s' - retry %s/%s", host, retries, self.num_retries) while retries < self.num_retries: sleep(self.retry_delay) return self._connect(host, port, retries=retries+1) raise UnknownHostException("Unknown host %s - %s - retry %s/%s", host, str(ex.args[1]), retries, self.num_retries) except sock_error as ex: logger.error("Error connecting to host '%s:%s' - retry %s/%s", host, port, retries, self.num_retries) while retries < self.num_retries: sleep(self.retry_delay) return self._connect(host, port, retries=retries+1) error_type = ex.args[1] if len(ex.args) > 1 else ex.args[0] raise ConnectionErrorException( "Error connecting to host '%s:%s' - %s - retry %s/%s", host, port, str(error_type), retries, self.num_retries,) def _pkey_auth(self): self.session.userauth_publickey_fromfile( self.user, self.pkey, passphrase=self.password if self.password is not None else '') def _identity_auth(self): passphrase = self.password if self.password is not None else '' for identity_file in self.IDENTITIES: if not os.path.isfile(identity_file): continue logger.debug( "Trying to authenticate with identity file %s", identity_file) try: self.session.userauth_publickey_fromfile( self.user, identity_file, passphrase=passphrase) except Exception: logger.debug("Authentication with identity file %s failed, " "continuing with other identities", identity_file) continue else: logger.debug("Authentication succeeded with identity file %s", identity_file) return raise AuthenticationException("No authentication methods succeeded") def auth(self): if self.pkey is not None: logger.debug( "Proceeding with private key file authentication") return self._pkey_auth() if self.allow_agent: try: self.session.agent_auth(self.user) except Exception as ex: logger.debug("Agent auth failed with %s, " "continuing with other authentication methods", ex) else: logger.debug("Authentication with SSH Agent succeeded") return try: self._identity_auth() except AuthenticationException: if self.password is None: raise logger.debug("Private key auth failed, trying password") self._password_auth() def _password_auth(self): try: self.session.userauth_password(self.user, self.password) except Exception: raise AuthenticationException("Password authentication failed") def open_session(self): """Open new channel from session""" try: chan = self.session.open_session() except Exception as ex: raise SessionError(ex) while chan == LIBSSH2_ERROR_EAGAIN: wait_select(self.session) try: chan = self.session.open_session() except Exception as ex: raise SessionError(ex) # Multiple forward requests result in ChannelRequestDenied # errors, flag is used to avoid this. if self.forward_ssh_agent and not self._forward_requested: if not hasattr(chan, 'request_auth_agent'): warn("Requested SSH Agent forwarding but libssh2 version used " "does not support it - ignoring") return chan self._eagain(chan.request_auth_agent) self._forward_requested = True return chan def execute(self, cmd, use_pty=False, channel=None): """Execute command on remote server. :param cmd: Command to execute. :type cmd: str :param use_pty: Whether or not to obtain a PTY on the channel. :type use_pty: bool :param channel: Use provided channel for execute rather than creating a new one. :type channel: :py:class:`ssh2.channel.Channel` """ channel = self.open_session() if channel is None else channel if use_pty: self._eagain(channel.pty) logger.debug("Executing command '%s'" % cmd) self._eagain(channel.execute, cmd) return channel def read_stderr(self, channel, timeout=None): """Read standard error buffer from channel. :param channel: Channel to read output from. :type channel: :py:class:`ssh2.channel.Channel` """ return _read_output(self.session, channel.read_stderr, timeout=timeout) def read_output(self, channel, timeout=None): """Read standard output buffer from channel. :param channel: Channel to read output from. :type channel: :py:class:`ssh2.channel.Channel` """ return _read_output(self.session, channel.read, timeout=timeout) def _select_timeout(self, func, timeout): ret = func() while ret == LIBSSH2_ERROR_EAGAIN: wait_select(self.session, timeout=timeout) ret = func() if ret == LIBSSH2_ERROR_EAGAIN and timeout is not None: raise Timeout def wait_finished(self, channel, timeout=None): """Wait for EOF from channel and close channel. Used to wait for remote command completion and be able to gather exit code. :param channel: The channel to use. :type channel: :py:class:`ssh2.channel.Channel` """ if channel is None: return # If .eof() returns EAGAIN after a select with a timeout, it means # it reached timeout without EOF and _select_timeout will raise # timeout exception causing the channel to appropriately # not be closed as the command is still running. self._select_timeout(channel.wait_eof, timeout) # Close channel to indicate no more commands will be sent over it self.close_channel(channel) def close_channel(self, channel): logger.debug("Closing channel") self._eagain(channel.close) def _eagain(self, func, *args, **kwargs): ret = func(*args, **kwargs) while ret == LIBSSH2_ERROR_EAGAIN: wait_select(self.session) ret = func(*args, **kwargs) return ret def read_output_buffer(self, output_buffer, prefix=None, callback=None, callback_args=None, encoding='utf-8'): """Read from output buffers and log to ``host_logger``. :param output_buffer: Iterator containing buffer :type output_buffer: iterator :param prefix: String to prefix log output to ``host_logger`` with :type prefix: str :param callback: Function to call back once buffer is depleted: :type callback: function :param callback_args: Arguments for call back function :type callback_args: tuple """ prefix = '' if prefix is None else prefix for line in output_buffer: output = line.decode(encoding) host_logger.info("[%s]%s\t%s", self.host, prefix, output) yield output if callback: callback(*callback_args) def run_command(self, command, sudo=False, user=None, use_pty=False, shell=None, encoding='utf-8', timeout=None): """Run remote command. :param command: Command to run. :type command: str :param sudo: Run command via sudo as super-user. :type sudo: bool :param user: Run command as user via sudo :type user: str :param use_pty: Whether or not to obtain a PTY on the channel. :type use_pty: bool :param shell: (Optional) Override shell to use to run command with. Defaults to login user's defined shell. Use the shell's command syntax, eg `shell='bash -c'` or `shell='zsh -c'`. :type shell: str :param encoding: Encoding to use for output. Must be valid `Python codec <https://docs.python.org/2.7/library/codecs.html>`_ :type encoding: str :rtype: (channel, host, stdout, stderr, stdin) tuple. """ # Fast path for no command substitution needed if not sudo and not user and not shell: _command = command else: _command = '' if sudo and not user: _command = 'sudo -S ' elif user: _command = 'sudo -u %s -S ' % (user,) _shell = shell if shell else '$SHELL -c' _command += "%s '%s'" % (_shell, command,) channel = self.execute(_command, use_pty=use_pty) return channel, self.host, \ self.read_output_buffer( self.read_output(channel, timeout=timeout), encoding=encoding), \ self.read_output_buffer( self.read_stderr(channel, timeout=timeout), encoding=encoding, prefix='\t[err]'), channel def _make_sftp(self): """Make SFTP client from open transport""" try: sftp = self.session.sftp_init() except Exception as ex: raise SFTPError(ex) while sftp == LIBSSH2_ERROR_EAGAIN: wait_select(self.session) try: sftp = self.session.sftp_init() except Exception as ex: raise SFTPError(ex) return sftp def _mkdir(self, sftp, directory): """Make directory via SFTP channel :param sftp: SFTP client object :type sftp: :py:class:`ssh2.sftp.SFTP` :param directory: Remote directory to create :type directory: str :raises: :py:class:`pssh.exceptions.SFTPIOError` on SFTP IO errors """ mode = LIBSSH2_SFTP_S_IRUSR | \ LIBSSH2_SFTP_S_IWUSR | \ LIBSSH2_SFTP_S_IXUSR | \ LIBSSH2_SFTP_S_IRGRP | \ LIBSSH2_SFTP_S_IROTH | \ LIBSSH2_SFTP_S_IXGRP | \ LIBSSH2_SFTP_S_IXOTH try: self._eagain(sftp.mkdir, directory, mode) except SFTPProtocolError as error: msg = "Error occured creating directory %s on host %s - %s" logger.error(msg, directory, self.host, error) raise SFTPIOError(msg, directory, self.host, error) logger.debug("Created remote directory %s", directory) def copy_file(self, local_file, remote_file, recurse=False, sftp=None, _dir=None): """Copy local file to host via SFTP. :param local_file: Local filepath to copy to remote host :type local_file: str :param remote_file: Remote filepath on remote host to copy file to :type remote_file: str :param recurse: Whether or not to descend into directories recursively. :type recurse: bool :raises: :py:class:`ValueError` when a directory is supplied to ``local_file`` and ``recurse`` is not set :raises: :py:class:`pss.exceptions.SFTPError` on SFTP initialisation errors :raises: :py:class:`pssh.exceptions.SFTPIOError` on I/O errors writing via SFTP :raises: :py:class:`IOError` on local file IO errors :raises: :py:class:`OSError` on local OS errors like permission denied """ sftp = self._make_sftp() if sftp is None else sftp if os.path.isdir(local_file) and recurse: return self._copy_dir(local_file, remote_file, sftp) elif os.path.isdir(local_file) and not recurse: raise ValueError("Recurse must be true if local_file is a " "directory.") destination = self._remote_paths_split(remote_file) if destination is not None: try: self._eagain(sftp.stat, destination) except (SFTPHandleError, SFTPProtocolError): self.mkdir(sftp, destination) self.sftp_put(sftp, local_file, remote_file) logger.info("Copied local file %s to remote destination %s:%s", local_file, self.host, remote_file) def _sftp_put(self, remote_fh, local_file): with open(local_file, 'rb', 2097152) as local_fh: for data in local_fh: eagain_write(remote_fh.write, data, self.session) def sftp_put(self, sftp, local_file, remote_file): mode = LIBSSH2_SFTP_S_IRUSR | \ LIBSSH2_SFTP_S_IWUSR | \ LIBSSH2_SFTP_S_IRGRP | \ LIBSSH2_SFTP_S_IROTH f_flags = LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE | LIBSSH2_FXF_TRUNC with self._sftp_openfh( sftp.open, remote_file, f_flags, mode) as remote_fh: try: self._sftp_put(remote_fh, local_file) # THREAD_POOL.apply( # sftp_put, args=(self.session, remote_fh, local_file)) except SFTPProtocolError as ex: msg = "Error writing to remote file %s - %s" logger.error(msg, remote_file, ex) raise SFTPIOError(msg, remote_file, ex) def mkdir(self, sftp, directory, _parent_path=None): """Make directory via SFTP channel. Parent paths in the directory are created if they do not exist. :param sftp: SFTP client object :type sftp: :py:class:`paramiko.sftp_client.SFTPClient` :param directory: Remote directory to create :type directory: str Catches and logs at error level remote IOErrors on creating directory. """ try: _dir, sub_dirs = directory.split('/', 1) except ValueError: _dir = directory.split('/', 1)[0] sub_dirs = None if not _dir and directory.startswith('/'): try: _dir, sub_dirs = sub_dirs.split(os.path.sep, 1) except ValueError: return True if _parent_path is not None: _dir = '/'.join((_parent_path, _dir)) try: self._eagain(sftp.stat, _dir) except (SFTPHandleError, SFTPProtocolError) as ex: logger.debug("Stat for %s failed with %s", _dir, ex) self._mkdir(sftp, _dir) if sub_dirs is not None: if directory.startswith('/'): _dir = ''.join(('/', _dir)) return self.mkdir(sftp, sub_dirs, _parent_path=_dir) def _copy_dir(self, local_dir, remote_dir, sftp): """Call copy_file on every file in the specified directory, copying them to the specified remote directory.""" file_list = os.listdir(local_dir) for file_name in file_list: local_path = os.path.join(local_dir, file_name) remote_path = '/'.join([remote_dir, file_name]) self.copy_file(local_path, remote_path, recurse=True, sftp=sftp) def copy_remote_file(self, remote_file, local_file, recurse=False, sftp=None, encoding='utf-8'): """Copy remote file to local host via SFTP. :param remote_file: Remote filepath to copy from :type remote_file: str :param local_file: Local filepath where file(s) will be copied to :type local_file: str :param recurse: Whether or not to recursively copy directories :type recurse: bool :param encoding: Encoding to use for file paths. :type encoding: str :raises: :py:class:`ValueError` when a directory is supplied to ``local_file`` and ``recurse`` is not set :raises: :py:class:`pss.exceptions.SFTPError` on SFTP initialisation errors :raises: :py:class:`pssh.exceptions.SFTPIOError` on I/O errors reading from SFTP :raises: :py:class:`IOError` on local file IO errors :raises: :py:class:`OSError` on local OS errors like permission denied """ sftp = self._make_sftp() if sftp is None else sftp try: self._eagain(sftp.stat, remote_file) except (SFTPHandleError, SFTPProtocolError): msg = "Remote file or directory %s does not exist" logger.error(msg, remote_file) raise SFTPIOError(msg, remote_file) try: dir_h = self._sftp_openfh(sftp.opendir, remote_file) except SFTPError: pass else: if not recurse: raise ValueError("Recurse must be true if remote_file is a " "directory.") file_list = self._sftp_readdir(dir_h) return self._copy_remote_dir(file_list, remote_file, local_file, sftp, encoding=encoding) destination = os.path.join(os.path.sep, os.path.sep.join( [_dir for _dir in local_file.split('/') if _dir][:-1])) self._make_local_dir(destination) self.sftp_get(sftp, remote_file, local_file) logger.info("Copied local file %s from remote destination %s:%s", local_file, self.host, remote_file) def scp_recv(self, remote_file, local_file, recurse=False, sftp=None, encoding='utf-8'): """Copy remote file to local host via SCP. Note - Remote directory listings are gather via SFTP when ``recurse`` is enabled - SCP lacks directory list support. Enabling recursion therefore involves creating an extra SFTP channel and requires SFTP support on the server. :param remote_file: Remote filepath to copy from :type remote_file: str :param local_file: Local filepath where file(s) will be copied to :type local_file: str :param recurse: Whether or not to recursively copy directories :type recurse: bool :param encoding: Encoding to use for file paths when recursion is enabled. :type encoding: str :raises: :py:class:`pssh.exceptions.SCPError` when a directory is supplied to ``local_file`` and ``recurse`` is not set. :raises: :py:class:`pssh.exceptions.SCPError` on errors copying file. :raises: :py:class:`IOError` on local file IO errors. :raises: :py:class:`OSError` on local OS errors like permission denied. """ sftp = self._make_sftp() if (sftp is None and recurse) else sftp if recurse: try: self._eagain(sftp.stat, remote_file) except (SFTPHandleError, SFTPProtocolError): msg = "Remote file or directory %s does not exist" logger.error(msg, remote_file) raise SCPError(msg, remote_file) try: dir_h = self._sftp_openfh(sftp.opendir, remote_file) except SFTPError: pass else: file_list = self._sftp_readdir(dir_h) return self._scp_recv_dir(file_list, remote_file, local_file, sftp, encoding=encoding) destination = os.path.join(os.path.sep, os.path.sep.join( [_dir for _dir in local_file.split('/') if _dir][:-1])) self._make_local_dir(destination) self._scp_recv(remote_file, local_file) logger.info("SCP local file %s from remote destination %s:%s", local_file, self.host, remote_file) def _scp_recv(self, remote_file, local_file): try: (file_chan, fileinfo) = self._eagain( self.session.scp_recv2, remote_file) except Exception as ex: msg = "Error copying file %s from host %s - %s" logger.error(msg, remote_file, self.host, ex) raise SCPError(msg, remote_file, self.host, ex) local_fh = open(local_file, 'wb') try: total = 0 size, data = file_chan.read(size=fileinfo.st_size) while size == LIBSSH2_ERROR_EAGAIN: wait_select(self.session) size, data = file_chan.read(size=fileinfo.st_size) total += size local_fh.write(data) while total < fileinfo.st_size: size, data = file_chan.read(size=fileinfo.st_size - total) while size == LIBSSH2_ERROR_EAGAIN: wait_select(self.session) continue total += size local_fh.write(data) if total != fileinfo.st_size: msg = "Error copying data from remote file %s on host %s. " \ "Copied %s out of %s total bytes" raise SCPError(msg, remote_file, self.host, total, fileinfo.st_size) finally: local_fh.close() def _scp_send_dir(self, local_dir, remote_dir, sftp): file_list = os.listdir(local_dir) for file_name in file_list: local_path = os.path.join(local_dir, file_name) remote_path = '/'.join([remote_dir, file_name]) self.scp_send(local_path, remote_path, recurse=True, sftp=sftp) def _scp_recv_dir(self, file_list, remote_dir, local_dir, sftp, encoding='utf-8'): for file_name in file_list: file_name = file_name.decode(encoding) if file_name in ('.', '..'): continue remote_path = os.path.join(remote_dir, file_name) local_path = os.path.join(local_dir, file_name) logger.debug("Attempting recursive copy from %s:%s to %s", self.host, remote_path, local_path) self.scp_recv(remote_path, local_path, sftp=sftp, recurse=True) def scp_send(self, local_file, remote_file, recurse=False, sftp=None): """Copy local file to host via SCP. Note - Directories are created via SFTP when ``recurse`` is enabled - SCP lacks directory create support. Enabling recursion therefore involves creating an extra SFTP channel and requires SFTP support on the server. :param local_file: Local filepath to copy to remote host :type local_file: str :param remote_file: Remote filepath on remote host to copy file to :type remote_file: str :param recurse: Whether or not to descend into directories recursively. :type recurse: bool :raises: :py:class:`ValueError` when a directory is supplied to ``local_file`` and ``recurse`` is not set :raises: :py:class:`pss.exceptions.SFTPError` on SFTP initialisation errors :raises: :py:class:`pssh.exceptions.SFTPIOError` on I/O errors writing via SFTP :raises: :py:class:`IOError` on local file IO errors :raises: :py:class:`OSError` on local OS errors like permission denied """ if os.path.isdir(local_file) and recurse: sftp = self._make_sftp() if sftp is None else sftp return self._scp_send_dir(local_file, remote_file, sftp) elif os.path.isdir(local_file) and not recurse: raise ValueError("Recurse must be True if local_file is a " "directory.") destination = self._remote_paths_split(remote_file) if destination is not None: sftp = self._make_sftp() if sftp is None else sftp try: self._eagain(sftp.stat, destination) except (SFTPHandleError, SFTPProtocolError): self.mkdir(sftp, destination) self._scp_send(local_file, remote_file) logger.info("SCP local file %s to remote destination %s:%s", local_file, self.host, remote_file) def _scp_send(self, local_file, remote_file): fileinfo = os.stat(local_file) try: chan = self._eagain( self.session.scp_send64, remote_file, fileinfo.st_mode & 0o777, fileinfo.st_size, fileinfo.st_mtime, fileinfo.st_atime) except Exception as ex: msg = "Error opening remote file %s for writing on host %s - %s" logger.error(msg, remote_file, self.host, ex) raise SCPError(msg, remote_file, self.host, ex) try: with open(local_file, 'rb', 2097152) as local_fh: for data in local_fh: eagain_write(chan.write, data, self.session) except Exception as ex: msg = "Error writing to remote file %s on host %s - %s" logger.error(msg, remote_file, self.host, ex) raise SCPError(msg, remote_file, self.host, ex) def _sftp_readdir(self, dir_h): for size, buf, attrs in dir_h.readdir(): for line in buf.splitlines(): yield line def _sftp_openfh(self, open_func, remote_file, *args): try: fh = open_func(remote_file, *args) except Exception as ex: raise SFTPError(ex) while fh == LIBSSH2_ERROR_EAGAIN: wait_select(self.session, timeout=0.1) try: fh = open_func(remote_file, *args) except Exception as ex: raise SFTPError(ex) return fh def _sftp_get(self, remote_fh, local_file): with open(local_file, 'wb') as local_fh: for size, data in remote_fh: if size == LIBSSH2_ERROR_EAGAIN: wait_select(self.session) continue local_fh.write(data) def sftp_get(self, sftp, remote_file, local_file): with self._sftp_openfh( sftp.open, remote_file, LIBSSH2_FXF_READ, LIBSSH2_SFTP_S_IRUSR) as remote_fh: try: self._sftp_get(remote_fh, local_file) # Running SFTP in a thread requires a new session # as session handles or any handles created by a session # cannot be used simultaneously in multiple threads. # THREAD_POOL.apply( # sftp_get, args=(self.session, remote_fh, local_file)) except SFTPProtocolError as ex: msg = "Error reading from remote file %s - %s" logger.error(msg, remote_file, ex) raise SFTPIOError(msg, remote_file, ex) def _copy_remote_dir(self, file_list, remote_dir, local_dir, sftp, encoding='utf-8'): for file_name in file_list: file_name = file_name.decode(encoding) if file_name in ('.', '..'): continue remote_path = os.path.join(remote_dir, file_name) local_path = os.path.join(local_dir, file_name) self.copy_remote_file(remote_path, local_path, sftp=sftp, recurse=True) def _make_local_dir(self, dirpath): if os.path.exists(dirpath): return try: os.makedirs(dirpath) except OSError: logger.error("Unable to create local directory structure for " "directory %s", dirpath) raise def _remote_paths_split(self, file_path): _sep = file_path.rfind('/') if _sep > 0: return file_path[:_sep] return