Paramiko服务器控制台在客户端上冻结

时间:2018-08-13 22:19:26

标签: python server paramiko asyncore

我已经对返回外壳程序的Paramiko SSH服务器进行了概念验证。欢迎消息将打印在SSH客户端(使用macos终端SSH客户端)上,并在提示符上显示。然后客户端似乎冻结了,但是Paramiko服务器线程似乎可以正常工作。

import paramiko

from io import BytesIO

import asyncore
import socket
import threading
import logging
import sys
import cmd


LISTEN_BACKLOG = 20

class whatever:
    SSH_HANDLERS = {}
    SSH_BIND = ('localhost', 22)
    SSH_SERVER_KEY = """\
-----BEGIN RSA PRIVATE KEY-----
<Private RSA key goes here>
-----END RSA PRIVATE KEY-----"""


settings = whatever()


class Shell(cmd.Cmd, threading.Thread):
    use_rawinput = 0
    intro = 'Welcome to the server!'

    def __init__(self, channel):
        stdin = channel.makefile('r')
        stdout = channel.makefile('w')
        self.__channel = channel

        threading.Thread.__init__(self, name='shell')
        cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout)

    def run(self):
        self.preloop()
        try:
            if self.intro:
                self.stdout.write(str(self.intro)+'\r\n')
            stop = None
            while not stop and not self.__channel.exit_status_ready():
                if self.cmdqueue:
                    line = self.cmdqueue.pop(0)
                else:
                    if self.use_rawinput:
                        try:
                            line = raw_input(self.prompt)
                        except EOFError:
                            line = 'EOF'
                    else:
                        self.stdout.write(self.prompt)
                        self.stdout.flush()
                        line = self.stdin.readline()
                        if not len(line):
                            line = 'EOF'
                        else:
                            line = line.rstrip('\r\n')
                line = self.precmd(line)
                stop = self.onecmd(line)
                stop = self.postcmd(stop, line)
            self.postloop()
        finally:
            pass


class SSHServer(paramiko.ServerInterface):
    def __init__(self):
        paramiko.ServerInterface.__init__(self)
        self._message = None

    def get_allowed_auths(self, username):
        return 'publickey'

    def check_auth_publickey(self, username, key):
        return paramiko.AUTH_SUCCESSFUL

    def check_channel_request(self, kind, chanid):
        if kind == 'session':
            return paramiko.OPEN_SUCCEEDED
        return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED

    def check_channel_shell_request(self, channel):
        print 'check_channel_shell_request: {:}'.format(channel)
        Shell(channel).start()
        return True

    def check_channel_pty_request(self, channel, term, width, height, pixelwidth, pixelheight, modes):
        return True


class SSHDispatcher(asyncore.dispatcher):
    def __init__(self, server_key):
        asyncore.dispatcher.__init__(self)
        self._server_key = server_key

        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(settings.SSH_BIND)
        self.listen(LISTEN_BACKLOG)

    def handle_accepted(self, conn, addr):
        t = paramiko.Transport(conn)
        t.add_server_key(self._server_key)
        t.start_server(event=threading.Event(), server=SSHServer())

    # python<3.2 compat
    def handle_accept(self):
        ret = self.accept()
        if ret is not None:
            self.handle_accepted(*ret)


logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logging.getLogger("paramiko").setLevel(logging.DEBUG)
server_key = paramiko.RSAKey(file_obj=BytesIO(settings.SSH_SERVER_KEY))

SSHDispatcher(server_key)
asyncore.loop()
raise SystemError('SSH server loop exited')

这两个网站启发了我: https://github.com/simon-engledew/sshim/blob/master/sshim/Server.py http://nullege.com/codes/show/src@i@d@identity.gentoo.orgHEAD@okupy@common@ssh.py/100/paramiko.Transport.start_server

我想做的是通过SSH访问自定义控制台外壳程序。我实现的服务器成功生成并连接了从cmd.CMD继承的Shell类。通过标准SSH客户端从我的终端连接到该服务器,我可以看到终端提示。

Welcome to the server!
(Cmd)

但是我无法在SSH客户端上进行交互,它已冻结。该问题与从套接字line = self.stdin.readline()读取有关。我以前尝试使用raw_input line = raw_input(self.prompt)进行读取,然后出现的问题是我可以在Server终端上编写命令,并在Client终端上输出命令。

如何使SSH客户端能够与服务器上的Shell交互?

0 个答案:

没有答案