From 6f3f573f612d6b29b640069b3748e88428f7808b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Thu, 28 Nov 2019 14:11:55 +0100 Subject: [PATCH] Advancing on actor --- actor/deps.txt | 1 + actor/src/udsactor/linux/__main__.py | 75 +++++++++++++ actor/src/udsactor/linux/operations.py | 54 +-------- actor/src/udsactor/linux/renamer/__init__.py | 3 + actor/src/udsactor/linux/renamer/common.py | 8 -- .../linux/{UDSActorService.py => service.py} | 55 ++------- actor/src/udsactor/linux/xss.py | 105 ++++++++++++++++++ actor/src/udsactor/service.py | 2 +- actor/src/udsactor/windows/__main__.py | 37 ++++++ .../{UDSActorService.py => service.py} | 5 - 10 files changed, 231 insertions(+), 114 deletions(-) create mode 100644 actor/src/udsactor/linux/__main__.py rename actor/src/udsactor/linux/{UDSActorService.py => service.py} (77%) create mode 100644 actor/src/udsactor/linux/xss.py create mode 100644 actor/src/udsactor/windows/__main__.py rename actor/src/udsactor/windows/{UDSActorService.py => service.py} (99%) diff --git a/actor/deps.txt b/actor/deps.txt index 8696e6b3..571b753d 100644 --- a/actor/deps.txt +++ b/actor/deps.txt @@ -1,3 +1,4 @@ Linux: python3-prctl (recommended, but not required in fact) +python3-pyqt5 diff --git a/actor/src/udsactor/linux/__main__.py b/actor/src/udsactor/linux/__main__.py new file mode 100644 index 00000000..7160e412 --- /dev/null +++ b/actor/src/udsactor/linux/__main__.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014-2019 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 +''' +import sys + +from ..log import logger +from .service import UDSActorSvc + +def usage(): + sys.stderr.write('usage: udsactor start|stop|restart|login "username"|logout "username"\n') + sys.exit(2) + + +logger.setLevel(20000) + +if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'): + logger.debug('Running client udsactor') + # client = None + # try: + # client = ipc.ClientIPC(IPC_PORT) + # if 'login' == sys.argv[1]: + # client.sendLogin(sys.argv[2]) + # sys.exit(0) + # elif 'logout' == sys.argv[1]: + # client.sendLogout(sys.argv[2]) + # sys.exit(0) + # else: + # usage() + # except Exception as e: + # logger.error(e) + sys.exit(0) +elif len(sys.argv) != 2: + usage() + +daemonSvr = UDSActorSvc() +if len(sys.argv) == 2: + if sys.argv[1] == 'start': + daemonSvr.start() + elif sys.argv[1] == 'stop': + daemonSvr.stop() + elif sys.argv[1] == 'restart': + daemonSvr.restart() + else: + usage() + sys.exit(0) +else: + usage() diff --git a/actor/src/udsactor/linux/operations.py b/actor/src/udsactor/linux/operations.py index 7c93f5e8..29d52ecc 100644 --- a/actor/src/udsactor/linux/operations.py +++ b/actor/src/udsactor/linux/operations.py @@ -34,8 +34,6 @@ import platform import socket import fcntl import os -import ctypes -import ctypes.util import subprocess import struct import array @@ -44,6 +42,7 @@ import typing from .. import types from .renamer import rename +from . import xss def _getMacAddr(ifname: str) -> typing.Optional[str]: @@ -106,7 +105,6 @@ def _getIpAndMac(ifname: str) -> typing.Tuple[typing.Optional[str], typing.Optio ip, mac = _getIpAddr(ifname), _getMacAddr(ifname) return (ip, mac) - def checkPermissions() -> bool: return os.getuid() == 0 @@ -166,33 +164,6 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None: os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword)) -class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods - _fields_ = [('window', ctypes.c_long), - ('state', ctypes.c_int), - ('kind', ctypes.c_int), - ('til_or_since', ctypes.c_ulong), - ('idle', ctypes.c_ulong), - ('eventMask', ctypes.c_ulong)] - -# Initialize xlib & xss -try: - xlibPath = ctypes.util.find_library('X11') - xssPath = ctypes.util.find_library('Xss') - xlib = xss = None - if not xlibPath or not xssPath: - raise Exception() - xlib = ctypes.cdll.LoadLibrary(xlibPath) - xss = ctypes.cdll.LoadLibrary(xssPath) - - # Fix result type to XScreenSaverInfo Structure - xss.XScreenSaverQueryExtension.restype = ctypes.c_int - xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure - display = xlib.XOpenDisplay(None) - xssInfo = xss.XScreenSaverAllocInfo() -except Exception: # Libraries not accesible, not found or whatever.. - xlib = xss = display = xssInfo = None - - def initIdleDuration(atLeastSeconds: int) -> None: subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)]) # And now reset it @@ -200,28 +171,7 @@ def initIdleDuration(atLeastSeconds: int) -> None: def getIdleDuration() -> float: - ''' - Returns idle duration, in seconds - ''' - if xlib is None or xss is None: - return 0 # Libraries not available - - event_base = ctypes.c_int() - error_base = ctypes.c_int() - - available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base)) - - if available != 1: - return 0 # No screen saver is available, no way of getting idle - - xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo) - - # Centos seems to set state to 1?? (weird, but it's happening don't know why... will try this way) - if xssInfo.contents.state != 0 and 'centos' not in getLinuxOs().lower().strip(): - return 3600 * 100 * 1000 # If screen saver is active, return a high enough value - - return xssInfo.contents.idle / 1000.0 - + return xss.getIdleDuration() def getCurrentUser() -> str: ''' diff --git a/actor/src/udsactor/linux/renamer/__init__.py b/actor/src/udsactor/linux/renamer/__init__.py index 27932c9c..6792e346 100644 --- a/actor/src/udsactor/linux/renamer/__init__.py +++ b/actor/src/udsactor/linux/renamer/__init__.py @@ -30,3 +30,6 @@ @author: Adolfo Gómez, dkmaster at dkmon dot com ''' from .common import rename + +# Import packages +from . import debian, opensuse, redhat diff --git a/actor/src/udsactor/linux/renamer/common.py b/actor/src/udsactor/linux/renamer/common.py index 8b567427..f63d53e9 100644 --- a/actor/src/udsactor/linux/renamer/common.py +++ b/actor/src/udsactor/linux/renamer/common.py @@ -49,11 +49,3 @@ def rename(newName: str) -> bool: logger.info('Renamer for platform "{0}" not found, tryin debian renamer'.format(distribution)) return renamers['debian'](newName) - -# Do load of packages -def _init(): - pkgpath = os.path.dirname(sys.modules[__name__].__file__) - for _, name, _ in pkgutil.iter_modules([pkgpath]): - __import__(__name__ + '.' + name, globals(), locals()) - -_init() \ No newline at end of file diff --git a/actor/src/udsactor/linux/UDSActorService.py b/actor/src/udsactor/linux/service.py similarity index 77% rename from actor/src/udsactor/linux/UDSActorService.py rename to actor/src/udsactor/linux/service.py index 54847b82..223a517f 100644 --- a/actor/src/udsactor/linux/UDSActorService.py +++ b/actor/src/udsactor/linux/service.py @@ -29,7 +29,6 @@ ''' @author: Adolfo Gómez, dkmaster at dkmon dot com ''' -import sys import signal import typing @@ -57,10 +56,9 @@ class UDSActorSvc(daemon.Daemon, CommonService): signal.signal(signal.SIGTERM, self.markForExit) - def markForExit(self, signum, frame): + def markForExit(self, signum, frame) -> None: self._isAlive = False - def rename( # pylint: disable=unused-argument self, name: str, @@ -78,6 +76,8 @@ class UDSActorSvc(daemon.Daemon, CommonService): logger.info('Computer name is already {}'.format(hostName)) return + logger.debug('Data: {}'.format((name, userName, oldPassword, newPassword))) + # Check for password change request for an user if userName and oldPassword and newPassword: logger.info('Setting password for user {}'.format(userName)) @@ -100,14 +100,15 @@ class UDSActorSvc(daemon.Daemon, CommonService): ) -> None: logger.fatal('Join domain is not supported on linux platforms right now') - def run(self): - logger.debug('Running Daemon') + def run(self) -> None: + logger.debug('Running Daemon: {}'.format(self._isAlive)) set_proctitle('UDSActorDaemon') # Linux daemon will continue running unless something is requested to if not self.initialize(): return # Stop daemon if initializes told to do so + logger.debug('Initialized, setting ready') # Initialization is done, set machine to ready for UDS, communicate urls, etc... self.setReady() @@ -117,7 +118,7 @@ class UDSActorSvc(daemon.Daemon, CommonService): # Counter used to check ip changes only once every 10 seconds, for # example counter = 0 - while self.isAlive: + while self._isAlive: counter += 1 if counter % 10 == 0: self.checkIpsChanged() @@ -125,45 +126,3 @@ class UDSActorSvc(daemon.Daemon, CommonService): self.doWait(1000) self.notifyStop() - - -def usage(): - sys.stderr.write("usage: {} start|stop|restart|login 'username'|logout 'username'\n".format(sys.argv[0])) - sys.exit(2) - - -if __name__ == '__main__': - logger.setLevel(20000) - - if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'): - logger.debug('Running client udsactor') - # client = None - # try: - # client = ipc.ClientIPC(IPC_PORT) - # if 'login' == sys.argv[1]: - # client.sendLogin(sys.argv[2]) - # sys.exit(0) - # elif 'logout' == sys.argv[1]: - # client.sendLogout(sys.argv[2]) - # sys.exit(0) - # else: - # usage() - # except Exception as e: - # logger.error(e) - elif len(sys.argv) != 2: - usage() - - logger.debug('Executing actor') - daemonSvr = UDSActorSvc() - if len(sys.argv) == 2: - if sys.argv[1] == 'start': - daemonSvr.start() - elif sys.argv[1] == 'stop': - daemonSvr.stop() - elif sys.argv[1] == 'restart': - daemonSvr.restart() - else: - usage() - sys.exit(0) - else: - usage() diff --git a/actor/src/udsactor/linux/xss.py b/actor/src/udsactor/linux/xss.py new file mode 100644 index 00000000..3c625770 --- /dev/null +++ b/actor/src/udsactor/linux/xss.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2014-2019 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 +''' +# pylint: disable=invalid-name +import ctypes +import ctypes.util +import subprocess + +xlib = None +xss = None +display = None +xssInfo = None +initialized = False + +class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods + _fields_ = [('window', ctypes.c_long), + ('state', ctypes.c_int), + ('kind', ctypes.c_int), + ('til_or_since', ctypes.c_ulong), + ('idle', ctypes.c_ulong), + ('eventMask', ctypes.c_ulong)] + +def _init(): + global xlib, xss, xssInfo, display, initialized # pylint: disable=global-statement + initialized = True + + # Initialize xlib & xss + try: + xlibPath = ctypes.util.find_library('X11') + xssPath = ctypes.util.find_library('Xss') + xlib = xss = None + if not xlibPath or not xssPath: + raise Exception() + xlib = ctypes.cdll.LoadLibrary(xlibPath) + xss = ctypes.cdll.LoadLibrary(xssPath) + + # Fix result type to XScreenSaverInfo Structure + xss.XScreenSaverQueryExtension.restype = ctypes.c_int + xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure + display = xlib.XOpenDisplay(None) + xssInfo = xss.XScreenSaverAllocInfo() + if display <= 0: + raise Exception() # Invalid display, not accesible + except Exception: # Libraries not accesible, not found or whatever.. + xlib = xss = display = xssInfo = None + + +def initIdleDuration(atLeastSeconds: int) -> None: + subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)]) + # And now reset it + subprocess.call(['/usr/bin/xset', 's', 'reset']) + + +def getIdleDuration() -> float: + ''' + Returns idle duration, in seconds + ''' + if not initialized: + _init() + + if not xlib or not xss or not xssInfo: + return 0 # Libraries not available + + event_base = ctypes.c_int() + error_base = ctypes.c_int() + + available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base)) + + if available != 1: + return 0 # No screen saver is available, no way of getting idle + + xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo) + + # Centos seems to set state to 1?? (weird, but it's happening don't know why... will try this way) + if xssInfo.contents.state == 1: # state = 1 means "active", so idle is not a valid state + return 3600 * 100 * 1000 # If screen saver is active, return a high enough value + + return xssInfo.contents.idle / 1000.0 diff --git a/actor/src/udsactor/service.py b/actor/src/udsactor/service.py index 5fef33dc..f3bbbc3d 100644 --- a/actor/src/udsactor/service.py +++ b/actor/src/udsactor/service.py @@ -69,7 +69,7 @@ class CommonService: @staticmethod def execute(cmdLine: str, section: str) -> bool: try: - res = subprocess.check_call(cmdLine) + res = subprocess.check_call(cmdLine, shell=True) except Exception as e: logger.error('Got exception executing: {} - {} - {}'.format(section, cmdLine, e)) return False diff --git a/actor/src/udsactor/windows/__main__.py b/actor/src/udsactor/windows/__main__.py new file mode 100644 index 00000000..dc11e707 --- /dev/null +++ b/actor/src/udsactor/windows/__main__.py @@ -0,0 +1,37 @@ +# -*- 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 +''' +# pylint: disable=invalid-name +import win32serviceutil + +from .service import UDSActorSvc + +if __name__ == '__main__': + win32serviceutil.HandleCommandLine(UDSActorSvc) diff --git a/actor/src/udsactor/windows/UDSActorService.py b/actor/src/udsactor/windows/service.py similarity index 99% rename from actor/src/udsactor/windows/UDSActorService.py rename to actor/src/udsactor/windows/service.py index 5ae7eb5e..f804c723 100644 --- a/actor/src/udsactor/windows/UDSActorService.py +++ b/actor/src/udsactor/windows/service.py @@ -364,8 +364,3 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService): self.endAPI() # And deinitializes REST api if needed self.notifyStop() - - -if __name__ == '__main__': - initCfg() - win32serviceutil.HandleCommandLine(UDSActorSvc)