Exemple #1
0
class WebTerminalHandler(tornado.websocket.WebSocketHandler):
    clients = []
    tasks = []

    def __init__(self, *args, **kwargs):
        self.term = None
        self.log_file_f = None
        self.log_time_f = None
        self.log = None
        self.id = 0
        self.user = None
        self.ssh = None
        self.channel = None
        super(WebTerminalHandler, self).__init__(*args, **kwargs)

    def check_origin(self, origin):
        return True

    @django_request_support
    @require_auth('user')
    def open(self):
        logger.debug('Websocket: Open request')
        role_name = self.get_argument('role', 'sb')
        asset_id = self.get_argument('id', 9999)
        asset = get_object(Asset, id=asset_id)
        self.termlog = TermLogRecorder(User.objects.get(id=self.user_id))
        if asset:
            roles = user_have_perm(self.user, asset)
            logger.debug(roles)
            logger.debug('系统用户: %s' % role_name)
            login_role = ''
            for role in roles:
                if role.name == role_name:
                    login_role = role
                    break
            if not login_role:
                logger.warning(
                    'Websocket: Not that Role %s for Host: %s User: %s ' %
                    (role_name, asset.hostname, self.user.username))
                self.close()
                return
        else:
            logger.warning('Websocket: No that Host: %s User: %s ' %
                           (asset_id, self.user.username))
            self.close()
            return
        logger.debug(
            'Websocket: request web terminal Host: %s User: %s Role: %s' %
            (asset.hostname, self.user.username, login_role.name))
        self.term = WebTty(self.user, asset, login_role, login_type='web')
        # self.term.remote_ip = self.request.remote_ip
        self.term.remote_ip = self.request.headers.get("X-Real-IP")
        if not self.term.remote_ip:
            self.term.remote_ip = self.request.remote_ip
        self.ssh = self.term.get_connection()
        self.channel = self.ssh.invoke_shell(term='xterm')
        WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound))
        WebTerminalHandler.clients.append(self)

        for t in WebTerminalHandler.tasks:
            if t.is_alive():
                continue
            try:
                t.setDaemon(True)
                t.start()
            except RuntimeError:
                pass

    def on_message(self, message):
        jsondata = json.loads(message)
        if not jsondata:
            return

        if 'resize' in jsondata.get('data'):
            self.termlog.write(message)
            self.channel.resize_pty(
                width=int(jsondata.get('data').get('resize').get('cols', 100)),
                height=int(jsondata.get('data').get('resize').get('rows', 35)))
        elif jsondata.get('data'):
            self.termlog.recoder = True
            self.term.input_mode = True
            if str(jsondata['data']) in ['\r', '\n', '\r\n']:
                match = re.compile(r'\x1b\[\?1049',
                                   re.X).findall(self.term.vim_data)
                if match:
                    if self.term.vim_flag or len(match) == 2:
                        self.term.vim_flag = False
                    else:
                        self.term.vim_flag = True
                elif not self.term.vim_flag:
                    result = self.term.deal_command(self.term.data)[0:200]
                    if len(result) > 0:
                        TtyLog(log=self.log,
                               datetime=datetime.datetime.now(),
                               cmd=result).save()
                self.term.vim_data = ''
                self.term.data = ''
                self.term.input_mode = False
            self.channel.send(jsondata['data'])
        else:
            pass

    def on_close(self):
        logger.debug('Websocket: Close request')
        print self.termlog.CMD
        self.termlog.save()
        if self in WebTerminalHandler.clients:
            WebTerminalHandler.clients.remove(self)
        try:
            self.log_file_f.write('End time is %s' % datetime.datetime.now())
            self.log.is_finished = True
            self.log.end_time = datetime.datetime.now()
            self.log.filename = self.termlog.filename
            self.log.save()
            self.log_time_f.close()
            self.ssh.close()
            self.close()
        except AttributeError:
            pass

    def forward_outbound(self):
        self.log_file_f, self.log_time_f, self.log = self.term.get_log()
        self.id = self.log.id
        self.termlog.setid(self.id)
        try:
            data = ''
            pre_timestamp = time.time()
            while True:
                r, w, e = select.select([self.channel], [], [])
                if self.channel in r:
                    recv = self.channel.recv(1024)
                    if not len(recv):
                        return
                    data += recv
                    self.term.vim_data += recv
                    try:
                        self.write_message(data.decode('utf-8', 'replace'))
                        self.termlog.write(data)
                        self.termlog.recoder = False
                        now_timestamp = time.time()
                        self.log_time_f.write('%s %s\n' % (round(
                            now_timestamp - pre_timestamp, 4), len(data)))
                        self.log_file_f.write(data)
                        pre_timestamp = now_timestamp
                        self.log_file_f.flush()
                        self.log_time_f.flush()
                        if self.term.input_mode:
                            self.term.data += data
                        data = ''
                    except UnicodeDecodeError:
                        pass
        except IndexError:
            pass
Exemple #2
0
    def posix_shell(self):
        """
        Use paramiko channel connect server interactive.
        使用paramiko模块的channel,连接后端,进入交互式
        """
        log_file_f, log_time_f, log = self.get_log()
        termlog = TermLogRecorder(User.objects.get(id=self.user.id))
        termlog.setid(log.id)
        old_tty = termios.tcgetattr(sys.stdin)
        pre_timestamp = time.time()
        data = ''
        input_mode = False
        try:
            tty.setraw(sys.stdin.fileno())
            tty.setcbreak(sys.stdin.fileno())
            self.channel.settimeout(0.0)

            while True:
                try:
                    r, w, e = select.select([self.channel, sys.stdin], [], [])
                    flag = fcntl.fcntl(sys.stdin, fcntl.F_GETFL, 0)
                    fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL,
                                flag | os.O_NONBLOCK)
                except Exception:
                    pass

                if self.channel in r:
                    try:
                        x = self.channel.recv(10240)
                        if len(x) == 0:
                            break

                        index = 0
                        len_x = len(x)
                        while index < len_x:
                            try:
                                n = os.write(sys.stdout.fileno(), x[index:])
                                sys.stdout.flush()
                                index += n
                            except OSError as msg:
                                if msg.errno == errno.EAGAIN:
                                    continue
                        now_timestamp = time.time()
                        termlog.write(x)
                        termlog.recoder = False
                        log_time_f.write(
                            '%s %s\n' %
                            (round(now_timestamp - pre_timestamp, 4), len(x)))
                        log_time_f.flush()
                        log_file_f.write(x)
                        log_file_f.flush()
                        pre_timestamp = now_timestamp
                        log_file_f.flush()

                        self.vim_data += x
                        if input_mode:
                            data += x

                    except socket.timeout:
                        pass

                if sys.stdin in r:
                    try:
                        x = os.read(sys.stdin.fileno(), 4096)
                    except OSError:
                        pass
                    termlog.recoder = True
                    input_mode = True
                    if self.is_output(str(x)):
                        # 如果len(str(x)) > 1 说明是复制输入的
                        if len(str(x)) > 1:
                            data = x
                        match = self.vim_end_pattern.findall(self.vim_data)
                        if match:
                            if self.vim_flag or len(match) == 2:
                                self.vim_flag = False
                            else:
                                self.vim_flag = True
                        elif not self.vim_flag:
                            self.vim_flag = False
                            data = self.deal_command(data)[0:200]
                            if data is not None:
                                TtyLog(log=log,
                                       datetime=datetime.datetime.now(),
                                       cmd=data).save()
                        data = ''
                        self.vim_data = ''
                        input_mode = False

                    if len(x) == 0:
                        break
                    self.channel.send(x)

        finally:
            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
            log_file_f.write('End time is %s' % datetime.datetime.now())
            log_file_f.close()
            log_time_f.close()
            termlog.save()
            log.filename = termlog.filename
            log.is_finished = True
            log.end_time = datetime.datetime.now()
            log.save()
Exemple #3
0
class WebTerminalHandler(tornado.websocket.WebSocketHandler):
    clients = []
    tasks = []

    def __init__(self, *args, **kwargs):
        self.term = None
        self.log_file_f = None
        self.log_time_f = None
        self.log = None
        self.id = 0
        self.user = None
        self.ssh = None
        self.channel = None
        super(WebTerminalHandler, self).__init__(*args, **kwargs)

    def check_origin(self, origin):
        return True

    @django_request_support
    @require_auth('user')
    def open(self):
        logger.debug('Websocket: Open request')
        role_name = self.get_argument('role', 'sb')
        asset_id = self.get_argument('id', 9999)
        asset = get_object(Asset, id=asset_id)
        self.termlog = TermLogRecorder(User.objects.get(id=self.user_id))
        if asset:
            roles = user_have_perm(self.user, asset)
            logger.debug(roles)
            logger.debug('系统用户: %s' % role_name)
            login_role = ''
            for role in roles:
                if role.name == role_name:
                    login_role = role
                    break
            if not login_role:
                logger.warning('Websocket: Not that Role %s for Host: %s User: %s ' % (role_name, asset.hostname,
                                                                                       self.user.username))
                self.close()
                return
        else:
            logger.warning('Websocket: No that Host: %s User: %s ' % (asset_id, self.user.username))
            self.close()
            return
        logger.debug('Websocket: request web terminal Host: %s User: %s Role: %s' % (asset.hostname, self.user.username,
                                                                                     login_role.name))
        self.term = WebTty(self.user, asset, login_role, login_type='web')
        # self.term.remote_ip = self.request.remote_ip
        self.term.remote_ip = self.request.headers.get("X-Real-IP")
        if not self.term.remote_ip:
            self.term.remote_ip = self.request.remote_ip
        self.ssh = self.term.get_connection()
        self.channel = self.ssh.invoke_shell(term='xterm')
        WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound))
        WebTerminalHandler.clients.append(self)

        for t in WebTerminalHandler.tasks:
            if t.is_alive():
                continue
            try:
                t.setDaemon(True)
                t.start()
            except RuntimeError:
                pass

    def on_message(self, message):
        jsondata = json.loads(message)
        if not jsondata:
            return

        if 'resize' in jsondata.get('data'):
            self.termlog.write(message)
            self.channel.resize_pty(
                width=int(jsondata.get('data').get('resize').get('cols', 100)),
                height=int(jsondata.get('data').get('resize').get('rows', 35))
            )
        elif jsondata.get('data'):
            self.termlog.recoder = True
            self.term.input_mode = True
            if str(jsondata['data']) in ['\r', '\n', '\r\n']:
                match = re.compile(r'\x1b\[\?1049', re.X).findall(self.term.vim_data)
                if match:
                    if self.term.vim_flag or len(match) == 2:
                        self.term.vim_flag = False
                    else:
                        self.term.vim_flag = True
                elif not self.term.vim_flag:
                    result = self.term.deal_command(self.term.data)[0:200]
                    if len(result) > 0:
                        TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=result).save()
                self.term.vim_data = ''
                self.term.data = ''
                self.term.input_mode = False
            self.channel.send(jsondata['data'])
        else:
            pass

    def on_close(self):
        logger.debug('Websocket: Close request')
        print self.termlog.CMD
        self.termlog.save()
        if self in WebTerminalHandler.clients:
            WebTerminalHandler.clients.remove(self)
        try:
            self.log_file_f.write('End time is %s' % datetime.datetime.now())
            self.log.is_finished = True
            self.log.end_time = datetime.datetime.now()
            self.log.filename = self.termlog.filename
            self.log.save()
            self.log_time_f.close()
            self.ssh.close()
            self.close()
        except AttributeError:
            pass

    def forward_outbound(self):
        self.log_file_f, self.log_time_f, self.log = self.term.get_log()
        self.id = self.log.id
        self.termlog.setid(self.id)
        try:
            data = ''
            pre_timestamp = time.time()
            while True:
                r, w, e = select.select([self.channel], [], [])
                if self.channel in r:
                    recv = self.channel.recv(1024)
                    if not len(recv):
                        return
                    data += recv
                    self.term.vim_data += recv
                    try:
                        self.write_message(data.decode('utf-8', 'replace'))
                        self.termlog.write(data)
                        self.termlog.recoder = False
                        now_timestamp = time.time()
                        self.log_time_f.write('%s %s\n' % (round(now_timestamp - pre_timestamp, 4), len(data)))
                        self.log_file_f.write(data)
                        pre_timestamp = now_timestamp
                        self.log_file_f.flush()
                        self.log_time_f.flush()
                        if self.term.input_mode:
                            self.term.data += data
                        data = ''
                    except UnicodeDecodeError:
                        pass
        except IndexError:
            pass
Exemple #4
0
    def posix_shell(self):
        """
        Use paramiko channel connect server interactive.
        使用paramiko模块的channel,连接后端,进入交互式
        """
        log_file_f, log_time_f, log = self.get_log()
        termlog = TermLogRecorder(User.objects.get(id=self.user.id))
        termlog.setid(log.id)
        old_tty = termios.tcgetattr(sys.stdin)
        pre_timestamp = time.time()
        data = ''
        input_str = ''
        input_mode = False
        try:
            tty.setraw(sys.stdin.fileno())
            tty.setcbreak(sys.stdin.fileno())
            self.channel.settimeout(0.0)

            while True:
                try:
                    r, w, e = select.select([self.channel, sys.stdin], [], [])
                    flag = fcntl.fcntl(sys.stdin, fcntl.F_GETFL, 0)
                    fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, flag|os.O_NONBLOCK)
                except Exception:
                    pass

                if self.channel in r:
                    try:
                        x = self.channel.recv(10240)
                        if len(x) == 0:
                            break
                        if self.vim_flag:
                            self.vim_data += x
                        index = 0
                        len_x = len(x)
                        while index < len_x:
                            try:
                                n = os.write(sys.stdout.fileno(), x[index:])
                                sys.stdout.flush()
                                index += n
                            except OSError as msg:
                                if msg.errno == errno.EAGAIN:
                                    continue
                        now_timestamp = time.time()
                        termlog.write(x)
                        termlog.recoder = False
                        log_time_f.write('%s %s\n' % (round(now_timestamp-pre_timestamp, 4), len(x)))
                        log_time_f.flush()
                        log_file_f.write(x)
                        log_file_f.flush()
                        pre_timestamp = now_timestamp
                        log_file_f.flush()

                        if input_mode and not self.is_output(x):
                            data += x

                        input_str = ''

                    except socket.timeout:
                        pass

                if sys.stdin in r:
                    try:
                        x = os.read(sys.stdin.fileno(), 4096)
                    except OSError:
                        pass
                    termlog.recoder = True
                    input_mode = True
                    input_str += x
                    if str(x) in ['\r', '\n', '\r\n']:
                        # 这个是用来处理用户的复制操作
                        if input_str != x:
                            data += input_str
                        if self.vim_flag:
                            match = self.vim_end_pattern.findall(self.vim_data)
                            if match:
                                if self.vim_end_flag or len(match) == 2:
                                    self.vim_flag = False
                                    self.vim_end_flag = False
                                else:
                                    self.vim_end_flag = True
                        else:
                            data = self.deal_command(data)[0:200]
                            if len(data) > 0:
                                TtyLog(log=log, datetime=datetime.datetime.now(), cmd=data).save()
                        data = ''
                        input_str = ''
                        self.vim_data = ''
                        input_mode = False

                    if len(x) == 0:
                        break
                    self.channel.send(x)

        finally:
            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
            log_file_f.write('End time is %s' % datetime.datetime.now())
            log_file_f.close()
            log_time_f.close()
            termlog.save()
            log.filename = termlog.filename
            log.is_finished = True
            log.end_time = datetime.datetime.now()
            log.save()
Exemple #5
0
        def start_shell():
            global q
            """
            Use paramiko channel connect server interactive.
            使用paramiko模块的channel,连接后端,进入交互式
            """
            log_file_f, log_time_f, log = self.get_log()
            termlog = TermLogRecorder(self.user)
            termlog.setid(log.id)
            old_tty = termios.tcgetattr(sys.stdin)
            pre_timestamp = time.time()
            data = ''
            input_mode = False
            try:
                tty.setraw(sys.stdin.fileno())
                tty.setcbreak(sys.stdin.fileno())
                self.channel.settimeout(0.0)

                cache_line = ""

                RECORD_CMD_FLAG = True
                while True:
                    try:
                        r, w, e = select.select([self.channel, sys.stdin], [],
                                                [])
                        flag = fcntl.fcntl(sys.stdin, fcntl.F_GETFL, 0)
                        fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL,
                                    flag | os.O_NONBLOCK)
                    except Exception:
                        pass

                    if self.channel in r:
                        try:
                            y = self.channel.recv(10240)
                            if len(y) == 0:
                                break

                            index = 0
                            len_y = len(y)
                            f = open(RECORD_PATH, "a+")
                            while index < len_y:
                                try:
                                    n = os.write(sys.stdout.fileno(),
                                                 y[index:])
                                    if self.role == "rd" and RECORD_CMD_FLAG:
                                        f.write(y[index:])
                                    sys.stdout.flush()
                                    index += n
                                except OSError as msg:
                                    if msg.errno == errno.EAGAIN:
                                        continue
                            f.close()
                            now_timestamp = time.time()
                            termlog.write(y)
                            termlog.recoder = False
                            log_time_f.write('%s %s\n' % (round(
                                now_timestamp - pre_timestamp, 4), len(y)))
                            log_time_f.flush()
                            log_file_f.write(y)
                            log_file_f.flush()
                            pre_timestamp = now_timestamp
                            log_file_f.flush()

                            self.vim_data += y
                            if input_mode:
                                data += y

                        except socket.timeout:
                            pass

                    if sys.stdin in r:
                        RECORD_CMD_FLAG = True
                        try:
                            x = os.read(sys.stdin.fileno(), 4096)
                            q.put(x)
                        except OSError:
                            pass
                        termlog.recoder = True
                        input_mode = True
                        if self.is_output(str(x)):
                            # 如果len(str(x)) > 1 说明是复制输入的
                            if len(str(x)) > 1:
                                data = x
                            match = self.vim_end_pattern.findall(self.vim_data)
                            if match:
                                if self.vim_flag or len(match) == 2:
                                    self.vim_flag = False
                                else:
                                    self.vim_flag = True
                            elif not self.vim_flag:
                                self.vim_flag = False
                                data = self.deal_command(data)[0:200]
                                if data is not None:
                                    TtyLog(log=log,
                                           datetime=datetime.datetime.now(),
                                           cmd=data).save()
                            data = ''
                            self.vim_data = ''
                            input_mode = False

                        if len(x) == 0:
                            break

                        if x in ['\x03', '\r\n', '\n', '\x0D']:
                            f = open(RECORD_PATH, "r")
                            lines = f.readlines()
                            cmd = ""
                            if lines:
                                cmd = lines[-1]
                            f.close()
                            f = open(RECORD_PATH, "w")
                            f.close()
                            cmds_str = re.compile('\[?.*@.*\]?[\$#]\s').split(
                                cmd)
                            logger.info("get command from log file is: %s",
                                        cmds_str)
                            if len(cmds_str) == 2:
                                cmds = cmds_str[1]
                                logger.info("command >>>: %s", cmds.split("|"))
                                cmd = set([
                                    i.split()[0].strip()
                                    for i in cmds.split("|") if i.split()
                                ])
                                logger.info("command set>>>: %s", cmd)
                                if self.role == "rd" and not ALLOW_CMD.issuperset(
                                        cmd):
                                    x = '\x03'
                                if "tail" in cmd or "cat" in cmd:
                                    RECORD_CMD_FLAG = False
                            else:
                                RECORD_CMD_FLAG = True
                            cache_line = ""
                        self.channel.send(x)

                        if self.kill_shell:
                            break

            finally:
                termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
                log_file_f.write('End time is %s' % datetime.datetime.now())
                log_file_f.close()
                log_time_f.close()
                termlog.save()
                log.filename = termlog.filename
                log.is_finished = True
                log.end_time = datetime.datetime.now()
                log.save()
                if os.path.isfile(RECORD_PATH):
                    os.remove(RECORD_PATH)
                sys.exit(0)