diff --git a/connect.py b/connect.py index 5559612c1..930452a36 100644 --- a/connect.py +++ b/connect.py @@ -13,16 +13,19 @@ import textwrap import getpass import readline import django -from multiprocessing import Pool import paramiko -import struct, fcntl, signal, socket, select, fnmatch +import struct, fcntl, signal, socket, select os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings' if django.get_version() != '1.6': django.setup() from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object -from jumpserver.api import logger, is_dir, Log, TtyLog -from jumpserver.settings import log_dir +from jumpserver.api import logger, mkdir, Log, TtyLog +from jumpserver.settings import LOG_DIR + + +login_user = get_object(User, username=getpass.getuser()) + try: import termios @@ -32,11 +35,6 @@ except ImportError: time.sleep(3) sys.exit() -VIM_FLAG = False -VIM_COMMAND = '' -SSH_TTY = '' -login_user = get_object(User, username=getpass.getuser()) - def color_print(msg, color='red', exits=False): """ @@ -53,49 +51,6 @@ def color_print(msg, color='red', exits=False): sys.exit() -def verify_connect(user, option): - """ - Check user was permed or not . Check ip is unique or not. - 鉴定用户是否有该主机权限 或 匹配到的ip是否唯一 - """ - ip_matched = [] - try: - assets_info = login_user.get_asset_info() - except ServerError, e: - color_print(e, 'red') - return False - - for ip, asset_info in assets_info.items(): - if option in asset_info[1:] and option: - ip_matched = [asset_info[1]] - break - - for info in asset_info[1:]: - if option in info: - ip_matched.append(ip) - - logger.debug('%s matched input %s: %s' % (login_user.username, option, ip_matched)) - ip_matched = list(set(ip_matched)) - - if len(ip_matched) > 1: # 如果匹配ip不唯一 - ip_comment = {} - for ip in ip_matched: - ip_comment[ip] = assets_info[ip][2] - - for ip in sorted(ip_comment): - if ip_comment[ip]: - print '%-15s -- %s' % (ip, ip_comment[ip]) - else: - print '%-15s' % ip - print '' - elif len(ip_matched) < 1: # 如果没匹配到 - color_print('没有该主机,或者您没有该主机的权限 No Permission or No host.', 'red') - else: # 恰好是1个 - asset = get_object(Asset, ip=ip_matched[0]) - jtty = Jtty(user, asset) - jtty.connect() - - def check_vim_status(command, ssh): global SSH_TTY print command @@ -194,7 +149,7 @@ def deal_command(str_r, ssh): else : result_command += str_r[0] str_r = str_r[1:] - + if pattern_str !='': pattern_list.append(pattern_str) @@ -207,8 +162,7 @@ def deal_command(str_r, ssh): result_command = result_command[:-int(backspace)] result_command += pattern_list[0] pattern_list = pattern_list[1:] - - + control_char = re.compile(r""" \x1b[ #%()*+\-.\/]. | \r | #匹配 回车符(CR) @@ -237,14 +191,6 @@ def deal_command(str_r, ssh): return '' -def newline_code_in(strings): - for i in ['\r', '\r\n', '\n']: - if i in strings: - #print "new line" - return True - return False - - class Tty(object): """ A virtual tty class @@ -256,8 +202,8 @@ class Tty(object): self.ip = None self.port = 22 self.channel = None - self.user = None - self.asset = None + #self.asset = get_object(Asset, name=asset_name) + #self.user = get_object(User, username=username) self.role = None self.ssh = None self.connect_info = None @@ -292,44 +238,45 @@ class Tty(object): return line_filtered - def get_log_file(self): + def get_log(self): """ Logging user command and output. 记录用户的日志 """ - tty_log_dir = os.path.join(log_dir, 'tty') - timestamp_start = int(time.time()) - date_start = time.strftime('%Y%m%d', time.localtime(timestamp_start)) - time_start = time.strftime('%H%M%S', time.localtime(timestamp_start)) + tty_log_dir = os.path.join(LOG_DIR, 'tty') + date_today = datetime.datetime.now() + date_start = date_today.strftime('%Y%m%d') + time_start = date_today.strftime('%H%M%S') today_connect_log_dir = os.path.join(tty_log_dir, date_start) log_file_path = os.path.join(today_connect_log_dir, '%s_%s_%s' % (self.username, self.asset_name, time_start)) try: - is_dir(today_connect_log_dir, mode=0777) + mkdir(today_connect_log_dir, mode=0777) except OSError: + logger.debug('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, tty_log_dir)) raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, tty_log_dir)) try: log_file_f = open(log_file_path + '.log', 'a') log_time_f = open(log_file_path + '.time', 'a') except IOError: + logger.debug('创建tty日志文件失败, 请修改目录%s权限' % today_connect_log_dir) raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir) - if self.login_type == 'ssh': + if self.login_type == 'ssh': # 如果是ssh连接过来,记录connect.py的pid,web terminal记录为日志的id pid = os.getpid() - remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n') + remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n') # 获取远端IP log = Log(user=self.username, host=self.asset_name, remote_ip=remote_ip, - log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid) + log_path=log_file_path, start_time=date_today, pid=pid) else: remote_ip = 'Web' log = Log(user=self.username, host=self.asset_name, remote_ip=remote_ip, - log_path=log_file_path, start_time=datetime.datetime.now(), pid=0) + log_path=log_file_path, start_time=date_today, pid=0) log.save() log.pid = log.id - log.save() - log_file_f.write('Start at %s\n' % datetime.datetime.now()) log.save() + log_file_f.write('Start at %s\n' % datetime.datetime.now()) return log_file_f, log_time_f, log def get_connect_info(self): @@ -413,10 +360,10 @@ class SshTty(Tty): Use paramiko channel connect server interactive. 使用paramiko模块的channel,连接后端,进入交互式 """ - log_file_f, log_time_f, log = self.get_log_file() + log_file_f, log_time_f, log = self.get_log() old_tty = termios.tcgetattr(sys.stdin) pre_timestamp = time.time() - input_r = '' + data = '' input_mode = False try: @@ -445,22 +392,20 @@ class SshTty(Tty): log_time_f.flush() if input_mode and not self.is_output(x): - input_r += x + data += x except socket.timeout: pass if sys.stdin in r: x = os.read(sys.stdin.fileno(), 1) - if not input_mode: - input_mode = True + input_mode = True if str(x) in ['\r', '\n', '\r\n']: - # input_r = deal_command(input_r,ssh) - input_r = self.remove_control_char(input_r) + data = self.remove_control_char(data) - TtyLog(log=log, datetime=datetime.datetime.now(), cmd=input_r).save() - input_r = '' + TtyLog(log=log, datetime=datetime.datetime.now(), cmd=data).save() + data = '' input_mode = False if len(x) == 0: diff --git a/jlog/views.py b/jlog/views.py index 1e192fd78..0e3ee2ade 100644 --- a/jlog/views.py +++ b/jlog/views.py @@ -8,7 +8,7 @@ from django.http import HttpResponseNotFound from jlog.log_api import renderTemplate from models import Log -from jumpserver.settings import web_socket_host +from jumpserver.settings import WEB_SOCKET_HOST @require_role('admin') @@ -48,8 +48,8 @@ def log_list(request, offset): contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request) - web_monitor_uri = 'ws://%s/monitor' % web_socket_host - web_kill_uri = 'http://%s/kill' % web_socket_host + web_monitor_uri = 'ws://%s/monitor' % WEB_SOCKET_HOST + web_kill_uri = 'http://%s/kill' % WEB_SOCKET_HOST return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request)) @@ -108,6 +108,6 @@ def web_terminal(request): token = request.COOKIES.get('sessionid') username = request.user.username asset_name = '127.0.0.1' - web_terminal_uri = 'ws://%s/terminal?username=%s&asset_name=%s&token=%s' % (web_socket_host, username, asset_name, token) + web_terminal_uri = 'ws://%s/terminal?username=%s&asset_name=%s&token=%s' % (WEB_SOCKET_HOST, username, asset_name, token) return render_to_response('jlog/web_terminal.html', locals()) diff --git a/jumpserver.conf b/jumpserver.conf index 1b9ed3b25..fda6a681a 100644 --- a/jumpserver.conf +++ b/jumpserver.conf @@ -14,14 +14,6 @@ password = mysql234 database = jumpserver -[ldap] -ldap_enable = 1 -host_url = ldap://127.0.0.1:389 -base_dn = dc=jumpserver, dc=org -root_dn = cn=admin,dc=jumpserver,dc=org -root_pw = secret234 - - [websocket] web_socket_host = 192.168.244.129:3000 diff --git a/jumpserver/api.py b/jumpserver/api.py index 8f0073c15..d81a6eecd 100644 --- a/jumpserver/api.py +++ b/jumpserver/api.py @@ -25,7 +25,6 @@ import json import logging - def set_log(level): """ return a log file object @@ -35,7 +34,7 @@ def set_log(level): 'critical': logging.CRITICAL} logger_f = logging.getLogger('jumpserver') logger_f.setLevel(logging.DEBUG) - fh = logging.FileHandler(JLOG_FILE) + fh = logging.FileHandler(os.path.join(LOG_DIR, 'jumpserver.log')) fh.setLevel(log_level_total.get(level, logging.DEBUG)) formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) @@ -86,7 +85,6 @@ def pages(post_objects, request): return post_objects, paginator, page_objects, page_range, current_page, show_first, show_end - class PyCrypt(object): """ This class used to encrypt and decrypt password. @@ -98,7 +96,7 @@ class PyCrypt(object): self.mode = AES.MODE_CBC @staticmethod - def random_pass(length, especial=False): + def gen_rand_pass(length, especial=False): """ random password 随机生成密码 @@ -139,7 +137,7 @@ class PyCrypt(object): 对称加密之加密生成密码 """ if not passwd: - passwd = self.random_pass() + passwd = self.gen_rand_pass() cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1') try: @@ -256,6 +254,7 @@ def get_session_user_info(request): # return [user.id, user.username, user] return [request.user.id, request.user.username, request.user] + def get_user_dept(request): """ get the user dept id @@ -389,7 +388,7 @@ def bash(cmd): return subprocess.call(cmd, shell=True) -def is_dir(dir_name, username='root', mode=0755): +def mkdir(dir_name, username='root', mode=0755): """ insure the dir exist and mode ok 目录存在,如果不存在就建立,并且权限正确 @@ -414,5 +413,5 @@ def my_render(template, data, request): CRYPTOR = PyCrypt(KEY) -logger = set_log(log_level) +logger = set_log(LOG_LEVEL) diff --git a/jumpserver/settings.py b/jumpserver/settings.py index 4304c9f19..87785d0fb 100644 --- a/jumpserver/settings.py +++ b/jumpserver/settings.py @@ -34,18 +34,12 @@ EMAIL_USE_TLS = config.getboolean('mail', 'email_use_tls') EMAIL_TIMEOUT = 5 # ======== Log ========== -LOG = False LOG_DIR = os.path.join(BASE_DIR, 'logs') -JLOG_FILE = os.path.join(LOG_DIR, 'jumpserver.log') SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys') -# SERVER_KEY_DIR = os.path.join(SSH_KEY_DIR, 'server') KEY = config.get('base', 'key') -LOGIN_NAME = getpass.getuser() -# LDAP_ENABLE = CONF.getint('ldap', 'ldap_enable') URL = config.get('base', 'url') -log_dir = os.path.join(BASE_DIR, 'logs') -log_level = config.get('base', 'log') -web_socket_host = config.get('websocket', 'web_socket_host') +LOG_LEVEL = config.get('base', 'log') +WEB_SOCKET_HOST = config.get('websocket', 'web_socket_host') # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ diff --git a/run_websocket.py b/run_websocket.py index 4b8f2f981..ff0cbdace 100644 --- a/run_websocket.py +++ b/run_websocket.py @@ -179,7 +179,7 @@ class WebTty(Tty): super(WebTty, self).__init__(*args, **kwargs) self.login_type = 'web' self.ws = None - self.input_r = '' + self.data = '' self.input_mode = False @@ -197,12 +197,11 @@ class WebTerminalKillHandler(tornado.web.RequestHandler): class WebTerminalHandler(tornado.websocket.WebSocketHandler): - tasks = [] clients = [] + tasks = [] def __init__(self, *args, **kwargs): self.term = None - self.channel = None self.log_file_f = None self.log_time_f = None self.log = None @@ -220,7 +219,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler): print asset_name, username, token self.term = WebTty('a', 'b') self.term.get_connection() - self.channel = self.term.ssh.invoke_shell(term='xterm') + self.term.channel = self.term.ssh.invoke_shell(term='xterm') WebTerminalHandler.tasks.append(MyThread(target=self.forward_outbound)) WebTerminalHandler.clients.append(self) @@ -237,10 +236,10 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler): if data.get('data'): self.term.input_mode = True if str(data['data']) in ['\r', '\n', '\r\n']: - TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=self.term.remove_control_char(self.term.input_r)).save() - self.term.input_r = '' + TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=self.term.remove_control_char(self.term.data)).save() + self.term.data = '' self.term.input_mode = False - self.channel.send(data['data']) + self.term.channel.send(data['data']) def on_close(self): print 'On_close' @@ -256,15 +255,15 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler): pass def forward_outbound(self): - self.log_file_f, self.log_time_f, self.log = self.term.get_log_file() + self.log_file_f, self.log_time_f, self.log = self.term.get_log() self.id = self.log.id try: data = '' pre_timestamp = time.time() while True: - r, w, e = select.select([self.channel, sys.stdin], [], []) - if self.channel in r: - recv = self.channel.recv(1024) + r, w, e = select.select([self.term.channel, sys.stdin], [], []) + if self.term.channel in r: + recv = self.term.channel.recv(1024) if not len(recv): return data += recv @@ -277,7 +276,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler): self.log_file_f.flush() self.log_time_f.flush() if self.term.input_mode and not self.term.is_output(data): - self.term.input_r += data + self.term.data += data data = '' except UnicodeDecodeError: pass