diff --git a/actors/src/UDSActorUser.py b/actors/src/UDSActorUser.py index 3c5064187..3371a446d 100644 --- a/actors/src/UDSActorUser.py +++ b/actors/src/UDSActorUser.py @@ -40,8 +40,10 @@ from udsactor import ipc from udsactor import utils from udsactor.log import logger from udsactor.service import IPC_PORT +from udsactor import operations from about_dialog_ui import Ui_UDSAboutDialog + # About dialog class UDSAboutDialog(QtGui.QDialog): def __init__(self, parent=None): @@ -52,6 +54,7 @@ class UDSAboutDialog(QtGui.QDialog): def closeDialog(self): self.hide() + class MessagesProcessor(QtCore.QThread): logoff = QtCore.pyqtSignal(name='logoff') @@ -125,6 +128,7 @@ class UDSSystemTray(QtGui.QSystemTrayIcon): self.setContextMenu(self.menu) self.ipc = MessagesProcessor() self.ipc.start() + self.maxIdleTime = None self.ipc.displayMessage.connect(self.displayMessage) self.ipc.exit.connect(self.quit) @@ -152,6 +156,16 @@ class UDSSystemTray(QtGui.QSystemTrayIcon): print("Loggof --", self.counter) def information(self, info): + ''' + Invoked when received information from service + ''' + if 'idle' in info: + idle = int(info['idle']) + operations.initIdleDuration(idle) + self.maxIdleTime = idle + else: + self.maxIdleTime = None + self.counter += 1 print("Information:", info, '--', self.counter) diff --git a/actors/src/udsactor/REST.py b/actors/src/udsactor/REST.py index 73ffd2cff..9b9be8cc6 100644 --- a/actors/src/udsactor/REST.py +++ b/actors/src/udsactor/REST.py @@ -122,6 +122,7 @@ class Api(object): self.uuid = None self.mac = None self.url = "{}://{}/rest/actor/".format(('http', 'https')[ssl], self.host) + self.idle = None self.secretKey = six.text_type(uuid.uuid4()) self.newerRequestLib = requests.__version__.split('.') >= '1' # Disable logging requests messages except for errors, ... @@ -183,9 +184,18 @@ class Api(object): def init(self, ids): ''' Ids is a comma separated values indicating MAC=ip + Server returns: + uuid, mac + Optionally can return an third parameter, that is max "idle" request time ''' url = self._getUrl('init', key=self.masterKey, ids=ids) - self.uuid, self.mac = self._request(url)['result'] + res = self._request(url)['result'] + self.uuid, self.mac = res[0:2] + if len[res] >= 3: + self.idle = int(res[3]) + if self.idle <= 30: + self.idle = None # No values under 30 + return self.uuid def postMessage(self, msg, data, processData=True): diff --git a/actors/src/udsactor/ipc.py b/actors/src/udsactor/ipc.py index 8121a5d76..0f95aa76f 100644 --- a/actors/src/udsactor/ipc.py +++ b/actors/src/udsactor/ipc.py @@ -35,6 +35,7 @@ import threading import sys import six import traceback +import pickle from udsactor.utils import toUnicode from udsactor.log import logger @@ -239,6 +240,9 @@ class ServerIPC(threading.Thread): def sendScriptMessage(self, script): self.sendMessage(MSG_SCRIPT, script) + def sendInformationMessage(self, info): + self.sendMessage(MSG_INFORMATION, pickle.dumps(info)) + def cleanupFinishedThreads(self): ''' Cleans up current threads list diff --git a/actors/src/udsactor/linux/operations.py b/actors/src/udsactor/linux/operations.py index 60766cfa9..0356d1d9e 100644 --- a/actors/src/udsactor/linux/operations.py +++ b/actors/src/udsactor/linux/operations.py @@ -178,11 +178,17 @@ try: # Fix result type to XScreenSaverInfo Structure xss.XScreenSaverQueryExtension.restype = ctypes.c_int xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure - except Exception: # Libraries not accesible, not found or whatever.. xlib = xss = None +def initIdleDuration(atLeastSeconds): + ''' + On linux we set the screensaver to at least required seconds, or we never will get "idle" + ''' + os.system('/usr/bin/xset s {}'.format(atLeastSeconds + 30)) + + def getIdleDuration(): ''' Returns idle duration, in seconds diff --git a/actors/src/udsactor/service.py b/actors/src/udsactor/service.py index bfa94f8f5..9850069dd 100644 --- a/actors/src/udsactor/service.py +++ b/actors/src/udsactor/service.py @@ -218,7 +218,10 @@ class CommonService(object): elif msg == ipc.REQ_LOGOUT: self.api.logout(data) elif msg == ipc.REQ_INFORMATION: - logger.debug('Requested information') + info = {} + if self.api.idle is not None: + info['idle'] = self.api.idle + self.ipc.sendInformationMessage(info) def initIPC(self): # ****************************************** @@ -241,19 +244,19 @@ class CommonService(object): if self.ipc is not None: try: self.ipc.stop() - except: + except Exception: logger.error('Couln\'t stop ipc server') if self.httpServer is not None: try: self.httpServer.stop() - except: + except Exception: logger.error('Couln\'t stop REST server') def endAPI(self): if self.api is not None: try: self.api.notifyComm(None) - except: + except Exception: logger.error('Couln\'t remove comms url from broker') self.notifyStop() diff --git a/actors/src/udsactor/windows/operations.py b/actors/src/udsactor/windows/operations.py index d7929c312..dae0321a9 100644 --- a/actors/src/udsactor/windows/operations.py +++ b/actors/src/udsactor/windows/operations.py @@ -186,6 +186,13 @@ class LASTINPUTINFO(ctypes.Structure): ] +def initIdleDuration(atLeastSeconds): + ''' + In windows, there is no need to set screensaver + ''' + pass + + def getIdleDuration(): lastInputInfo = LASTINPUTINFO() lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo) diff --git a/server/src/uds/REST/methods/actor.py b/server/src/uds/REST/methods/actor.py index bad4acc19..4adc3f8c9 100644 --- a/server/src/uds/REST/methods/actor.py +++ b/server/src/uds/REST/methods/actor.py @@ -138,7 +138,10 @@ class Actor(Handler): else: # Set last seen actor version service.setProperty('actor_version', actorVersion) - return Actor.result((service.uuid, service.unique_id)) + maxIdle = None + if service.deployed_service.osmanager is not None: + maxIdle = service.deployed_service.osmanager.getInstance().maxIdle() + return Actor.result((service.uuid, service.unique_id, 0 if maxIdle is None else maxIdle)) raise RequestError('Invalid request') # Must be invoked as '/rest/actor/UUID/[message], with message data in post body diff --git a/server/src/uds/core/osmanagers/BaseOsManager.py b/server/src/uds/core/osmanagers/BaseOsManager.py index faf598754..28542f801 100644 --- a/server/src/uds/core/osmanagers/BaseOsManager.py +++ b/server/src/uds/core/osmanagers/BaseOsManager.py @@ -36,7 +36,7 @@ from django.utils.translation import ugettext_noop as _ from uds.core.util.State import State from uds.core import Module -__updated__ = '2014-11-27' +__updated__ = '2014-12-01' STORAGE_KEY = 'osmk' @@ -119,6 +119,13 @@ class OSManager(Module): ''' pass + def maxIdle(self): + ''' + If os manager request "max idle", this method will return a value different to None so actors will get informed on Connection + @return Must return None (default if not overriden), or a "max idle" in seconds + ''' + return None + @classmethod def transformsUserOrPasswordForService(cls): ''' @@ -137,7 +144,7 @@ class OSManager(Module): MUST Return: An array with 2 elements, [newUserName, newPassword]. - Default method simplt does nothing with in parameters, just returns it. (So, if your os manager does not need this, + Default method simply does nothing with in parameters, just returns it. (So, if your os manager does not need this, simply do not implement it) Note: This method is, right now, invoked by Transports directly. So if you implement a Transport, remember to invoke this diff --git a/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py b/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py index c87018427..5c2f68338 100644 --- a/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py +++ b/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py @@ -37,6 +37,7 @@ from uds.core.ui.UserInterface import gui from uds.core import osmanagers from uds.core.util.State import State from uds.core.util import log +import six import logging from uds.core.managers.UserServiceManager import UserServiceManager @@ -61,6 +62,9 @@ class LinuxOsManager(osmanagers.OSManager): ], defvalue='keep') + idle = gui.NumericField(label=_("Max.Idle time"), length=4, defvalue=-1, rdonly=False, order=11, + tooltip=_('Maximum idle time (in seconds) before session is automaticatlly closed to the user (<= 0 means no max idle time). Note that this value only applies to "removable" services'), required=True) + def __setProcessUnusedMachines(self): self.processUnusedMachines = self._onLogout == 'remove' @@ -68,8 +72,10 @@ class LinuxOsManager(osmanagers.OSManager): super(LinuxOsManager, self).__init__(environment, values) if values is not None: self._onLogout = values['onLogout'] + self._idle = int(values['idle']) else: self._onLogout = '' + self._idle = -1 self.__setProcessUnusedMachines() @@ -181,17 +187,27 @@ class LinuxOsManager(osmanagers.OSManager): logger.debug('Checking state for service {0}'.format(service)) return State.RUNNING + def maxIdle(self): + if self._onLogout == 'remove' or self._idle <= 0: + return None + + return self._idle + def marshal(self): ''' Serializes the os manager data so we can store it in database ''' - return '\t'.join(['v1', self._onLogout]) + return '\t'.join(['v2', self._onLogout, six.text_type(self._idle)]) def unmarshal(self, s): data = s.split('\t') if data[0] == 'v1': self._onLogout = data[1] + self._idle = -1 + elif data[0] == 'v2': + self._onLogout, self._idle = data[1], int(data[2]) + self.__setProcessUnusedMachines() def valuesDict(self): - return {'onLogout': self._onLogout} + return {'onLogout': self._onLogout, 'idle': self._idle} diff --git a/server/src/uds/osmanagers/LinuxOsManager/LinuxRandomPassOsManager.py b/server/src/uds/osmanagers/LinuxOsManager/LinuxRandomPassOsManager.py index 9bb5d1c2b..4511d4559 100644 --- a/server/src/uds/osmanagers/LinuxOsManager/LinuxRandomPassOsManager.py +++ b/server/src/uds/osmanagers/LinuxOsManager/LinuxRandomPassOsManager.py @@ -53,6 +53,7 @@ class LinuxRandomPassManager(LinuxOsManager): # Inherits base "onLogout" onLogout = LinuxOsManager.onLogout + idle = LinuxOsManager.idle def __init__(self, environment, values): super(LinuxRandomPassManager, self).__init__(environment, values) diff --git a/server/src/uds/osmanagers/WindowsOsManager/WinDomainOsManager.py b/server/src/uds/osmanagers/WindowsOsManager/WinDomainOsManager.py index 78be2066a..d3363a2ac 100644 --- a/server/src/uds/osmanagers/WindowsOsManager/WinDomainOsManager.py +++ b/server/src/uds/osmanagers/WindowsOsManager/WinDomainOsManager.py @@ -37,10 +37,11 @@ class WinDomainOsManager(WindowsOsManager): ou = gui.TextField(length=64, label=_('OU'), order=4, tooltip=_('Organizational unit where to add machines in domain (check it before using it)')) # Inherits base "onLogout" onLogout = WindowsOsManager.onLogout + idle = WindowsOsManager.idle def __init__(self, environment, values): super(WinDomainOsManager, self).__init__(environment, values) - if values != None: + if values is not None: if values['domain'] == '': raise osmanagers.OSManager.ValidationException(_('Must provide a domain!')) if values['domain'].find('.') == -1: diff --git a/server/src/uds/osmanagers/WindowsOsManager/WinRandomPassOsManager.py b/server/src/uds/osmanagers/WindowsOsManager/WinRandomPassOsManager.py index 8e8c9cf1b..12512755b 100644 --- a/server/src/uds/osmanagers/WindowsOsManager/WinRandomPassOsManager.py +++ b/server/src/uds/osmanagers/WindowsOsManager/WinRandomPassOsManager.py @@ -33,10 +33,11 @@ class WinRandomPassManager(WindowsOsManager): # Inherits base "onLogout" onLogout = WindowsOsManager.onLogout + idle = WindowsOsManager.idle def __init__(self, environment, values): super(WinRandomPassManager, self).__init__(environment, values) - if values != None: + if values is not None: if values['userAccount'] == '': raise osmanagers.OSManager.ValidationException(_('Must provide an user account!!!')) if values['password'] == '': diff --git a/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py b/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py index eb6fe4989..99f8498a7 100644 --- a/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py +++ b/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py @@ -55,6 +55,9 @@ class WindowsOsManager(osmanagers.OSManager): defvalue='keep' ) + idle = gui.NumericField(label=_("Max.Idle time"), length=4, defvalue=-1, rdonly=False, order=11, + tooltip=_('Maximum idle time (in seconds) before session is automaticatlly closed to the user (<= 0 means no max idle time). Note that this value only applies to "removable" services'), required=True) + @staticmethod def validateLen(length): try: @@ -72,8 +75,10 @@ class WindowsOsManager(osmanagers.OSManager): super(WindowsOsManager, self).__init__(environment, values) if values is not None: self._onLogout = values['onLogout'] + self._idle = int(values['idle']) else: self._onLogout = '' + self._idle = -1 self.__setProcessUnusedMachines() @@ -189,18 +194,27 @@ class WindowsOsManager(osmanagers.OSManager): logger.debug('Checking state for service {0}'.format(service)) return State.RUNNING + def maxIdle(self): + if self._onLogout == 'remove' or self._idle <= 0: + return None + + return self._idle + def marshal(self): ''' Serializes the os manager data so we can store it in database ''' - return '\t'.join(['v1', self._onLogout]) + return '\t'.join(['v2', self._onLogout, six.text_type(self._idle)]) def unmarshal(self, s): data = s.split('\t') if data[0] == 'v1': self._onLogout = data[1] + self._idle = -1 + elif data[0] == 'v2': + self._onLogout, self._idle = data[1], int(data[2]) self.__setProcessUnusedMachines() def valuesDict(self): - return {'onLogout': self._onLogout} + return {'onLogout': self._onLogout, 'idle': self._idle}