# coding:utf-8 from django.db.models import Q from django.template import RequestContext from django.shortcuts import render_to_response, render from jumpserver.api import * from jperm.perm_api import user_have_perm from django.http import HttpResponseNotFound from jlog.log_api import renderTemplate from jlog.models import Log, ExecLog, FileLog, TermLog from jumpserver.settings import LOG_DIR import zipfile import json import pyte @require_role('admin') def log_list(request, offset): """ 显示日志 """ header_title, path1 = u'审计', u'操作审计' date_seven_day = request.GET.get('start', '') date_now_str = request.GET.get('end', '') username_list = request.GET.getlist('username', []) host_list = request.GET.getlist('host', []) cmd = request.GET.get('cmd', '') if offset == 'online': keyword = request.GET.get('keyword', '') posts = Log.objects.filter(is_finished=False).order_by('-start_time') if keyword: posts = posts.filter(Q(user__icontains=keyword) | Q(host__icontains=keyword) | Q(login_type__icontains=keyword)) elif offset == 'exec': posts = ExecLog.objects.all().order_by('-id') keyword = request.GET.get('keyword', '') if keyword: posts = posts.filter(Q(user__icontains=keyword) | Q(host__icontains=keyword) | Q(cmd__icontains=keyword)) elif offset == 'file': posts = FileLog.objects.all().order_by('-id') keyword = request.GET.get('keyword', '') if keyword: posts = posts.filter( Q(user__icontains=keyword) | Q(host__icontains=keyword) | Q(filename__icontains=keyword)) else: posts = Log.objects.filter(is_finished=True).order_by('-start_time') username_all = set([log.user for log in Log.objects.all()]) ip_all = set([log.host for log in Log.objects.all()]) if date_seven_day and date_now_str: datetime_start = datetime.datetime.strptime(date_seven_day + ' 00:00:01', '%m/%d/%Y %H:%M:%S') datetime_end = datetime.datetime.strptime(date_now_str + ' 23:59:59', '%m/%d/%Y %H:%M:%S') posts = posts.filter(start_time__gte=datetime_start).filter(start_time__lte=datetime_end) if username_list: posts = posts.filter(user__in=username_list) if host_list: posts = posts.filter(host__in=host_list) if cmd: log_id_list = set([log.log_id for log in TtyLog.objects.filter(cmd__contains=cmd)]) posts = posts.filter(id__in=log_id_list) if not date_seven_day: date_now = datetime.datetime.now() date_now_str = date_now.strftime('%m/%d/%Y') date_seven_day = (date_now + datetime.timedelta(days=-7)).strftime('%m/%d/%Y') contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request) session_id = request.session.session_key return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request)) @require_role('admin') def log_detail(request): return my_render('jlog/exec_detail.html', locals(), request) @require_role('admin') def log_kill(request): """ 杀掉connect进程 """ pid = request.GET.get('id', '') log = Log.objects.filter(pid=pid) if log: log = log[0] try: os.kill(int(pid), 9) except OSError: pass Log.objects.filter(pid=pid).update(is_finished=1, end_time=datetime.datetime.now()) return render_to_response('jlog/log_offline.html', locals(), context_instance=RequestContext(request)) else: return HttpResponseNotFound(u'没有此进程!') @require_role('admin') def log_history(request): """ 命令历史记录 """ log_id = request.GET.get('id', 0) log = Log.objects.filter(id=log_id) if log: log = log[0] tty_logs = log.ttylog_set.all() if tty_logs: content = '' for tty_log in tty_logs: content += '%s: %s\n' % (tty_log.datetime.strftime('%Y-%m-%d %H:%M:%S'), tty_log.cmd) return HttpResponse(content) return HttpResponse('无日志记录!') # @require_role('admin') # def log_record(request): # log_id = request.GET.get('id', 0) # log = Log.objects.filter(id=int(log_id)) # if log: # log = log[0] # log_file = log.log_path + '.log' # log_time = log.log_path + '.time' # if os.path.isfile(log_file) and os.path.isfile(log_time): # content = renderTemplate(log_file, log_time) # return HttpResponse(content) # else: # return HttpResponse('无日志记录!') @require_role('admin') def log_record(request): """ Author: liuzheng712@gmail.com """ if request.method == "GET": return render(request, 'jlog/record.html') elif request.method == "POST": log_id = request.REQUEST.get('id', None) if log_id: TermL = TermLogRecorder(request.user) log = Log.objects.get(id=int(log_id)) return HttpResponse(TermL.load_full_log(filename=log.filename)) else: return HttpResponse("ERROR") else: return HttpResponse("ERROR METHOD!") @require_role('admin') def log_detail(request, offset): log_id = request.GET.get('id') if offset == 'exec': log = get_object(ExecLog, id=log_id) assets_hostname = log.host.split(' ') try: result = eval(str(log.result)) except (SyntaxError, NameError): result = {} return my_render('jlog/exec_detail.html', locals(), request) elif offset == 'file': log = get_object(FileLog, id=log_id) assets_hostname = log.host.split(' ') file_list = log.filename.split(' ') try: result = eval(str(log.result)) except (SyntaxError, NameError): result = {} return my_render('jlog/file_detail.html', locals(), request) class TermLogRecorder(object): """ TermLogRecorder --- Author: liuzheng This class is use for record the terminal output log. self.commands is pure commands list, it will have empty item '' because in vi/vim model , I made it log noting. self.CMD is the command with timestamp, like this {'1458723794.88': u'ls', '1458723799.82': u'tree'}. self.log is the all output with delta time log. self.vim_pattern is the regexp for check vi/vim/fg model. Usage: recorder = TermLogRecorder(user=UserObject) # or recorder = TermLogRecorder(uid=UserID) recoder.write(messages) recoder.save() # save all log into database # The following methods all have `user`,`uid`,args. Same as __init__ list = recoder.list() # will give a object about this user's all log info recoder.load_full_log(filemane) # will get full log recoder.load_history(filename) # will only get the command history list recoder.share_to(filename,user=UserObject) # or recoder.share_to(filename,uid=UserID). will share this commands to someone recoder.unshare_to(filename,user=UserObject) # or recoder.unshare_to(filename,uid=UserID). will unshare this commands to someone recoder.setid(id) # registered this term with an id, for monitor """ loglist = dict() def __init__(self, user=None, uid=None): self.log = {} self.id = 0 if isinstance(user, User): self.user = user elif uid: self.user = User.objects.get(id=uid) else: self.user = None self.recoderStartTime = time.time() self.__init_screen_stream() self.recoder = False self.commands = [] self._lists = None self.file = None self.filename = None self._data = None self.vim_pattern = re.compile(r'\W?vi[m]?\s.* | \W?fg\s.*', re.X) self._in_vim = False self.CMD = {} def __init_screen_stream(self): """ Initializing the virtual screen and the character stream """ self._stream = pyte.ByteStream() self._screen = pyte.Screen(80, 24) self._stream.attach(self._screen) def _command(self): for i in self._screen.display: if i.strip().__len__() > 0: self.commands.append(i.strip()) if not i.strip() == '': self.CMD[str(time.time())] = self.commands[-1] self._screen.reset() def setid(self, id): self.id = id TermLogRecorder.loglist[str(id)] = [self] def write(self, msg): if self.recoder and (not self._in_vim): if self.commands.__len__() == 0: self._stream.feed(msg) elif not self.vim_pattern.search(self.commands[-1]): self._stream.feed(msg) else: self._in_vim = True self._command() else: if self._in_vim: if re.compile(r'\[\?1049', re.X).search(msg.decode('utf-8', 'replace')): self._in_vim = False self.commands.append('') self._screen.reset() else: self._command() try: self.write_message(msg) except: pass # print "<<<<<<<<<<<<<<<<" # print self.commands # print self.CMD # print ">>>>>>>>>>>>>>>>" self.log[str(time.time() - self.recoderStartTime)] = msg.decode('utf-8', 'replace') def save(self, path=LOG_DIR): date = datetime.datetime.now().strftime('%Y%m%d') filename = str(uuid.uuid4()) self.filename = filename filepath = os.path.join(path, 'tty', date, filename + '.zip') if not os.path.isdir(os.path.join(path, 'tty', date)): os.makedirs(os.path.join(path, 'tty', date), mode=0777) while os.path.isfile(filepath): filename = str(uuid.uuid4()) filepath = os.path.join(path, 'tty', date, filename + '.zip') password = str(uuid.uuid4()) try: zf = zipfile.ZipFile(filepath, 'w', zipfile.ZIP_DEFLATED) zf.setpassword(password) zf.writestr(filename, json.dumps(self.log)) zf.close() record = TermLog.objects.create(logPath=filepath, logPWD=password, filename=filename, history=json.dumps(self.CMD), timestamp=int(self.recoderStartTime)) if self.user: record.user.add(self.user) except: record = TermLog.objects.create(logPath='locale', logPWD=password, log=json.dumps(self.log), filename=filename, history=json.dumps(self.CMD), timestamp=int(self.recoderStartTime)) if self.user: record.user.add(self.user) try: del TermLogRecorder.loglist[str(self.id)] except KeyError: pass def list(self, user=None, uid=None): tmp = [] if isinstance(user, User): user = user elif uid: user = User.objects.get(id=uid) else: user = self.user if user: self._lists = TermLog.objects.filter(user=user.id) for i in self._lists.all(): tmp.append( {'filename': i.filename, 'locale': i.logPath == 'locale', 'nick': i.nick, 'timestamp': i.timestamp, 'date': i.datetimestamp}) return tmp def load_full_log(self, filename, user=None, uid=None): if isinstance(user, User): user = user elif uid: user = User.objects.get(id=uid) else: user = self.user if user: if self._lists: self.file = self._lists.get(filename=filename) else: self.file = TermLog.objects.get(user=user.id, filename=filename) if self.file.logPath == 'locale': return self.file.log else: try: zf = zipfile.ZipFile(self.file.logPath, 'r', zipfile.ZIP_DEFLATED) zf.setpassword(self.file.logPWD) self._data = zf.read(zf.namelist()[0]) return self._data except KeyError: return 'ERROR: Did not find %s file' % filename return 'ERROR User(None)' def load_history(self, filename, user=None, uid=None): if isinstance(user, User): user = user elif uid: user = User.objects.get(id=uid) else: user = self.user if user: if self._lists: self.file = self._lists.get(filename=filename) else: self.file = TermLog.objects.get(user=user.id, filename=filename) return self.file.history return 'ERROR User(None)' def share_to(self, filename, user=None, uid=None): if isinstance(user, User): user = user elif uid: user = User.objects.get(id=uid) else: pass if user: TermLog.objects.get(filename=filename).user.add(user) return True return False def unshare_to(self, filename, user=None, uid=None): if isinstance(user, User): user = user elif uid: user = User.objects.get(id=uid) else: pass if user: TermLog.objects.get(filename=filename).user.remove(user) return True return False