Larger python qt pyqt example



This is my OLD blog. I've copied this post over to my NEW blog at:

http://www.saltycrane.com/blog/2006/12/larger-python-qt-pyqt-example/

You should be redirected in 2 seconds.



This script is used to parse Windows Event Viewer logs. It uses dumpel.exe. It colors significant events and presents results in a QT GUI.
"""windows_audit.py
"""

__author__ = "So Feng"
__version__ = "$Revision: 1.0 $"
__date__ = "$Date: 2006/10/17 $"
__license__ = "Python"

import re
import datetime
from datetime import date
import time
import glob
import os
import sys
from Qt import *
import StringIO

# constants
NCHARS_TO_WRAP = 30
EARLY_HOUR = 6
LATE_HOUR = 20
outfile = "audit_" + str(datetime.date.today()) + ".txt"
red_eventids = ["560","565","592","678"] orange_eventids = ["539","629","644","531","544","545","675","676"]
yellow_eventids = ["529","530","532","533","534","535","536","537","681",
                   "576","608","609","610","611","624","625","626","627",
                   "628","630","631","632","633","634","635","636","637",
                   "638","639","640","641","642","643","645","646","647",
                   "648","649","650","651","652","653","654","655","656",
                   "657","658","659","660","661","662","663","664","665",
                   "666","667","668","669","670","672"]
green_eventids = ["528", "538", "540", "680"] other_eventids = ["612", "617", "618", "619"] failure_list = ('529', '530', '531', '532', '533', '534', '535', '536', '537', '539', '544', '545', '546', '547', '616', '675', '676', '677', '679', '681', ) success_list = ('512', '513', '514', '515', '516', '517', '518', '528', '538', '540', '541', '542', '543', '560', '561', '562', '563', '564', '565', '566', '576', '577', '578', '592', '593', '594', '595', '608', '609', '610', '611', '612', '613', '614', '615', '617', '618', '619', '620', '624', '625', '626', '627', '628', '630', '631', '632', '633', '634', '635', '636', '637', '638', '639', '640', '641', '642', '643', '644', '645', '646', '647', '648', '649', '650', '651', '652', '653', '654', '655', '656', '657', '658', '659', '660', '661', '662', '663', '664', '665', '666', '667', '668', '669', '670', '672', '673', '674', '678', '680', '682', '683', ) event_desc = {
'512': 'Windows NT is starting up. ',
'513': 'Windows NT is shutting down.\n             All logon sessions will be terminated by this shutdown. ',
'514': 'An authentication package has been loaded by the Local Security Authority.\n             This authentication package will be used to authenticate logon attempts. ',
'515': 'A trusted logon process has registered with the Local Security Authority.\n             This logon process will be trusted to submit logon requests. ',
'516': 'Internal resources allocated for the queuing of audit messages have been\n             exhausted, leading to the loss of some audits. ',
'517': 'The audit log was cleared ',
'518': 'An notification package has been loaded by the Security Account Manager.\n             This package will be notified of any account or password changes. ',
'528': 'Successful Logon: ',
'529': 'Logon Failure Unknown user name or bad password',
'530': 'Logon Failure Account logon time restriction violation',
'531': 'Logon Failure Account currently disabled',
'532': 'Logon Failure The specified user account has expired',
'533': 'Logon Failure User not allowed to logon at this computer',
'534': 'Logon Failure The user has not been granted the requested \n             logon type at this machine',
'535': 'Logon Failure The specified account\'s password has expired',
'536': 'Logon Failure The NetLogon component is not active',
'537': 'Logon Failure An unexpected error occurred during logon',
'538': 'User Logoff ',

'539': 'Logon Failure Account locked out',
'540': 'Successful Network Logon ',
'541': 'IKE security association established. ',
'542': 'IKE security association ended. ',
'543': 'IKE security association ended. ',
'544': 'IKE security association establishment failed because peer could not\n             authenticate. The certificate trust could not be established. ',
'545': 'IKE peer authentication failed. ',
'546': 'IKE security association establishment failed because peer\n             sent invalid proposal. ',
'547': 'IKE security association negotiation failed. ',
'560': 'Object Open ',
'561': 'Handle Allocated ',
'562': 'Handle Closed ',
'563': 'Object Open for Delete ',
'564': 'Object Deleted ',
'565': 'Object Open ',
'566': 'Object Operation ',
'576': 'Special privileges assigned to new logon: ',
'577': 'Privileged Service Called ',
'578': 'Privileged object operation ',
'592': 'A new process has been created ',
'593': 'A process has exited ',
'594': 'A handle to an object has been duplicated ',
'595': 'Indirect access to an object has been obtained ',
'608': 'User Right Assigned ',
'609': 'User Right Removed ',
'610': 'New Trusted Domain ',
'611': 'Removing Trusted Domain ',
'612': 'Audit Policy Change ',
'613': 'IPSec policy agent started ',
'614': 'IPSec policy agent disabled ',
'615': 'IPSEC PolicyAgent Service:  %1 ',
'616': 'IPSec policy agent encountered a potentially serious failure. ',
'617': 'Kerberos Policy Changed ',
'618': 'Encrypted Data Recovery Policy Changed ',
'619': 'Quality of Service Policy Changed ',
'620': 'Trusted Domain Information Modified: ',
'624': 'User Account Created ',
'625': 'User Account Type Change ',
'626': 'User Account Enabled ',
'627': 'Change Password Attempt ',
'628': 'User Account password set ',
'630': 'User Account Deleted: ',
'631': 'Security Enabled Global Group Created ',
'632': 'Security Enabled Global Group Member Added ',
'633': 'Security Enabled Global Group Member Removed ',
'634': 'Security Enabled Global Group Deleted ',
'635': 'Security Enabled Local Group Created ',
'636': 'Security Enabled Local Group Member Added ',
'637': 'Security Enabled Local Group Member Removed ',
'638': 'Security Enabled Local Group Deleted ',
'639': 'Security Enabled Local Group Changed ',
'640': 'General Account Database Change ',
'641': 'Security Enabled Global Group Changed ',
'642': 'User Account Changed ',
'643': 'Domain Policy Changed: %1 modified ',
'644': 'User Account Locked Out ',
'645': 'Computer Account Created ',
'646': 'Computer Account Changed ',
'647': 'Computer Account Deleted ',
'648': 'Security Disabled Local Group Created ',
'649': 'Security Disabled Local Group Changed ',
'650': 'Security Disabled Local Group Member Added ',
'651': 'Security Disabled Local Group Member Removed ',
'652': 'Security Disabled Local Group Deleted ',
'653': 'Security Disabled Global Group Created ',
'654': 'Security Disabled Global Group Changed ',
'655': 'Security Disabled Global Group Member Added ',
'656': 'Security Disabled Global Group Member Removed ',
'657': 'Security Disabled Global Group Deleted ',
'658': 'Security Enabled Universal Group Created ',
'659': 'Security Enabled Universal Group Changed ',
'660': 'Security Enabled Universal Group Member Added ',
'661': 'Security Enabled Universal Group Member Removed ',
'662': 'Security Enabled Universal Group Deleted ',
'663': 'Security Disabled Universal Group Created ',
'664': 'Security Disabled Universal Group Changed ',
'665': 'Security Disabled Universal Group Member Added ',
'666': 'Security Disabled Universal Group Member Removed ',
'667': 'Security Disabled Universal Group Deleted ',
'668': 'Group Type Changed ',
'669': 'Add SID History ',
'670': 'Add SID History ',
'672': 'Authentication Ticket Granted ',
'673': 'Service Ticket Granted ',
'674': 'Ticket Granted Renewed ',
'675': 'Pre-authentication failed ',
'676': 'Authentication Ticket Request Failed ',
'677': 'Authentication Ticket Request Failed ',
'678': 'Account Mapped for Logon by: %1 ',
'679': 'The name: %2 could not be mapped for logon by: %1 ',
'680': 'Account Used for Logon by: %1 ',
'681': 'The logon to account: %2 by: %1 from workstation: %3 failed. The error code was: %4 ',
'682': 'Session reconnected to winstation: ',
'683': 'Session disconnected from winstation: ',
              }
#sys.stderr = StringIO.StringIO()
#sys.stdout = StringIO.StringIO()
################################################################            
################################################################
def main():
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)
    form = StartForm()
    form.show()
    report = ReportWindow()
    app.connect(form, SIGNAL("okClicked"),
                report.create)
    sys.exit(app.exec_())
    
################################################################            
################################################################
class StartForm(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        
#        # directory tree
#        label_file = QLabel()
#        label_file.setText("Select file:")
#        dirmodel = QDirModel()
#        treeview = QTreeView(self)
#        treeview.setModel(dirmodel)
#        treeview.setRootIndex(dirmodel.index(QDir.currentPath()))
#        treeview.hideColumn(1)
#        treeview.hideColumn(2)
#        treeview.hideColumn(3)
#        treeview.header().hide()
        
        # date box
        self.label_date = QLabel()
        self.label_date.setText("Set date of last audit:")
        default = datetime.date.today() - datetime.timedelta(10)
        self.datebox = QDateEdit(QDate(default.year, default.month, default.day))
        
        # buttons
        spacer = QSpacerItem(20,40,QSizePolicy.Minimum,QSizePolicy.Expanding)
        self.button_ok = QPushButton()
        self.button_ok.setText("OK")
        self.button_ok.setDefault(True)
        button_cancel = QPushButton()
        button_cancel.setText("Cancel")
    
        # layout
#        layout_left = QVBoxLayout()
#        layout_left.addWidget(label_file)
#        layout_left.addWidget(treeview)
        layout_right = QVBoxLayout(self)
        layout_right.addWidget(self.label_date)
        layout_right.addWidget(self.datebox)
        layout_right.addItem(spacer)
        layout_right.addWidget(self.button_ok)
        layout_right.addWidget(button_cancel)
#        layout = QHBoxLayout(self)
#        layout.addLayout(layout_left)
#        layout.addLayout(layout_right)
        
        # connections
        self.connect(button_cancel, SIGNAL("clicked()"),
                    self.close)
        self.connect(self.button_ok, SIGNAL("clicked()"),
                    self.ok_clicked)
        
    def ok_clicked(self):
        self.label_date.setText("Getting eventlog data...")
        year = self.datebox.date().year()
        month = self.datebox.date().month()
        day = self.datebox.date().day()
        delta = datetime.date.today() - datetime.date(int(year),int(month),int(day))
        self.emit(SIGNAL("okClicked"), delta.days)
        self.close()
        
################################################################            
################################################################
class ReportWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
#        self.cb = QCheckBox()
        self.table = MyTable()
        self.textbrowser = QTextBrowser()
        self.textbrowser.setFontFamily("Courier")
        self.textbrowser.setFontPointSize(10)
        splitter = QSplitter(Qt.Vertical, self)
#        splitter = QSplitter(Qt.Vertical)
        splitter.addWidget(self.table)
        splitter.addWidget(self.textbrowser)
#        vlayout = QVBoxLayout(self)
#        vlayout.addWidget(self.cb)
#        vlayout.addWidget(splitter)        
        self.setGeometry(100,100,750,550)
        self.setCentralWidget(splitter)
        
    def create(self, date):
        self.table.parse_event_log(date) 
        self.table.setdata()

        fh = open(outfile, "r")
        text = fh.read()
        self.textbrowser.setPlainText(text)
        
        self.show()

################################################################
################################################################
class MyTable(QTableWidget):
    def __init__(self, *args):
        QTableWidget.__init__(self, *args)
        self.setSortingEnabled(True)
        self.setSelectionMode(self.ContiguousSelection)
        #self.setFixedWidth(750)
        self.setGeometry(0,0,700,400)
        self.data = []
    
    def setdata(self):
        if len(self.data) == 0:
            self.setRowCount(1)
            self.setColumnCount(1)
            newitem = QTableWidgetItem("No data for this date range.")
            self.setItem(0, 0, newitem)
            self.resizeColumnsToContents()
        else:
            self.nrows = len(self.data)
            self.ncols = len(self.data[0])
            self.setRowCount(self.nrows)
            self.setColumnCount(self.ncols)
            self.setmydata_list()
            self.resizeColumnsToContents()
            self.setGridStyle(Qt.DotLine)
            self.setShowGrid(False)
            self.setColumnWidth(3, 250)
            #self.resizeRowsToContents()
            #self.setHorizontalHeaderLabels(['date','time','?','?','event','source','user','?','computer','data'])
            self.setHorizontalHeaderLabels(['Date','Time','Type','Event','User','Computer','Data'])

    def setmydata_list(self):    
        n = 0
        date_prev = ''
        for row in self.data:
            # event processing
            event = row[4]
            try:
                row[4] = event + ": " + event_desc[event]
            except:
                pass
            color = QColor("white")
            if event in red_eventids:
                color = QColor("red")
            elif event in orange_eventids:
                color = QColor("orange")
            elif event in yellow_eventids:
                color = QColor("yellow")
            elif event in green_eventids:
                #color = QColor("green")
                pass
            elif event in other_eventids:
                color = QColor("blue")
            
            # success or failure processing
            if row[2] == "8":
                row[2] = "Success"
                icon = QIcon("success.png")
            elif row[2] == "16":
                row[2] = "Failure"
                icon = QIcon("failure.png")
            else:
                row[2] = "Unknown"
                icon = QIcon("unknown.png")
                
            # date processing
            row[0] = format_datetime(row[0], row[1])
            (date, thetime) = re.split(r"\n", row[0])
            newday = False
            if date != date_prev:
                newday = True
            date_prev = date
            thetime = re.split(r":", thetime)
            hour = int(thetime[0])
            if hour <= EARLY_HOUR or hour >= LATE_HOUR:
                colordate = QColor(0,0,102)
            else:
                colordate = QColor("white")

            # user
            (dom, user) = re.split(r"\\", row[6])
            row[6] = user
            if user in ("SYSTEM", "NETWORK SERVICE", "LOCAL SERVICE", "ANONYMOUS LOGON"):
                textcolor = QColor("gray")
                font = QFont("Arial", 8)
            else:
                textcolor = QColor("black")
                font = QFont("Arial", 8)
                font.setBold(True)

            # insert line
            if newday:
                m = 0
                for j in range(len(row)-3):
                    text = ""
                    if j == 0:
                        text = date
                    newitem = QTableWidgetItem(text)
                    newitem.setBackgroundColor(QColor("black"))
                    self.setItem(n, m, newitem)
                    m += 1
                self.setRowHeight(n, 15)
                n += 1

            #for item in row:
            m = 0
            for j in range(len(row)):
                # skip these columns
                if j in (3,5,7):
                    continue
                
                item = row[j]
                if j == 1:
                    color2 = colordate
                else:
                    color2 = color

                newitem = QTableWidgetItem(item)
                newitem.setBackgroundColor(color2)
                newitem.setTextColor(textcolor)
                newitem.setFont(font)
                newitem.setTextAlignment(Qt.AlignTop)
                newitem.setToolTip(item)
                if j == 2:
                    newitem.setIcon(icon)
                self.setItem(n, m, newitem)
                m += 1
            self.setRowHeight(n, 16)
            n += 1

    def parse_event_log(self, ndays):
        """Parses event log file.
        Returns none.
        """
        # run dumpel.exe
        os.system("dumpel -f dumpel_results.txt -l security -d %s" % ndays)
        fin = open("dumpel_results.txt")
        lines = fin.readlines()
    
        # open output files
        #outfile = "audit_" + str(datetime.date.today()) + ".txt"
        fout=open(outfile,'w')
    
        # initialization
        fout.write("LOGON/LOGOFFS:\n")
        fout.write("--------------\n")
        output = "%-13s %3s %11s %12s %12s\n" % ('user','day','date','logon','logoff')
        fout.write(output)
        event578_count = 0
        user_logged_in = 0
        red_events = []
        orange_events = []
        yellow_events = []
        
        # loop on each line in the file
        for line in lines:
            items = re.split('\t', line)
            self.data.append(items)
            date = items[0]
            time = items[1]
            event = items[4]
            (dom, user) = re.split(r"\\", items[6])
            day = get_weekday(date)
            if event in red_eventids:
                red_events.append(line)
            elif event in orange_eventids:
                orange_events.append(line)
            elif event in yellow_eventids:
                yellow_events.append(line)
            elif user != "SYSTEM":
                #if (not user_logged_in) and (event == "528"):
                if event == "528":
                    if user_logged_in:
                        output = "%-13s %3s %11s %12s %12s\n" % (user,day,logon_date,logon_time,'no logout')
                        fout.write(output)
                    logon_time = time
                    logon_user = user
                    logon_date = date
                    logout_backup = ""
                    user_logged_in = 1
                        
                elif user_logged_in and event == "578":
                    if user == logon_user:
                        if event578_count == 0:
                            event578_count = 1
                        elif event578_count == 1:
                            event578_count = 0
                            user_logged_in = 0
                            output = "%-13s %3s %11s %12s %12s\n" % (user,day,logon_date,logon_time,time)
                            fout.write(output)
    
        # print red events
        fout.write("\nRED EVENTS:\n")
        fout.write("-----------\n")
        if len(red_events) == 0:
            fout.write("None.\n")
        else:
            for event in red_events:
                fout.write(event)
    
        # print orange events
        fout.write("\nORANGE EVENTS:\n")
        fout.write("--------------\n")
        if len(orange_events) == 0:
            fout.write("None.\n")
        else:
            for event in orange_events:
                fout.write(event)
    
        # print yellow events
        fout.write("\nYELLOW EVENTS:\n")
        fout.write("--------------\n")
        if len(yellow_events) == 0:
            fout.write("None.\n")
        else:
            for event in yellow_events:
                fout.write(event)
    
        # close files
        fin.close()
        fout.close()
    
        # print message
        print "Parse sucessful.\n"
        
        return

################################################################
################################################################
def get_weekday(date):
    (month,day,year) = re.split('/', date)
    weekday = datetime.date(int(year),int(month),int(day)).weekday()
    day_names = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']

    return day_names[weekday]

################################################################
################################################################
def format_datetime(date, thetime):
    (month,day,year) = re.split('/', date)
    dateobj = datetime.date(int(year),int(month),int(day))
    newdate = "%04d/%02d/%02d" % (dateobj.year, dateobj.month, dateobj.day)
    
    timeobj = time.strptime(thetime, "%I:%M:%S %p")
    newtime = time.strftime("%H:%M:%S", timeobj)
    
    return newdate + "\n" + newtime

################################################################
################################################################
def get_dateobject(date):
    (month,day,year) = re.split('/', date)
    return datetime.date(int(year),int(month),int(day))
  
################################################################
################################################################
if __name__ == "__main__":
    main()

1 comment:

Anonymous said...

Hello
Thanks for your postings.

What is the best way to deal with null dates in a QDateEdit? - ie the end date for a particular date range that hasn't ended yet? I want the user to set the date and not have a date equivalent of null displayed.

About

This is my *OLD* blog. I've copied all of my posts and comments over to my NEW blog at:

http://www.saltycrane.com/blog/.

Please go there for my updated posts. I will leave this blog up for a short time, but eventually plan to delete it. Thanks for reading.