Example #1
0
    def stop(self):
        """
        Stop the daemon
        """
        # Get the pid from the pidfile
        try:
            pf = open(self.pidfile, 'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None

        if pid is None:
            message = "pidfile {} does not exist. Daemon not running?\n".format(self.pidfile)
            logger.info(message)
            # sys.stderr.write(message)
            return  # not an error in a restart

        # Try killing the daemon process
        try:
            while True:
                os.kill(pid, SIGTERM)
                time.sleep(1)
        except OSError as err:
            if err.errno == 3:  # No such process
                if os.path.exists(self.pidfile):
                    os.remove(self.pidfile)
            else:
                sys.stderr.write(err)
                sys.exit(1)
Example #2
0
    def clientMessageProcessor(self, msg, data):
        logger.debug('Got message {}'.format(msg))
        if self.api is None:
            logger.info('Rest api not ready')
            return

        if msg == ipc.REQ_LOGIN:
            res = self.api.login(data).split('\t')
            # third parameter, if exists, sets maxSession duration to this.
            # First & second parameters are ip & hostname of connection source
            if len(res) >= 3:
                self.api.maxSession = int(res[2])  # Third parameter is max session duration
                msg = ipc.REQ_INFORMATION  # Senf information, requested or not, to client on login notification
        elif msg == ipc.REQ_LOGOUT:
            self.api.logout(data)
            self.onLogout(data)
        elif msg == ipc.REQ_INFORMATION:
            info = {}
            if self.api.idle is not None:
                info['idle'] = self.api.idle
            if self.api.maxSession is not None:
                info['maxSession'] = self.api.maxSession
            self.ipc.sendInformationMessage(info)
        elif msg == ipc.REQ_TICKET:
            d = json.loads('data')
            try:
                result = self.api.getTicket(d['ticketId'], d['secure'])
                self.ipc.sendTicketMessage(result)
            except Exception:
                logger.exception('Getting ticket')
                self.ipc.sendTicketMessage({'error': 'invalid ticket'})
Example #3
0
def rename(newName):
    distribution = platform.linux_distribution()[0].lower().strip()
    if distribution in renamers:
        return renamers[distribution](newName)

    # Try Debian renamer, simplest one
    logger.info('Renamer for platform "{0}" not found, tryin debian renamer'.format(distribution))
    return renamers['debian'](newName)
Example #4
0
 def joinDomain(self, name, domain, ou, account, password):
     ver = operations.getWindowsVersion()
     ver = ver[0] * 10 + ver[1]
     logger.info('Starting joining domain {} with name {} (detected operating version: {})'.format(
         domain, name, ver))
     # Accepts one step joinDomain, also remember XP is no more supported by
     # microsoft, but this also must works with it because will do a "multi
     # step" join
     if ver >= 60:
         self.oneStepJoin(name, domain, ou, account, password)
     else:
         self.multiStepJoin(name, domain, ou, account, password)
Example #5
0
 def testParameters(self):
     logger.debug('Testing connection')
     try:
         cfg = self._getCfg()
         api = REST.Api(
             cfg['host'], cfg['masterKey'], cfg['ssl'])
         api.test()
         QtGui.QMessageBox.information(
             self, 'Test Passed', 'The test was executed successfully', QtGui.QMessageBox.Ok)
         logger.info('Test was passed successfully')
     except Exception as e:
         logger.info('Test error: {}'.format(utils.exceptionToMessage(e)))
         QtGui.QMessageBox.critical(self, 'Test Error', utils.exceptionToMessage(e), QtGui.QMessageBox.Ok)
Example #6
0
    def initIPC(self):
        # ******************************************
        # * Initialize listener IPC & REST threads *
        # ******************************************
        logger.debug('Starting IPC listener at {}'.format(IPC_PORT))
        self.ipc = ipc.ServerIPC(IPC_PORT, clientMessageProcessor=self.clientMessageProcessor)
        self.ipc.start()

        if self.api.mac in self.knownIps:
            address = (self.knownIps[self.api.mac], random.randrange(40000, 44000))
            logger.info('Starting REST listener at {}'.format(address))
            self.httpServer = httpserver.HTTPServerThread(address, self)
            self.httpServer.start()
            # And notify it to broker
            self.api.notifyComm(self.httpServer.getServerUrl())
Example #7
0
 def checkIpsChanged(self):
     if self.api.uuid is None:
         return  # Not connected
     netInfo = tuple(operations.getNetworkInfo())
     for i in netInfo:
         # If at least one ip has changed
         if i.mac in self.knownIps and self.knownIps[i.mac] != i.ip:
             logger.info('Notifying ip change to broker (mac {}, from {} to {})'.format(i.mac, self.knownIps[i.mac], i.ip))
             try:
                 # Notifies all interfaces IPs
                 self.api.notifyIpChanges(((v.mac, v.ip) for v in netInfo))
                 # Regenerates Known ips
                 self.knownIps = dict(((i.mac, i.ip) for i in netInfo))
             except Exception as e:
                 logger.warn('Got an error notifiying IPs to broker: {} (will retry in a bit)'.format(e.message.decode('windows-1250', 'ignore')))
Example #8
0
    def joinDomain(self, name, domain, ou, account, password):
        ver = operations.getWindowsVersion()
        ver = ver[0] * 10 + ver[1]
        logger.debug('Starting joining domain {} with name {} (detected operating version: {})'.format(
            domain, name, ver))
        # If file c:\compat.bin exists, joind domain in two steps instead one

        # Accepts one step joinDomain, also remember XP is no more supported by
        # microsoft, but this also must works with it because will do a "multi
        # step" join
        if ver >= 60 and store.useOldJoinSystem() is False:
            self.oneStepJoin(name, domain, ou, account, password)
        else:
            logger.info('Using multiple step join because configuration requests to do so')
            self.multiStepJoin(name, domain, ou, account, password)
Example #9
0
    def execute(self, cmd, section):
        import os
        import subprocess
        import stat

        if os.path.isfile(cmd):
            if (os.stat(cmd).st_mode & stat.S_IXUSR) != 0:
                subprocess.call([cmd, ])
                return True
            else:
                logger.info('{} file exists but it it is not executable (needs execution permission by admin/root)'.format(section))
        else:
            logger.info('{} file not found & not executed'.format(section))

        return False
Example #10
0
    def clientMessageProcessor(self, msg, data):
        logger.debug('Got message {}'.format(msg))
        if self.api is None:
            logger.info('Rest api not ready')
            return

        if msg == ipc.REQ_LOGIN:
            self.api.login(data)
        elif msg == ipc.REQ_LOGOUT:
            self.api.logout(data)
            self.onLogout(data)
        elif msg == ipc.REQ_INFORMATION:
            info = {}
            if self.api.idle is not None:
                info['idle'] = self.api.idle
            self.ipc.sendInformationMessage(info)
Example #11
0
    def preConnect(self, user, protocol):
        logger.debug('Pre connect invoked')
        if protocol != 'rdp':  # If connection is not using rdp, skip adding user
            return 'ok'
        # Well known SSID for Remote Desktop Users
        REMOTE_USERS_SID = 'S-1-5-32-555'

        p = win32security.GetBinarySid(REMOTE_USERS_SID)
        groupName = win32security.LookupAccountSid(None, p)[0]

        useraAlreadyInGroup = False
        resumeHandle = 0
        while True:
            users, _, resumeHandle = win32net.NetLocalGroupGetMembers(None, groupName, 1, resumeHandle, 32768)
            if user.lower() in [u['name'].lower() for u in users]:
                useraAlreadyInGroup = True
                break
            if resumeHandle == 0:
                break

        if useraAlreadyInGroup is False:
            logger.debug('User not in group, adding it')
            self._user = user
            try:
                userSSID = win32security.LookupAccountName(None, user)[0]
                win32net.NetLocalGroupAddMembers(None, groupName, 0, [{'sid': userSSID}])
            except Exception as e:
                logger.error('Exception adding user to Remote Desktop Users: {}'.format(e))
        else:
            self._user = None
            logger.debug('User {} already in group'.format(user))

        # Now try to run pre connect command
        try:
            pre_cmd = store.preApplication()
            if os.path.isfile(pre_cmd):
                if (os.stat(pre_cmd).st_mode & stat.S_IXUSR) != 0:
                    subprocess.call([pre_cmd, user, protocol])
                else:
                    logger.info('PRECONNECT file exists but it it is not executable (needs execution permission by root)')
            else:
                logger.info('PRECONNECT file not found & not executed')
        except Exception as e:
            # Ignore output of execution command
            logger.error('Executing preconnect command give')

        return 'ok'
Example #12
0
 def multiStepJoin(self, name, domain, ou, account, password):
     currName = operations.getComputerName()
     if currName.lower() == name.lower():
         currDomain = operations.getDomainName()
         logger.debug('Name: "{}" vs "{}", Domain: "{}" vs "{}"'.format(currName.lower(), name.lower(), currDomain.lower(), domain.lower()))
         if currDomain is not None:
             logger.info(
                 'Machine {} is part of domain {}'.format(name, domain))
             self.setReady()
         else:
             operations.joinDomain(
                 domain, ou, account, password, executeInOneStep=False)
     else:
         operations.renameComputer(name)
         logger.info(
             'Rebooting computer got activate new name {}'.format(name))
         self.reboot()
Example #13
0
    def preConnect(self, user, protocol):
        '''
        Invoked when received a PRE Connection request via REST
        '''
        # Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
        # This will be executed only when machine gets "ready"
        try:

            if os.path.isfile(PRECONNECT_CMD):
                if (os.stat(PRECONNECT_CMD).st_mode & stat.S_IXUSR) != 0:
                    subprocess.call([PRECONNECT_CMD, user, protocol])
                else:
                    logger.info('PRECONNECT file exists but it it is not executable (needs execution permission by root)')
            else:
                logger.info('PRECONNECT file not found & not executed')
        except Exception as e:
            # Ignore output of execution command
            logger.error('Executing preconnect command give')
Example #14
0
    def information(self, info):
        '''
        Invoked when received information from service
        '''
        logger.info('Got information message: {}'.format(info))
        if 'idle' in info:
            idle = int(info['idle'])
            operations.initIdleDuration(idle)
            self.maxIdleTime = idle
            logger.debug('Set screensaver launching to {}'.format(idle))
        else:
            self.maxIdleTime = None

        if 'maxSession' in info:
            maxSession = int(info['maxSession'])
            # operations.initMaxSession(maxSession)
            self.maxSessionTime = maxSession
            logger.debug('Set maxsession to {}'.format(maxSession))
Example #15
0
    def execute(self, cmdLine, section):
        cmd = shlex.split(cmdLine, posix=False)

        if os.path.isfile(cmd[0]):
            if (os.stat(cmd[0]).st_mode & stat.S_IXUSR) != 0:
                try:
                    res = subprocess.check_call(cmd)
                except Exception as e:
                    logger.error('Got exception executing: {} - {}'.format(cmdLine, e))
                    return False
                logger.info('Result of executing cmd was {}'.format(res))
                return True
            else:
                logger.error('{} file exists but it it is not executable (needs execution permission by admin/root)'.format(section))
        else:
            logger.error('{} file not found & not executed'.format(section))

        return False
Example #16
0
    def rename(self, name, user=None, oldPassword=None, newPassword=None):
        '''
        Renames the computer, and optionally sets a password for an user
        before this
        '''

        # Check for password change request for an user
        if user is not None:
            logger.info('Setting password for user {}'.format(user))
            try:
                operations.changeUserPassword(user, oldPassword, newPassword)
            except Exception as e:
                # We stop here without even renaming computer, because the
                # process has failed
                raise Exception(
                    'Could not change password for user {} (maybe invalid current password is configured at broker): {} '.format(user, unicode(e)))

        renamer.rename(name)
        self.setReady()
Example #17
0
 def multiStepJoin(self, name, domain, ou, account, password):
     currName = operations.getComputerName()
     if currName.lower() == name.lower():
         currDomain = operations.getDomainName()
         if currDomain is not None:
             # logger.debug('Name: "{}" vs "{}", Domain: "{}" vs "{}"'.format(currName.lower(), name.lower(), currDomain.lower(), domain.lower()))
             logger.info('Machine {} is part of domain {}'.format(
                 name, domain))
             self.setReady()
         else:
             operations.joinDomain(domain,
                                   ou,
                                   account,
                                   password,
                                   executeInOneStep=False)
             self.reboot()
     else:
         operations.renameComputer(name)
         logger.info(
             'Rebooting computer got activate new name {}'.format(name))
         self.reboot()
Example #18
0
    def execute(self, cmdLine, section):
        cmd = shlex.split(cmdLine, posix=False)

        if os.path.isfile(cmd[0]):
            if (os.stat(cmd[0]).st_mode & stat.S_IXUSR) != 0:
                try:
                    res = subprocess.check_call(cmd)
                except Exception as e:
                    logger.error('Got exception executing: {} - {}'.format(
                        cmdLine, e))
                    return False
                logger.info('Result of executing cmd was {}'.format(res))
                return True
            else:
                logger.error(
                    '{} file exists but it it is not executable (needs execution permission by admin/root)'
                    .format(section))
        else:
            logger.error('{} file not found & not executed'.format(section))

        return False
Example #19
0
    def rename(self, name, user=None, oldPassword=None, newPassword=None):
        '''
        Renames the computer, and optionally sets a password for an user
        before this
        '''
        hostName = operations.getComputerName()

        if hostName.lower() == name.lower():
            logger.info('Computer name is now {}'.format(hostName))
            self.setReady()
            return

        # Check for password change request for an user
        if user is not None:
            logger.info('Setting password for user {}'.format(user))
            try:
                operations.changeUserPassword(user, oldPassword, newPassword)
            except Exception as e:
                # We stop here without even renaming computer, because the
                # process has failed
                raise Exception(
                    'Could not change password for user {} (maybe invalid current password is configured at broker): {} '
                    .format(user, unicode(e)))

        operations.renameComputer(name)
        # Reboot just after renaming
        logger.info('Rebooting computer to activate new name {}'.format(name))
        self.reboot()
Example #20
0
    def rename(self, name, user=None, oldPassword=None, newPassword=None):
        '''
        Renames the computer, and optionally sets a password for an user
        before this
        '''
        hostName = operations.getComputerName()

        if hostName.lower() == name.lower():
            logger.info('Computer name is already {}'.format(hostName))
            self.setReady()
            return

        # Check for password change request for an user
        if user is not None:
            logger.info('Setting password for user {}'.format(user))
            try:
                operations.changeUserPassword(user, oldPassword, newPassword)
            except Exception as e:
                # We stop here without even renaming computer, because the
                # process has failed
                raise Exception(
                    'Could not change password for user {} (maybe invalid current password is configured at broker): {} '.format(user, unicode(e)))

        renamer.rename(name)

        if self.rebootMachineAfterOp is False:
            self.setReady()
        else:
            logger.info('Rebooting computer to activate new name {}'.format(name))
            self.reboot()
Example #21
0
    def preConnect(self, user, protocol):
        '''
        Invoked when received a PRE Connection request via REST
        '''
        # Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
        # This will be executed only when machine gets "ready"
        try:
            pre_cmd = store.preApplication()
            if os.path.isfile(pre_cmd):
                if (os.stat(pre_cmd).st_mode & stat.S_IXUSR) != 0:
                    subprocess.call([pre_cmd, user, protocol])
                else:
                    logger.info(
                        'PRECONNECT file exists but it it is not executable (needs execution permission by root)'
                    )
            else:
                logger.info('PRECONNECT file not found & not executed')
        except Exception:
            # Ignore output of execution command
            logger.error('Executing preconnect command give')

        return 'ok'
Example #22
0
    def checkIdle(self):
        if self.maxIdleTime is None:  # No idle check
            return

        if self.graceTimerShots > 0:
            self.graceTimerShots -= 1
            return

        idleTime = operations.getIdleDuration()
        remainingTime = self.maxIdleTime - idleTime

        if remainingTime > 300:  # Reset show Warning dialog if we have more than 5 minutes left
            self.showIdleWarn = True

        logger.debug('User has been idle for: {}'.format(idleTime))

        if remainingTime <= 0:
            logger.info('User has been idle for too long, notifying Broker that service can be reclaimed')
            self.quit()

        if self.showIdleWarn is True and remainingTime < 120:  # With two minutes, show a warning message
            self.showIdleWarn = False
            self.msgDlg.displayMessage("You have been idle for too long. The session will end if you don't resume operations")
Example #23
0
    def clientMessageProcessor(self, msg, data):
        logger.debug('Got message {}'.format(msg))
        if self.api is None:
            logger.info('Rest api not ready')
            return

        if msg == ipc.REQ_LOGIN:
            res = self.api.login(data).split('\t')
            # third parameter, if exists, sets maxSession duration to this.
            # First & second parameters are ip & hostname of connection source
            if len(res) >= 3:
                self.api.maxSession = int(
                    res[2])  # Third parameter is max session duration
                msg = ipc.REQ_INFORMATION  # Senf information, requested or not, to client on login notification
        if msg == ipc.REQ_LOGOUT:
            self.api.logout(data)
            self.onLogout(data)
        if msg == ipc.REQ_INFORMATION:
            info = {}
            if self.api.idle is not None:
                info['idle'] = self.api.idle
            if self.api.maxSession is not None:
                info['maxSession'] = self.api.maxSession
            self.ipc.sendInformationMessage(info)
Example #24
0
    def checkIpsChanged(self):
        if self.api is None or self.api.uuid is None:
            return  # Not connected
        netInfo = tuple(operations.getNetworkInfo())
        for i in netInfo:
            # If at least one ip has changed
            if i.mac in self.knownIps and self.knownIps[i.mac] != i.ip:
                logger.info('Notifying ip change to broker (mac {}, from {} to {})'.format(i.mac, self.knownIps[i.mac], i.ip))
                try:
                    # Notifies all interfaces IPs
                    self.api.notifyIpChanges(((v.mac, v.ip) for v in netInfo))

                    # Regenerates Known ips
                    self.knownIps = dict(((v.mac, v.ip) for v in netInfo))

                    # And notify new listening address to broker
                    address = (self.knownIps[self.api.mac], self.httpServer.getPort())
                    # And new listening address
                    self.httpServer.restart(address)
                    # sends notification
                    self.api.notifyComm(self.httpServer.getServerUrl())

                except Exception as e:
                    logger.warn('Got an error notifiying IPs to broker: {} (will retry in a bit)'.format(e.message.decode('windows-1250', 'ignore')))
Example #25
0
    def interactWithBroker(self):
        '''
        Returns True to continue to main loop, false to stop & exit service
        '''
        # If no configuration is found, stop service
        if cfg is None:
            logger.fatal('No configuration found, stopping service')
            return False

        self.api = REST.Api(cfg['host'], cfg['masterKey'], cfg['ssl'])

        # Wait for Broker to be ready
        counter = 0
        while self.isAlive:
            try:
                # getNetworkInfo is a generator function
                netInfo = tuple(operations.getNetworkInfo())
                self.knownIps = dict(((i.mac, i.ip) for i in netInfo))
                ids = ','.join([i.mac for i in netInfo])
                if ids == '':
                    # Wait for any network interface to be ready
                    logger.debug('No valid network interfaces found, retrying in a while...')
                    raise Exception()
                logger.debug('Ids: {}'.format(ids))
                self.api.init(ids)
                # Set remote logger to notify log info to broker
                logger.setRemoteLogger(self.api)

                break
            except REST.InvalidKeyError:
                logger.fatal('Can\'t sync with broker: Invalid broker Master Key')
                return False
            except REST.UnmanagedHostError:
                # Maybe interface that is registered with broker is not enabled already?
                # Right now, we thing that the interface connected to broker is
                # the interface that broker will know, let's see how this works
                logger.fatal('This host is not managed by UDS Broker (ids: {})'.format(ids))
                return False  # On unmanaged hosts, there is no reason right now to continue running
            except Exception as e:
                logger.debug('Exception on network info: retrying')
                # Any other error is expectable and recoverable, so let's wait a bit and retry again
                # but, if too many errors, will log it (one every minute, for
                # example)
                counter += 1
                if counter % 60 == 0:  # Every 5 minutes, raise a log
                    logger.info('Trying to inititialize connection with broker (last error: {})'.format(exceptionToMessage(e)))
                # Wait a bit before next check
                self.doWait(5000)

        # Now try to run the "runonce" element
        runOnce = store.runApplication()
        if runOnce is not None:
            if self.execute(runOnce, 'RunOnce') is True:
                # operations.reboot()
                return False

        # Broker connection is initialized, now get information about what to
        # do
        counter = 0
        while self.isAlive:
            try:
                logger.debug('Requesting information of what to do now')
                info = self.api.information()
                data = info.split('\r')
                if len(data) != 2:
                    logger.error('The format of the information message is not correct (got {})'.format(info))
                    raise Exception
                params = data[1].split('\t')
                if data[0] == 'rename':
                    try:
                        if len(params) == 1:  # Simple rename
                            logger.debug('Renaming computer to {}'.format(params[0]))
                            self.rename(params[0])
                        # Rename with change password for an user
                        elif len(params) == 4:
                            logger.debug('Renaming computer to {}'.format(params))
                            self.rename(params[0], params[1], params[2], params[3])
                        else:
                            logger.error('Got invalid parameter for rename operation: {}'.format(params))
                            return False
                        break
                    except Exception as e:
                        logger.error('Error at computer renaming stage: {}'.format(e.message))
                        return None  # Will retry complete broker connection if this point is reached
                elif data[0] == 'domain':
                    if len(params) != 5:
                        logger.error('Got invalid parameters for domain message: {}'.format(params))
                        return False  # Stop running service
                    self.joinDomain(params[0], params[1], params[2], params[3], params[4])
                    break
                else:
                    logger.error('Unrecognized action sent from broker: {}'.format(data[0]))
                    return False  # Stop running service
            except REST.UserServiceNotFoundError:
                logger.error('The host has lost the sync state with broker! (host uuid changed?)')
                return False
            except Exception as err:
                if counter % 60 == 0:
                    logger.warn('Too many retries in progress, though still trying (last error: {})'.format(exceptionToMessage(err)))
                counter += 1
                # Any other error is expectable and recoverable, so let's wait
                # a bit and retry again
                # Wait a bit before next check
                self.doWait(5000)

        if self.rebootRequested:
            try:
                operations.reboot()
            except Exception as e:
                logger.error('Exception on reboot: {}'.format(e.message))
            return False  # Stops service

        return True
Example #26
0
    def SvcDoRun(self):
        '''
        Main service loop
        '''
        try:
            initCfg()

            logger.debug('running SvcDoRun')
            servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                  servicemanager.PYS_SERVICE_STARTED,
                                  (self._svc_name_, ''))

            # call the CoInitialize to allow the registration to run in an other
            # thread
            logger.debug('Initializing com...')
            pythoncom.CoInitialize()

            # ********************************************************
            # * Ask brokers what to do before proceding to main loop *
            # ********************************************************
            while True:
                brokerConnected = self.interactWithBroker()
                if brokerConnected is False:
                    logger.debug(
                        'Interact with broker returned false, stopping service after a while'
                    )
                    self.notifyStop()
                    win32event.WaitForSingleObject(self.hWaitStop, 5000)
                    return
                elif brokerConnected is True:
                    break

                # If brokerConnected returns None, repeat the cycle
                self.doWait(16000)  # Wait for a looong while

            if self.interactWithBroker() is False:
                logger.debug(
                    'Interact with broker returned false, stopping service after a while'
                )
                self.notifyStop()
                win32event.WaitForSingleObject(self.hWaitStop, 5000)
                return

            if self.isAlive is False:
                logger.debug(
                    'The service is not alive after broker interaction, stopping it'
                )
                self.notifyStop()
                return

            if self.rebootRequested is True:
                logger.debug('Reboot has been requested, stopping service')
                self.notifyStop()
                return

            self.initIPC()
        except Exception:  # Any init exception wil be caught, service must be then restarted
            logger.exception()
            logger.debug('Exiting service with failure status')
            os._exit(-1)  # pylint: disable=protected-access

        # ********************************
        # * Registers SENS subscriptions *
        # ********************************
        logevent('Registering ISensLogon')
        subscription_guid = '{41099152-498E-11E4-8FD3-10FEED05884B}'
        sl = SensLogon(self)
        subscription_interface = pythoncom.WrapObject(sl)

        event_system = win32com.client.Dispatch(PROGID_EventSystem)

        event_subscription = win32com.client.Dispatch(PROGID_EventSubscription)
        event_subscription.EventClassID = SENSGUID_EVENTCLASS_LOGON
        event_subscription.PublisherID = SENSGUID_PUBLISHER
        event_subscription.SubscriptionName = 'UDS Actor subscription'
        event_subscription.SubscriptionID = subscription_guid
        event_subscription.SubscriberInterface = subscription_interface

        event_system.Store(PROGID_EventSubscription, event_subscription)

        logger.debug('Registered SENS, running main loop')

        # Execute script in c:\\windows\\post-uds.bat after interacting with broker, if no reboot is requested ofc
        # This will be executed only when machine gets "ready"
        try:
            if os.path.isfile(POST_CMD):
                subprocess.call([
                    POST_CMD,
                ])
            else:
                logger.info('POST file not found & not executed')
        except Exception as e:
            # Ignore output of execution command
            logger.error('Executing post command give')

        # *********************
        # * Main Service loop *
        # *********************
        # Counter used to check ip changes only once every 10 seconds, for
        # example
        counter = 0
        while self.isAlive:
            counter += 1
            # Process SENS messages, This will be a bit asyncronous (1 second
            # delay)
            pythoncom.PumpWaitingMessages()
            if counter >= 15:  # Once every 15 seconds
                counter = 0
                try:
                    self.checkIpsChanged()
                except Exception as e:
                    logger.error('Error checking ip change: {}'.format(e))
            # In milliseconds, will break
            win32event.WaitForSingleObject(self.hWaitStop, 1000)

        logger.debug('Exited main loop, deregistering SENS')

        # *******************************************
        # * Remove SENS subscription before exiting *
        # *******************************************
        event_system.Remove(PROGID_EventSubscription,
                            "SubscriptionID == " + subscription_guid)

        self.endIPC()  # Ends IPC servers
        self.endAPI()  # And deinitializes REST api if needed

        self.notifyStop()
Example #27
0
 def log_message(self, fmt, *args):
     logger.info('HTTP ' + fmt % args)
Example #28
0
    def SvcDoRun(self):  # pylint: disable=too-many-statements, too-many-branches
        '''
        Main service loop
        '''
        try:
            initCfg()

            logger.debug('running SvcDoRun')
            servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                  servicemanager.PYS_SERVICE_STARTED,
                                  (self._svc_name_, ''))

            # call the CoInitialize to allow the registration to run in an other
            # thread
            logger.debug('Initializing com...')
            pythoncom.CoInitialize()

            # ********************************************************
            # * Ask brokers what to do before proceding to main loop *
            # ********************************************************
            while True:
                brokerConnected = self.interactWithBroker()
                if brokerConnected is False:
                    logger.debug('Interact with broker returned false, stopping service after a while')
                    self.notifyStop()
                    win32event.WaitForSingleObject(self.hWaitStop, 5000)
                    return
                elif brokerConnected is True:
                    break

                # If brokerConnected returns None, repeat the cycle
                self.doWait(16000)  # Wait for a looong while

            if self.interactWithBroker() is False:
                logger.debug('Interact with broker returned false, stopping service after a while')
                self.notifyStop()
                win32event.WaitForSingleObject(self.hWaitStop, 5000)
                return

            if self.isAlive is False:
                logger.debug('The service is not alive after broker interaction, stopping it')
                self.notifyStop()
                return

            if self.rebootRequested is True:
                logger.debug('Reboot has been requested, stopping service')
                self.notifyStop()
                return

            self.initIPC()
        except Exception:  # Any init exception wil be caught, service must be then restarted
            logger.exception()
            logger.debug('Exiting service with failure status')
            os._exit(-1)  # pylint: disable=protected-access

        # ********************************
        # * Registers SENS subscriptions *
        # ********************************
        logevent('Registering ISensLogon')
        subscription_guid = '{41099152-498E-11E4-8FD3-10FEED05884B}'
        sl = SensLogon(self)
        subscription_interface = pythoncom.WrapObject(sl)

        event_system = win32com.client.Dispatch(PROGID_EventSystem)

        event_subscription = win32com.client.Dispatch(PROGID_EventSubscription)
        event_subscription.EventClassID = SENSGUID_EVENTCLASS_LOGON
        event_subscription.PublisherID = SENSGUID_PUBLISHER
        event_subscription.SubscriptionName = 'UDS Actor subscription'
        event_subscription.SubscriptionID = subscription_guid
        event_subscription.SubscriberInterface = subscription_interface

        event_system.Store(PROGID_EventSubscription, event_subscription)

        logger.debug('Registered SENS, running main loop')

        # Execute script in c:\\windows\\post-uds.bat after interacting with broker, if no reboot is requested ofc
        # This will be executed only when machine gets "ready"
        try:
            if os.path.isfile(POST_CMD):
                subprocess.call([POST_CMD, ])
            else:
                logger.info('POST file not found & not executed')
        except Exception as e:
            # Ignore output of execution command
            logger.error('Executing post command give')

        # *********************
        # * Main Service loop *
        # *********************
        # Counter used to check ip changes only once every 10 seconds, for
        # example
        counter = 0
        while self.isAlive:
            counter += 1
            # Process SENS messages, This will be a bit asyncronous (1 second
            # delay)
            pythoncom.PumpWaitingMessages()
            if counter >= 15:  # Once every 15 seconds
                counter = 0
                try:
                    self.checkIpsChanged()
                except Exception as e:
                    logger.error('Error checking ip change: {}'.format(e))
            # In milliseconds, will break
            win32event.WaitForSingleObject(self.hWaitStop, 1000)

        logger.debug('Exited main loop, deregistering SENS')

        # *******************************************
        # * Remove SENS subscription before exiting *
        # *******************************************
        event_system.Remove(
            PROGID_EventSubscription, "SubscriptionID == " + subscription_guid)

        self.endIPC()  # Ends IPC servers
        self.endAPI()  # And deinitializes REST api if needed

        self.notifyStop()
Example #29
0
    def run(self):
        cfg = initCfg()  # Gets a local copy of config to get "reboot"

        logger.debug('CFG: {}'.format(cfg))

        if cfg is not None:
            self.rebootMachineAfterOp = cfg.get('reboot', True)
        else:
            self.rebootMachineAfterOp = False

        logger.info('Reboot after is {}'.format(self.rebootMachineAfterOp))

        logger.debug('Running Daemon')
        set_proctitle('UDSActorDaemon')

        # Linux daemon will continue running unless something is requested to
        while True:
            brokerConnected = self.interactWithBroker()
            if brokerConnected is False:
                logger.debug('Interact with broker returned false, stopping service after a while')
                return
            elif brokerConnected is True:
                break

            # If brokerConnected returns None, repeat the cycle
            self.doWait(16000)  # Wait for a looong while

        if self.isAlive is False:
            logger.debug('The service is not alive after broker interaction, stopping it')
            return

        if self.rebootRequested is True:
            logger.debug('Reboot has been requested, stopping service')
            return

        # Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
        # This will be executed only when machine gets "ready"
        try:

            if os.path.isfile(POST_CMD):
                if (os.stat(POST_CMD).st_mode & stat.S_IXUSR) != 0:
                    subprocess.call([POST_CMD, ])
                else:
                    logger.info('POST file exists but it it is not executable (needs execution permission by root)')
            else:
                logger.info('POST file not found & not executed')
        except Exception as e:
            # Ignore output of execution command
            logger.error('Executing post command give')

        self.initIPC()

        # *********************
        # * Main Service loop *
        # *********************
        # Counter used to check ip changes only once every 10 seconds, for
        # example
        counter = 0
        while self.isAlive:
            counter += 1
            if counter % 10 == 0:
                self.checkIpsChanged()
            # In milliseconds, will break
            self.doWait(1000)

        self.endIPC()
        self.endAPI()

        self.notifyStop()
Example #30
0
 def log_message(self, fmt, *args):
     logger.info('HTTP ' + fmt % args)
Example #31
0
    def interactWithBroker(self):
        '''
        Returns True to continue to main loop, false to stop & exit service
        '''
        # If no configuration is found, stop service
        if cfg is None:
            logger.fatal('No configuration found, stopping service')
            return False

        self.api = REST.Api(cfg['host'], cfg['masterKey'], cfg['ssl'])

        # Wait for Broker to be ready
        counter = 0
        while self.isAlive:
            try:
                # getNetworkInfo is a generator function
                netInfo = tuple(operations.getNetworkInfo())
                self.knownIps = dict(((i.mac, i.ip) for i in netInfo))
                ids = ','.join([i.mac for i in netInfo])
                if ids == '':
                    # Wait for any network interface to be ready
                    logger.debug('No valid network interfaces found, retrying in a while...')
                    raise Exception()
                logger.debug('Ids: {}'.format(ids))
                self.api.init(ids)
                # Set remote logger to notify log info to broker
                logger.setRemoteLogger(self.api)

                break
            except REST.InvalidKeyError:
                logger.fatal('Can\'t sync with broker: Invalid broker Master Key')
                return False
            except REST.UnmanagedHostError:
                # Maybe interface that is registered with broker is not enabled already?
                # Right now, we thing that the interface connected to broker is
                # the interface that broker will know, let's see how this works
                logger.fatal('This host is not managed by UDS Broker (ids: {})'.format(ids))
                return False  # On unmanaged hosts, there is no reason right now to continue running
            except Exception as e:
                logger.debug('Exception on network info: retrying')
                logger.exception()
                # Any other error is expectable and recoverable, so let's wait a bit and retry again
                # but, if too many errors, will log it (one every minute, for
                # example)
                counter += 1
                if counter % 60 == 0:  # Every 5 minutes, raise a log
                    logger.info('Trying to inititialize connection with broker (last error: {})'.format(exceptionToMessage(e)))
                # Wait a bit before next check
                self.doWait(5000)

        # Broker connection is initialized, now get information about what to
        # do
        counter = 0
        while self.isAlive:
            try:
                logger.debug('Requesting information of what to do now')
                info = self.api.information()
                data = info.split('\r')
                if len(data) != 2:
                    logger.error('The format of the information message is not correct (got {})'.format(info))
                    raise Exception
                params = data[1].split('\t')
                if data[0] == 'rename':
                    try:
                        if len(params) == 1:  # Simple rename
                            logger.debug('Renaming computer to {}'.format(params[0]))
                            self.rename(params[0])
                        # Rename with change password for an user
                        elif len(params) == 4:
                            logger.debug('Renaming computer to {}'.format(params))
                            self.rename(params[0], params[1], params[2], params[3])
                        else:
                            logger.error('Got invalid parameter for rename operation: {}'.format(params))
                            return False
                        break
                    except Exception as e:
                        logger.error('Error at computer renaming stage: {}'.format(e.message))
                        return False
                elif data[0] == 'domain':
                    if len(params) != 5:
                        logger.error('Got invalid parameters for domain message: {}'.format(params))
                        return False
                    self.joinDomain(params[0], params[1], params[2], params[3], params[4])
                    break
                else:
                    logger.error('Unrecognized action sent from broker: {}'.format(data[0]))
                    return False  # Stop running service
            except REST.UserServiceNotFoundError:
                logger.error('The host has lost the sync state with broker! (host uuid changed?)')
                return False
            except Exception:
                if counter % 60 == 0:
                    logger.warn('Too many retries in progress, though still trying (last error: {})'.format(exceptionToMessage(e)))
                counter += 1
                # Any other error is expectable and recoverable, so let's wait
                # a bit and retry again
                # Wait a bit before next check
                self.doWait(5000)

        if self.rebootRequested:
            try:
                operations.reboot()
            except Exception as e:
                logger.error('Exception on reboot: {}'.format(e.message))
            return False  # Stops service

        return True
Example #32
0
 def notifyStop(self):
     '''
     Overriden to log stop
     '''
     logger.info('Service is being stopped')
Example #33
0
from PyQt5.QtCore import QTimer

from udsactor.log import logger, DEBUG
from udsactor.client import UDSClientQApp
from udsactor.platform import operations

if __name__ == "__main__":
    logger.setLevel(DEBUG)

    # Ensure idle operations is initialized on start
    operations.initIdleDuration(0)

    if 'linux' in sys.platform:
        os.environ['QT_X11_NO_MITSHM'] = '1'

    logger.info('Started UDS Client Actor')

    UDSClientQApp.setQuitOnLastWindowClosed(False)

    qApp = UDSClientQApp(sys.argv)

    qApp.init()

    # Crate a timer, so we can check signals from time to time by executing python interpreter
    # Note: Signals are only checked on python code execution, so we create a
    timer = QTimer(qApp)
    timer.start(1000)
    timer.timeout.connect(lambda *a: None)

    qApp.exec_()
Example #34
0
def logevent(msg):
    logger.info(msg)
Example #35
0
 def notifyStop(self):
     '''
     Overriden to log stop
     '''
     logger.info('Service is being stopped')