def executeRemoteCommand(command): result = True if command == REMOTE_LOCK: if hardwareconfig.checkLock() == False: AFroutines.lockScreen() result = sendemail.sendEmail("Command successful","Screen locked") eventQueue.put(("Log",'Screen locked due to remote command')) else: eventQueue.put(("Log",'Lock screen failed - command received while locked')) result = sendemail.sendEmail("Command failed","Screen already locked") elif command == REMOTE_STARTMONITOR: #cant check ispy camera status, just have to assume it was not monitoring iSpyPath = fileconfig.config.get('TRIGGERS','ispy_path') roomCamID = fileconfig.config.get('TRIGGERS','room_cam_id') if os.path.exists(iSpyPath): eventQueue.put(("Log","Starting room camera due to remote command")) else: eventQueue.put(("Log","iSpy executable not found - cannot fulfill remote command")) return subprocess.call([iSpyPath,'commands bringonline,2,%s'%roomCamID]) result = sendemail.sendEmail("Command successful","Movement monitoring initiated. Have a nice day.") elif command == REMOTE_STOPMONITOR: #cant check ispy camera status, just have to assume it was already monitoring iSpyPath = fileconfig.config.get('TRIGGERS','ispy_path') roomCamID = fileconfig.config.get('TRIGGERS','room_cam_id') if os.path.exists(iSpyPath): eventQueue.put(("Log","Stopping room camera due to remote command")) else: eventQueue.put(("Log","iSpy executable not found - cannot fulfill remote command")) return subprocess.call([iSpyPath,'commands takeoffline,2,%s'%roomCamID]) result = sendemail.sendEmail("Command successful","Movement monitoring disabled. Welcome home!") elif command == REMOTE_SHUTDOWN: result = sendemail.sendEmail("Command successful","Shutting down...") eventQueue.put(("Log","Initiating standard shutdown due to remote command")) AFroutines.standardShutdown() elif command == REMOTE_KILLSWITCH: eventQueue.put(("Log","Initiating emergency shutdown due to remote command")) AFroutines.emergency() if result != True: eventQueue.put(('Log','Mail send failed: %s'%result))
def executeRemoteCommand(command): result = True if command == REMOTE_LOCK: if hardwareconfig.checkLock() == False: AFroutines.lockScreen() result = sendemail.sendEmail("Command successful", "Screen locked") eventQueue.put(("Log", 'Screen locked due to remote command')) else: eventQueue.put( ("Log", 'Lock screen failed - command received while locked')) result = sendemail.sendEmail("Command failed", "Screen already locked") elif command == REMOTE_STARTMONITOR: #cant check ispy camera status, just have to assume it was not monitoring iSpyPath = fileconfig.config.get('TRIGGERS', 'ispy_path') roomCamID = fileconfig.config.get('TRIGGERS', 'room_cam_id') if os.path.exists(iSpyPath): eventQueue.put( ("Log", "Starting room camera due to remote command")) else: eventQueue.put( ("Log", "iSpy executable not found - cannot fulfill remote command")) return subprocess.call([iSpyPath, 'commands bringonline,2,%s' % roomCamID]) result = sendemail.sendEmail( "Command successful", "Movement monitoring initiated. Have a nice day.") elif command == REMOTE_STOPMONITOR: #cant check ispy camera status, just have to assume it was already monitoring iSpyPath = fileconfig.config.get('TRIGGERS', 'ispy_path') roomCamID = fileconfig.config.get('TRIGGERS', 'room_cam_id') if os.path.exists(iSpyPath): eventQueue.put( ("Log", "Stopping room camera due to remote command")) else: eventQueue.put( ("Log", "iSpy executable not found - cannot fulfill remote command")) return subprocess.call([iSpyPath, 'commands takeoffline,2,%s' % roomCamID]) result = sendemail.sendEmail( "Command successful", "Movement monitoring disabled. Welcome home!") elif command == REMOTE_SHUTDOWN: result = sendemail.sendEmail("Command successful", "Shutting down...") eventQueue.put( ("Log", "Initiating standard shutdown due to remote command")) AFroutines.standardShutdown() elif command == REMOTE_KILLSWITCH: eventQueue.put( ("Log", "Initiating emergency shutdown due to remote command")) AFroutines.emergency() if result != True: eventQueue.put(('Log', 'Mail send failed: %s' % result))
def run(self): if fileconfig.config.get('TRIGGERS', 'debuglog') == 'True': global VERBOSELOGS VERBOSELOGS = True debugLog('Lockwatcher Started') global startupTime startupTime = time.time() #send log/status updates to connections in here - for config programs listeners = [] confMonThread = configMonitor() confMonThread.start() LOCKED = fileconfig.config.get('TRIGGERS', 'lockedtriggers').split(',') ALWAYS = fileconfig.config.get('TRIGGERS', 'alwaystriggers').split(',') ACTIVE = LOCKED + ALWAYS global eventQueue eventQueue = Queue.Queue() threadStatuses = {} threadDict = {} for trigger in ACTIVE: if trigger != '': startMonitor(threadDict, trigger) if fileconfig.config.get('EMAIL', 'ENABLE_REMOTE') == 'True': startMonitor(threadDict, 'email') #new month, new log logPath = fileconfig.config.get('TRIGGERS', 'logfile') if os.path.exists(logPath): creationTime = time.ctime(os.path.getctime(logPath)) creationMonth = datetime.datetime.strptime(creationTime, "%a %b %d %H:%M:%S %Y") monthNow = time.strftime('%m %Y') if creationMonth != monthNow: try: open(logPath, 'w').close() except: pass eventQueue.put(('Log', 'Lockwatcher monitoring started')) badCommands = 0 shutdownActivated = False while True: event = eventQueue.get(block=True, timeout=None) debugLog('Event in queue: ' + str(event)) eventType = event[0] #--------------trigger activated under shutdown conditions if eventType == 'Kill': eventReason = event[1] #don't trigger multiple shutdowns but keep logging while we can if shutdownActivated == False: shutdownActivated = True if fileconfig.config.get('EMAIL','email_alert') == 'True' and \ 'Kill switch' not in eventReason: try: #has a 4 second timeout for blocking operations result = sendemail.sendEmail( 'Emergency shutdown triggered', eventReason) if result != True: eventQueue.put( ('Log', 'Mail send failed: %s' % result)) except: pass #email failed, oh well. AFroutines.emergency() #--------------thread status changed, inform any listeners elif eventType == 'Status': #if self.statuses != None: self.statuses[event[1]].set(event[2]) threadStatuses[event[1]] = event[2] msg = 'Status::%s::%s' % (event[1], event[2]) broadcast(listeners, msg) #-----------config programs can request all the current statuses elif eventType == 'getStatuses': msg = 'AllStatuses::' for name, value in threadStatuses.items(): msg = msg + '%s::%s|' % (name, value) msg = msg[:-1] broadcast(listeners, msg) #--------------add to log file + listener log window if they exist elif eventType == 'Log': addLogEntry(str(event[1]), listeners) elif eventType == 'stop': broadcast(listeners, 'Shutdown') for threadname in threadDict.keys(): if isRunning(threadname, threadDict): threadDict[threadname].terminate() confMonThread.terminate() time.sleep(1) #give threads time to shutdown return elif eventType == 'startMonitor': monitor = event[1] if monitor in trigMonitorMap.keys(): thread = trigMonitorMap[monitor] else: continue if not isRunning(thread, threadDict): startMonitor(threadDict, trigEventMap[monitor]) elif eventType == 'stopMonitor': monitor = event[1] if monitor == 'devices': threadnames = [ 'deviceMonitor', 'volumeMonitor', 'logicalDiskRemoveMonitor', 'logicalDiskCreateMonitor' ] else: threadnames = [trigMonitorMap[monitor]] for threadname in threadnames: if isRunning(threadname, threadDict): threadDict[threadname].terminate() threadDict[threadname] = None elif eventType == 'Mail': #malformed emails would be a good way of crashing lockwatcher #be careful to valididate mail here validMail = True try: command, code = event[1].split(' ') eventQueue.put( ('Log', 'Received mail "%s %s"' % (command, code))) except: validMail = False #forgive bad command codes - crappy attack and causes #loop if we look at our returned emails with same sender/recv addresss if validMail == True: try: command = int(command) if command not in commandList: continue except: continue if validMail == True and sendemail.validHMAC(code, command) == True: executeRemoteCommand(command) badCommands = 0 #good command resets limit else: badCommands += 1 result = sendemail.sendEmail( "Command failed", "Bad command or authentication code received: %s" % str(event[1])) if result != True: eventQueue.put( ('Log', 'Mail send failed: %s' % result)) eventQueue.put(( 'Log', 'Mail not authenticated or bad command: "%s". Ensure clocks are synchronised.' % str(event[1]))) badCommandLimit = int( fileconfig.config.get('EMAIL', 'BAD_COMMAND_LIMIT')) if badCommandLimit > 0 and badCommands >= badCommandLimit: addLogEntry(str(event[1]), listeners) if shutdownActivated == False: shutdownActivated = True AFroutines.emergency() continue elif eventType == 'reloadConfig': fileconfig.reloadConfig() if isRunning('keyboardMonitor', threadDict): threadDict['keyboardMonitor'].reloadConfig() #eventQueue.put(('Log','Config reload forced')) #debugmode elif eventType == 'newListener': port = int(event[1]) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) eventQueue.put( ('Log', 'Lockwatcher connected to new configuration client')) try: s.connect(('127.0.0.1', port)) except: eventQueue.put( ('Log', 'Error: Failed to connect to client port: ' + str(port))) continue s.send(b'True@@') listeners.append(s) else: eventQueue.put( ('Log', 'Error: Unknown event in queue: ' + str(event)))
def run(self): if fileconfig.config.get('TRIGGERS','debuglog') == 'True': global VERBOSELOGS VERBOSELOGS = True debugLog('Lockwatcher Started') global startupTime startupTime = time.time() #send log/status updates to connections in here - for config programs listeners = [] confMonThread = configMonitor() confMonThread.start() LOCKED = fileconfig.config.get('TRIGGERS','lockedtriggers').split(',') ALWAYS = fileconfig.config.get('TRIGGERS','alwaystriggers').split(',') ACTIVE = LOCKED+ALWAYS global eventQueue eventQueue = Queue.Queue() threadStatuses = {} threadDict = {} for trigger in ACTIVE: if trigger != '': startMonitor(threadDict,trigger) if fileconfig.config.get('EMAIL','ENABLE_REMOTE') == 'True': startMonitor(threadDict,'email') #new month, new log logPath = fileconfig.config.get('TRIGGERS','logfile') if os.path.exists(logPath): creationTime = time.ctime(os.path.getctime(logPath)) creationMonth = datetime.datetime.strptime(creationTime, "%a %b %d %H:%M:%S %Y") monthNow = time.strftime('%m %Y') if creationMonth != monthNow: try: open(logPath, 'w').close() except: pass eventQueue.put(('Log','Lockwatcher monitoring started')) badCommands = 0 shutdownActivated = False while True: event = eventQueue.get(block=True, timeout=None) debugLog('Event in queue: '+str(event)) eventType = event[0] #--------------trigger activated under shutdown conditions if eventType == 'Kill': eventReason = event[1] #don't trigger multiple shutdowns but keep logging while we can if shutdownActivated == False: shutdownActivated = True if fileconfig.config.get('EMAIL','email_alert') == 'True' and \ 'Kill switch' not in eventReason: try: #has a 4 second timeout for blocking operations result = sendemail.sendEmail('Emergency shutdown triggered',eventReason) if result != True: eventQueue.put(('Log','Mail send failed: %s'%result)) except: pass #email failed, oh well. AFroutines.emergency() #--------------thread status changed, inform any listeners elif eventType == 'Status': #if self.statuses != None: self.statuses[event[1]].set(event[2]) threadStatuses[event[1]] = event[2] msg = 'Status::%s::%s'%(event[1],event[2]) broadcast(listeners,msg) #-----------config programs can request all the current statuses elif eventType == 'getStatuses': msg = 'AllStatuses::' for name,value in threadStatuses.items(): msg = msg+ '%s::%s|'%(name,value) msg = msg[:-1] broadcast(listeners,msg) #--------------add to log file + listener log window if they exist elif eventType == 'Log': addLogEntry(str(event[1]),listeners) elif eventType == 'stop': broadcast(listeners,'Shutdown') for threadname in threadDict.keys(): if isRunning(threadname,threadDict): threadDict[threadname].terminate() confMonThread.terminate() time.sleep(1) #give threads time to shutdown return elif eventType == 'startMonitor': monitor=event[1] if monitor in trigMonitorMap.keys(): thread = trigMonitorMap[monitor] else: continue if not isRunning(thread,threadDict): startMonitor(threadDict,trigEventMap[monitor]) elif eventType == 'stopMonitor': monitor = event[1] if monitor == 'devices': threadnames = ['deviceMonitor','volumeMonitor', 'logicalDiskRemoveMonitor','logicalDiskCreateMonitor'] else: threadnames = [trigMonitorMap[monitor]] for threadname in threadnames: if isRunning(threadname,threadDict): threadDict[threadname].terminate() threadDict[threadname] = None elif eventType == 'Mail': #malformed emails would be a good way of crashing lockwatcher #be careful to valididate mail here validMail = True try: command, code = event[1].split(' ') eventQueue.put(('Log','Received mail "%s %s"'%(command,code))) except: validMail = False #forgive bad command codes - crappy attack and causes #loop if we look at our returned emails with same sender/recv addresss if validMail == True: try: command = int(command) if command not in commandList: continue except: continue if validMail == True and sendemail.validHMAC(code,command) == True: executeRemoteCommand(command) badCommands = 0 #good command resets limit else: badCommands += 1 result = sendemail.sendEmail("Command failed","Bad command or authentication code received: %s"%str(event[1])) if result != True: eventQueue.put(('Log','Mail send failed: %s'%result)) eventQueue.put(('Log','Mail not authenticated or bad command: "%s". Ensure clocks are synchronised.'%str(event[1]))) badCommandLimit = int(fileconfig.config.get('EMAIL','BAD_COMMAND_LIMIT')) if badCommandLimit > 0 and badCommands >= badCommandLimit: addLogEntry(str(event[1]),listeners) if shutdownActivated == False: shutdownActivated = True AFroutines.emergency() continue elif eventType == 'reloadConfig': fileconfig.reloadConfig() if isRunning('keyboardMonitor',threadDict): threadDict['keyboardMonitor'].reloadConfig() #eventQueue.put(('Log','Config reload forced')) #debugmode elif eventType == 'newListener': port = int(event[1]) s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) eventQueue.put(('Log','Lockwatcher connected to new configuration client')) try: s.connect( ('127.0.0.1', port) ) except: eventQueue.put(('Log','Error: Failed to connect to client port: '+str(port))) continue s.send(b'True@@') listeners.append(s) else: eventQueue.put(('Log','Error: Unknown event in queue: '+str(event)))