def check_ssh_up(host, port): """ Return True if SSH connectivity exists. First checks if port is open, then tries to see if it response to SSH connectivity. """ try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(2) try: s.connect((host, port)) except socket.error as e: if e.errno in (61,): return False else: raise else: # Basic connectivity works, try SSH t = Transport(s) # Shut up paramiko logging plog = logging.getLogger('paramiko.transport') plog.disabled = True try: t.start_client() return True except paramiko.SSHException as e: return False finally: t.close() s.close() plog.disabled = False except Exception as e: raise SshError('Error while checking %s:%d for SSH: %s' % (host, port, e))
class RepoWriteLock: def __init__(self, url): self.url = url self.transport = None self.client = None self.socket = socket() def __enter__(self): self.socket.connect((interpret_urlish(self.url)[1], 22)) self.transport = Transport(self.socket) self.transport.start_client() authenticate_transport(self.transport) self.client = self.transport.open_sftp_client() self.client.chdir(interpret_urlish(self.url)[2]) self._lock() def _lock(self): target_locks = self.client.listdir("locks") target_locks.sort() if target_locks: raise RuntimeError("repo is locked; try again later") else: self.client.mkdir("locks/write_lock") def _unlock(self): self.client.rmdir("locks/write_lock") def __exit__(self, *args): self._unlock() self.client.close() self.transport.close() self.socket.close()
def restore(path): dbinfo = choicedb(path+'/conf/db_info.yaml') editData(dbinfo, [['reset master;']]) if sys.platform == 'win32': t = Transport(dbinfo[0], 22) t.connect(username=dbinfo[5], password=dbinfo[6]) sftp = SFTPClient.from_transport(t) src = '/home/mysql/basedata/initdata.sql' des = path + '/database/initdata.sql' sftp.put(des,src ) t.close() else: child = spawn( 'scp '+path+'/database/initdata.sql '+ dbinfo[5]+'@'+dbinfo[0]+':/home/mysql/basedata/') child.expect("password:"******"'"+dbinfo[3]+"'"' '+dbinfo[4]+' </home/mysql/basedata/initdata.sql') return stderr.read().decode('gbk', errors='ignore')
def dbbackup(path): dbinfo = choicedb(path + '/conf/db_info.yaml') s = sshconnect(hostname=dbinfo[0], port=dbinfo[7], username=dbinfo[5], password=dbinfo[6]) st, std, stde = s.exec_command('cd /home/mysql/backup'+'\n' 'ls') filelist = std.read().decode('gbk',errors='ignore').split('\n') if 'databackup.sql' in filelist: s.exec_command('cd /home/mysql/backup'+'\n' 'rm -rf databackup1.sql') stdin, stdout, stderr = s.exec_command('mysqldump -t -u'+dbinfo[2]+' -p'+dbinfo[3]+' '+dbinfo[4]+' >/home/mysql/backup/databackup.sql') if 'error' not in stderr.read().decode('gbk', errors='ignore'): t1,t2,t3=s.exec_command('du -b /home/mysql/databackup.sql') if sys.platform == 'win32': t = Transport(dbinfo[0], 22) t.connect(username=dbinfo[5], password=dbinfo[6]) sftp = SFTPClient.from_transport(t) src = '/home/mysql/backup/databackup.sql' des = path + '/database/databackup.sql' sftp.get(src, des) t.close() else: child = spawn( 'scp ' + dbinfo[5] + '@' + dbinfo[0] + ':/home/mysql/backup/databackup.sql ' + path + '/database/') child.expect("password:") child.sendline(dbinfo[6]) child.read() with zipfile.ZipFile(path + '/database/backupdatabase.zip', 'w') as z: z.write(path + '/database/databackup.sql') return t2.read().decode('gbk',errors='ignore').split('\t')[0].strip() else: return False s.close
def fx_authorized_sftp(fx_sftpd, fx_authorized_keys): port, (thread, path, ev) = fx_sftpd.popitem() thread.start() key = RSAKey.generate(1024) dot_ssh = path.mkdir('.ssh') with dot_ssh.join('authorized_keys').open('w') as f: print(format_openssh_pubkey(key), file=f) for authorized_key in fx_authorized_keys: print(format_openssh_pubkey(authorized_key), file=f) transport = Transport(('127.0.0.1', port)) transport.connect(username='******', pkey=key) sftp_client = SFTPClient.from_transport(transport) yield sftp_client, path, [key] + fx_authorized_keys sftp_client.close() transport.close()
def authorize(public_keys: collections.abc.Set, master_key: PKey, remote: Remote, timeout: datetime.timedelta) -> datetime.datetime: """Make an one-time authorization to the ``remote``, and then revokes it when ``timeout`` reaches soon. :param public_keys: the set of public keys (:class:`paramiko.pkey.PKey`) to authorize :type public_keys: :class:`collections.abc.Set` :param master_key: the master key (*not owner's key*) :type master_key: :class:`paramiko.pkey.PKey` :param remote: a remote to grant access permission :type remote: :class:`~.remote.Remote` :param timeout: the time an authorization keeps alive :type timeout: :class:`datetime.timedelta` :return: the expiration time :rtype: :class:`datetime.datetime` """ transport = Transport((remote.host, remote.port)) transport.connect(username=remote.user, pkey=master_key) try: sftp_client = SFTPClient.from_transport(transport) try: authorized_keys = AuthorizedKeyList(sftp_client) authorized_keys.extend(public_keys) except: sftp_client.close() raise except: transport.close() raise def rollback(): time.sleep(timeout.total_seconds()) authorized_keys[:] = [master_key] sftp_client.close() transport.close() timer = threading.Thread(target=rollback) expires_at = datetime.datetime.now(datetime.timezone.utc) + timeout timer.start() return expires_at
def get_host_key(host, port=22): logger.debug("Connecting to host %s to get ssh public host key" % host) INTERVAL = 15 MAX_RETRY = 60 / INTERVAL * 5 c = 0 while 1: try: sock = create_connection((host, port)) transport = Transport(sock) transport.start_client() key = transport.get_remote_server_key() transport.close() break except error, e: if type(e) is timeout: log = logger.warn else: log = logger.error log('socket %s: errno=%r, error msg=%s for server %s' % (e.__class__.__name__, e.errno, e.strerror, host)) except SSHException, e: logger.exception("attempt %s - error while attempting to connect to %s" % (c, host))
def sftp_push_file(host, user, password, to_, from_): """ 上传文件,注意:不支持文件夹 :param host: 主机名 :param user: 用户名 :param password: 密码 :param from_: 远程路径,比如:/home/sdn/tmp.txt :param to_: 本地路径,比如:D:/text.txt :param timeout: 超时时间(默认),必须是int类型 :return: bool """ logging.debug('SSH FILE PUSH') try: t = Transport((host, 22)) t.connect(username=user, password=password) sftp = paramiko.SFTPClient.from_transport(t) sftp.put(to_, from_) t.close() logging.info('SSH FILE PUSH SUCCESS') return True except Exception as e: logging.error(str(type(e)) + ' ' + e.strerror) logging.error('SSH FILE PUSH FAIL') return False
def get_host_keys(address, port=22, types=None): if types is None: types = Transport._preferred_keys af, sock_type, proto, name, addr = socket.getaddrinfo( address, port, 0,0, socket.IPPROTO_TCP)[0] keys = [] for key_type in types: try: sock = socket.socket(af, sock_type, proto) sock.connect(addr) t = Transport(sock) t.get_security_options().key_types = [key_type] t.start_client() keys.append(t.get_remote_server_key()) except Exception: pass finally: t.close() sock.close() return keys
def checkUsername(self, username, tried=0): sock = socket.socket() sock.connect((self.hostname, self.port)) # instantiate transport transport = Transport(sock) try: transport.start_client() except paramiko.ssh_exception.SSHException: # server was likely flooded, retry up to 3 times transport.close() if tried < 4: tried += 1 return self.checkUsername(username, tried) else: print("[-] Failed to negotiate SSH transport") try: transport.auth_publickey(username, paramiko.RSAKey.generate(1024)) except BadUsername: return (username, False) except paramiko.ssh_exception.AuthenticationException: return (username, True) #Successful auth(?) raise Exception( "There was an error. Is this the correct version of OpenSSH?")
class Repository: def __init__(self, url): self.url = url self.index = {} self.read_lock = RepoReadLock(url) self.write_lock = RepoWriteLock(url) self.client = None self.transport = None self.socket = socket() self.opened = False def open(self): """ Opens the connection """ self.socket.connect((interpret_urlish(self.url)[1], 22)) self.transport = Transport(self.socket) self.transport.start_client() authenticate_transport(self.transport) self.client = self.transport.open_sftp_client() target_path = interpret_urlish(self.url)[2] try: self.client.stat(target_path) except IOError: self.client.mkdir(target_path) self.client.chdir(target_path) self.opened = True def close(self): """ Closes the connection """ if not self.opened: return self.client.close() self.transport.close() self.socket.close() self.opened = False def update(self): """ Update the information in this class to match that of the remote. Raises exceptions if remote is invalid or in an invalid state """ if not self.opened: self.open() with self.read_lock: with self.client.open("index.json") as f: self.index = json.load(f) def get_script(self, hname=None): """ Get the script object """ if hname is None: hname = self.index["start"] return self.index["scripts"][hname] def download_script(self, hname=None): if hname is None: hname = self.index["start"] with self.read_lock: with self.client.open("scripts/" + hname + ".py", "r") as f: return f.read() def get_revision(self): return self.index["revision"] def append_script(self, script_obj, script_contents): h = sha512() h.update(script_contents.encode("utf-7")) hname = h.hexdigest() script_obj["prev"] = self.index["end"] with self.write_lock: self.index["revision"] += 1 if self.index["end"]: self.index["scripts"][self.index["end"]]["next"] = hname self.index["end"] = hname self.index["scripts"][hname] = script_obj if self.index["start"] == "": self.index["start"] = hname self._write() with self.client.open("scripts/" + hname + ".py", "w") as f: f.write(script_contents) def _write(self): with self.client.open("index.json", "w") as f: json.dump(self.index, f) def write(self): with self.write_lock: self._write() def __iter__(self): return FollowChainIterator(self, self.index["start"]) def iterate_from(self, pos): return FollowChainIterator(self, pos) def new(self): if not self.opened: self.open() try: self.client.stat("index.json") raise RuntimeError( "already init-ed, manually delete the folder to re-init") except IOError: pass # create the skeleton fs self.client.mkdir("locks") self.client.mkdir("scripts") # create a basic index.json self.index = { "version": 1, "revision": 0, "start": "", "end": "", "scripts": {} } self.write()
class Communicator(drm4g.communicators.Communicator): """ Create a SSH session to remote resources. """ _lock = __import__('threading').Lock() _sem = __import__('threading').Semaphore(SFTP_CONNECTIONS) _trans = None def connect(self): try: with self._lock: if not self._trans or not self._trans.is_authenticated(): logger.debug("Opening ssh connection ... ") keys = None logger.debug("Trying ssh-agent ... ") drm4g_agent = drm4g.commands.Agent() drm4g_agent.start() drm4g_agent.update_agent_env() # paramiko agent agent = Agent() keys = agent.get_keys() if not keys: logger.debug("Error trying to connect to '%s'" % self.frontend) logger.debug( "Impossible to load '%s' key from the ssh-agent" % self.private_key) try: status_ssh_agent = agent._conn except Exception as err: logger.warning( "Probably you are using paramiko version <= 1.7.7.2 : %s " % err) status_ssh_agent = agent.conn if not status_ssh_agent: logger.warning("'ssh-agent' is not running") else: if agent.get_keys(): logger.warning( "ssh-agent is running but none of the keys have been accepted" "by remote frontend %s." % self.frontend) else: logger.debug( "'ssh-agent' is running but without any keys" ) if self.private_key: logger.debug("Trying '%s' key ... " % self.private_key) private_key_path = expanduser(self.private_key) if (not exists(private_key_path)) and ( not 'PRIVATE KEY' in self.private_key): output = "'%s'key does not exist" % private_key_path raise ComException(output) for pkey_class in (RSAKey, DSSKey): try: if 'PRIVATE KEY' in self.private_key: import StringIO key = pkey_class.from_private_key( StringIO.StringIO( self.private_key.strip("'"))) else: key = pkey_class.from_private_key_file( private_key_path) keys = keys + (key, ) except Exception: pass if not keys: output = "Impossible to load any keys" logger.error(output) raise ComException(output) for key in keys: try: sock = socket.socket() try: sock.settimeout(SSH_CONNECT_TIMEOUT) except: output = "Timeout trying to connect to '%s'" % self.frontend raise ComException(output) logger.debug( "Connecting to '%s' as user '%s' port '%s' ..." % (self.frontend, self.username, self.port)) if ':' in self.frontend: self.frontend, self.port = self.frontend.split( ':') sock.connect((self.frontend, self.port)) self._trans = Transport(sock) self._trans.connect(username=self.username, pkey=key) if self._trans.is_authenticated(): break except socket.gaierror: output = "Could not resolve hostname '%s' " % self.frontend raise ComException(output) except Exception as err: logger.warning("Error connecting '%s': %s" % (self.frontend, str(err))) if not self._trans: output = "Authentication failed for '%s'. Try to execute `ssh -vvv -p %d %s@%s` and see the response." % ( self.frontend, self.port, self.username, self.frontend) raise ComException(output) except ComException: raise except Exception as err: if "No handlers could be found for logger" in str(err): raise Exception( "The connect function is the one causing problems : %s" % str(err)) else: raise def execCommand(self, command, input=None): self.connect() with self._lock: channel = self._trans.open_session() channel.settimeout(SSH_CONNECT_TIMEOUT) channel.exec_command(command) if input: for line in input.split(): channel.makefile('wb', -1).write('%s\n' % line) channel.makefile('wb', -1).flush() stdout = ''.join(channel.makefile('rb', -1).readlines()) stderr = ''.join(channel.makefile_stderr('rb', -1).readlines()) if channel: channel.close() return stdout, stderr def mkDirectory(self, url): to_dir = self._set_dir(urlparse(url).path) stdout, stderr = self.execCommand("mkdir -p %s" % to_dir) if stderr: raise ComException("Could not create %s directory on '%s': %s" % (to_dir, self.frontend, stderr)) def rmDirectory(self, url): to_dir = self._set_dir(urlparse(url).path) stdout, stderr = self.execCommand("rm -rf %s" % to_dir) if stderr: raise ComException("Could not remove %s directory on '%s': %s" % (to_dir, self.frontend, stderr)) def copy(self, source_url, destination_url, execution_mode=''): with self._sem: self.connect() scp = SCPClient(self._trans) if 'file://' in source_url: from_dir = urlparse(source_url).path to_dir = self._set_dir(urlparse(destination_url).path) scp.put(from_dir, to_dir) if execution_mode == 'X': stdout, stderr = self.execCommand("chmod +x %s" % to_dir) else: from_dir = self._set_dir(urlparse(source_url).path) to_dir = urlparse(destination_url).path logger.warning("%s , %s" % (from_dir, to_dir)) scp.get(from_dir, to_dir) def close(self): try: if self._trans: self._trans.close() except Exception as err: logger.warning("Could not close the SSH connection to '%s': %s" % (self.frontend, str(err))) def __del__(self): """ Attempt to clean up if not explicitly closed. """ self.close() #internal def _set_dir(self, path): work_directory = re.compile(r'^~').sub(self.work_directory, path) if work_directory[0] == r'~': return ".%s" % work_directory[1:] else: return work_directory
## Let's make an ssh tunnel if we find it in profiles.config from mr_utils.config import ProfileConfig from paramiko.transport import Transport import socket if __name__ == '__main__': profile = ProfileConfig() ssh_host = profile.get_config_val('ssh.host') ssh_user = profile.get_config_val('ssh.user') host = profile.get_config_val('gadgetron.host') port = profile.get_config_val('gadgetron.port') print(ssh_host, ssh_user) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ssh_host, 22)) transport = Transport(sock) transport.connect(username=ssh_user, password=None) chan = transport.open_channel('session', dest_addr=(host, port)) print(chan) chan.close() transport.close() sock.close()