From 1f519308a1f73562f4d7b502424a884de550a80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Mon, 10 Nov 2014 06:29:18 +0100 Subject: [PATCH] Started Linux Actors part --- actors/.gitignore | 2 + actors/src/.gitignore | 2 - actors/src/UDSActorConfig.py | 2 +- actors/src/UDSActorService.py | 20 ++++---- actors/src/{ => img}/uds-48x48.ico | Bin actors/src/{ => img}/uds.ico | Bin actors/src/udsactor/ipc.py | 19 ++++---- actors/src/udsactor/linux/store.py | 68 +++++++++++++++++++++++++++ actors/src/udsactor/log.py | 1 + actors/src/udsactor/store.py | 9 ++-- actors/src/udsactor/windows/log.py | 7 +-- actors/src/udsactor/windows/store.py | 28 ++++++----- 12 files changed, 117 insertions(+), 41 deletions(-) create mode 100644 actors/.gitignore rename actors/src/{ => img}/uds-48x48.ico (100%) rename actors/src/{ => img}/uds.ico (100%) create mode 100644 actors/src/udsactor/linux/store.py diff --git a/actors/.gitignore b/actors/.gitignore new file mode 100644 index 00000000..bbe31bbe --- /dev/null +++ b/actors/.gitignore @@ -0,0 +1,2 @@ +bin +*_enterprise* diff --git a/actors/src/.gitignore b/actors/src/.gitignore index 4a34b827..a964b0cc 100644 --- a/actors/src/.gitignore +++ b/actors/src/.gitignore @@ -1,5 +1,3 @@ build -dist -bin .idea *_enterprise* diff --git a/actors/src/UDSActorConfig.py b/actors/src/UDSActorConfig.py index ec2e8ad1..c86517f3 100644 --- a/actors/src/UDSActorConfig.py +++ b/actors/src/UDSActorConfig.py @@ -52,7 +52,7 @@ class MyForm(QtGui.QDialog): self.ui.host.setText(data.get('host', '')) self.ui.masterKey.setText(data.get('masterKey', '')) self.ui.useSSl.setCurrentIndex(1 if data.get('ssl', False) is True else 0) - self.ui.logLevelComboBox.setCurrentIndex(data.get('logLevel', 10000) / 10000 - 1) + self.ui.logLevelComboBox.setCurrentIndex(int(data.get('logLevel', '10000')) / 10000 - 1) def _getCfg(self): return { diff --git a/actors/src/UDSActorService.py b/actors/src/UDSActorService.py index 2102380d..aa7ff769 100644 --- a/actors/src/UDSActorService.py +++ b/actors/src/UDSActorService.py @@ -30,13 +30,14 @@ @author: Adolfo Gómez, dkmaster at dkmon dot com ''' from __future__ import unicode_literals +# pylint: disable=unused-wildcard-import, wildcard-import -import win32serviceutil -import win32service -import win32event -import win32com.client -import pythoncom -import servicemanager +import win32serviceutil # @UnresolvedImport, pylint: disable=import-error +import win32service # @UnresolvedImport, pylint: disable=import-error +import win32event # @UnresolvedImport, pylint: disable=import-error +import win32com.client # @UnresolvedImport, @UnusedImport, pylint: disable=import-error +import pythoncom # @UnresolvedImport, pylint: disable=import-error +import servicemanager # @UnresolvedImport, pylint: disable=import-error import socket import random @@ -47,13 +48,14 @@ from udsactor import operations from udsactor import httpserver from udsactor import ipc -from udsactor.windows.SENS import * +from udsactor.windows.SENS import * # @UnusedWildImport from udsactor.log import logger IPC_PORT = 39188 cfg = None + def initCfg(): global cfg cfg = store.readConfig() @@ -281,7 +283,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework): operations.reboot() except Exception as e: logger.error('Exception on reboot: {}'.format(e.message)) - return False # Stops service + return False # Stops service return True @@ -381,7 +383,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework): # Process SENS messages, This will be a bit asyncronous (1 second # delay) pythoncom.PumpWaitingMessages() - #if counter % 10 == 0: + # if counter % 10 == 0: # self.checkIpsChanged() # In milliseconds, will break win32event.WaitForSingleObject(self.hWaitStop, 1000) diff --git a/actors/src/uds-48x48.ico b/actors/src/img/uds-48x48.ico similarity index 100% rename from actors/src/uds-48x48.ico rename to actors/src/img/uds-48x48.ico diff --git a/actors/src/uds.ico b/actors/src/img/uds.ico similarity index 100% rename from actors/src/uds.ico rename to actors/src/img/uds.ico diff --git a/actors/src/udsactor/ipc.py b/actors/src/udsactor/ipc.py index 22e467e4..6fa9a544 100644 --- a/actors/src/udsactor/ipc.py +++ b/actors/src/udsactor/ipc.py @@ -46,7 +46,7 @@ from udsactor.log import logger # Message_id Data Action # ------------ -------- -------------------------- # MSG_LOGOFF None Logout user from session -# MSG_MESSAGE message,level Display a message with level (INFO, WARN, ERROR, FATAL) # TODO: Include levle, right now only has message +# MSG_MESSAGE message,level Display a message with level (INFO, WARN, ERROR, FATAL) # TODO: Include level, right now only has message # MSG_SCRIPT python script Execute an specific python script INSIDE CLIENT environment (this messages is not sent right now) # # All messages are in the form: @@ -64,7 +64,8 @@ VALID_MESSAGES = (MSG_LOGOFF, MSG_MESSAGE, MSG_SCRIPT, MSG_INFORMATION) REQ_INFORMATION = 0xAA -MAGIC = b'\x55\x44\x53\x00' # UDS in hexa with a padded 0 to the ridght +MAGIC = b'\x55\x44\x53\x00' # UDS in hexa with a padded 0 to the right + class ClientProcessor(threading.Thread): def __init__(self, parent, clientSocket): @@ -85,7 +86,7 @@ class ClientProcessor(threading.Thread): while self.running: try: while True: - buf = self.clientSocket.recv(512) # Empty buffer, this is set as non-blocking + buf = self.clientSocket.recv(512) # Empty buffer, this is set as non-blocking if buf == b'': # No data break for b in buf: @@ -110,7 +111,7 @@ class ClientProcessor(threading.Thread): try: m = msg[1] if msg[1] is not None else b'' l = len(m) - data = MAGIC + chr(msg[0]) + chr(l&0xFF) + chr(l>>8) + m + data = MAGIC + chr(msg[0]) + chr(l & 0xFF) + chr(l >> 8) + m try: self.clientSocket.sendall(data) except socket.error as e: @@ -236,13 +237,13 @@ class ClientIPC(threading.Thread): Override this method to automatically get notified on new message received. Message is at self.messages queue ''' - pass # Messa + pass # Messa def receiveBytes(self, number): msg = b'' while self.running and len(msg) < number: try: - buf = self.clientSocket.recv(number-len(msg)) + buf = self.clientSocket.recv(number - len(msg)) if buf == b'': self.running = False break @@ -268,7 +269,7 @@ class ClientIPC(threading.Thread): # We look for magic message header while self.running: # Wait for MAGIC try: - buf = self.clientSocket.recv(len(MAGIC)-len(msg)) + buf = self.clientSocket.recv(len(MAGIC) - len(msg)) if buf == b'': self.running = False break @@ -279,7 +280,7 @@ class ClientIPC(threading.Thread): msg = msg[1:] continue break - except socket.timeout: # Timeout is here so we can get stop thread + except socket.timeout: # Timeout is here so we can get stop thread continue # Now we get message basic data (msg + datalen) @@ -290,7 +291,7 @@ class ClientIPC(threading.Thread): continue msgId = ord(msg[0]) - dataLen = ord(msg[1]) + (ord(msg[2])<<8) + dataLen = ord(msg[1]) + (ord(msg[2]) << 8) if msgId not in VALID_MESSAGES: raise Exception('Invalid message id: {}'.format(msgId)) diff --git a/actors/src/udsactor/linux/store.py b/actors/src/udsactor/linux/store.py new file mode 100644 index 00000000..34ec4cbc --- /dev/null +++ b/actors/src/udsactor/linux/store.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +''' +@author: Adolfo Gómez, dkmaster at dkmon dot com +''' +from __future__ import unicode_literals + +import six +import os + +DEBUG = True + +CONFIGFILE = '/etc/udsactor/udsactor.cfg' if DEBUG is False else '/tmp/udsactor.cfg' + + +def checkPermissions(): + return True if DEBUG else os.getuid() == 0 + + +def readConfig(): + res = {} + try: + cfg = six.moves.configparser.SafeConfigParser() # @UndefinedVariable + cfg.read(CONFIGFILE) + # Just reads 'uds' section + for key in cfg.options('uds'): + res[key] = cfg.get('uds', key) + except Exception: + pass + + return res + + +def writeConfig(data): + cfg = six.moves.configparser.SafeConfigParser() # @UndefinedVariable + cfg.add_section('uds') + for key, val in data.iteritems(): + cfg.set('uds', key, unicode(val)) + with file(CONFIGFILE, 'w') as f: + cfg.write(f) + + os.chmod(CONFIGFILE, 0600) diff --git a/actors/src/udsactor/log.py b/actors/src/udsactor/log.py index d9b416af..76c6c350 100644 --- a/actors/src/udsactor/log.py +++ b/actors/src/udsactor/log.py @@ -40,6 +40,7 @@ else: # Valid logging levels, from UDS Broker (uds.core.utils.log) OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in xrange(6)) + class Logger(object): def __init__(self): self.logLevel = OTHER diff --git a/actors/src/udsactor/store.py b/actors/src/udsactor/store.py index aed18e07..6281eaa8 100644 --- a/actors/src/udsactor/store.py +++ b/actors/src/udsactor/store.py @@ -29,14 +29,11 @@ ''' @author: Adolfo Gómez, dkmaster at dkmon dot com ''' -# pylint: disable=unused-wildcard-import,wildcard-import +# pylint: disable=unused-wildcard-import, wildcard-import from __future__ import unicode_literals import sys if sys.platform == 'win32': - from udsactor.windows.store import * + from udsactor.windows.store import * # @UnusedWildImport else: - pass - - - + from udsactor.linux.store import * # @UnusedWildImport diff --git a/actors/src/udsactor/windows/log.py b/actors/src/udsactor/windows/log.py index 73f8c8ac..97d57887 100644 --- a/actors/src/udsactor/windows/log.py +++ b/actors/src/udsactor/windows/log.py @@ -31,7 +31,7 @@ ''' from __future__ import unicode_literals -import servicemanager +import servicemanager # @UnresolvedImport, pylint: disable=import-error import logging import os import tempfile @@ -39,6 +39,7 @@ import tempfile # Valid logging levels, from UDS Broker (uds.core.utils.log) OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in xrange(6)) + class LocalLogger(object): def __init__(self): # tempdir is different for "user application" and "service" @@ -57,14 +58,14 @@ class LocalLogger(object): # our loglevels are 10000 (other), 20000 (debug), .... # logging levels are 10 (debug), 20 (info) # OTHER = logging.NOTSET - self.logger.log(level/1000-10, message) + self.logger.log(level / 1000 - 10, message) if level < INFO or self.serviceLogger is False: # Only information and above will be on event log return if level < WARN: # Info servicemanager.LogInfoMsg(message) - elif level < ERROR: # WARN + elif level < ERROR: # WARN servicemanager.LogWarningMsg(message) else: # Error & Fatal servicemanager.LogErrorMsg(message) diff --git a/actors/src/udsactor/windows/store.py b/actors/src/udsactor/windows/store.py index d0138cd0..6e4c2026 100644 --- a/actors/src/udsactor/windows/store.py +++ b/actors/src/udsactor/windows/store.py @@ -31,26 +31,30 @@ ''' from __future__ import unicode_literals -from win32com.shell import shell -import _winreg as wreg -import win32security +from win32com.shell import shell # @UnresolvedImport, pylint: disable=import-error +import _winreg as wreg # @UnresolvedImport, pylint: disable=import-error +import win32security # @UnresolvedImport, pylint: disable=import-error import cPickle + # Can be changed to whatever we want, but registry key is protected by permissions def encoder(data): return data.encode('bz2') + def decoder(data): return data.decode('bz2') DEBUG = False path = 'Software\\UDSActor' -baseKey = wreg.HKEY_CURRENT_USER if DEBUG is True else wreg.HKEY_LOCAL_MACHINE +baseKey = wreg.HKEY_CURRENT_USER if DEBUG is True else wreg.HKEY_LOCAL_MACHINE # @UndefinedVariable + def checkPermissions(): return True if DEBUG else shell.IsUserAnAdmin() + def fixRegistryPermissions(handle): if DEBUG: return @@ -68,21 +72,23 @@ def fixRegistryPermissions(handle): win32security.DACL_SECURITY_INFORMATION | win32security.PROTECTED_DACL_SECURITY_INFORMATION, None, None, dacl, None) + def readConfig(): try: - key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_QUERY_VALUE) - data, _ = wreg.QueryValueEx(key, '') - wreg.CloseKey(key) + key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_QUERY_VALUE) # @UndefinedVariable + data, _ = wreg.QueryValueEx(key, '') # @UndefinedVariable + wreg.CloseKey(key) # @UndefinedVariable return cPickle.loads(decoder(data)) except Exception: return None + def writeConfig(data): try: - key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_ALL_ACCESS) + key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable except Exception: - key = wreg.CreateKeyEx(baseKey, path, 0, wreg.KEY_ALL_ACCESS) + key = wreg.CreateKeyEx(baseKey, path, 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable fixRegistryPermissions(key.handle) - wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, encoder(cPickle.dumps(data))) - wreg.CloseKey(key) + wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, encoder(cPickle.dumps(data))) # @UndefinedVariable + wreg.CloseKey(key) # @UndefinedVariable