예제 #1
0
    def __init__(self, config):
        if sys.platform.startswith("win32"):
            self._python_runner = config['python_interpreter_windows']
            self.command_paths = [
                os.path.join(os.path.dirname(__file__), '../../..')]  # Built-in commands (on root dir)
            tools_path = config.get('tools_path_windows')

        else:
            self._python_runner = config['python_interpreter_linux']
            self.command_paths = [
                os.path.join(os.path.dirname(__file__), '..', 'plugins')]  # Built-in commands (absolute path)
            tools_path = config.get('tools_path_linux')

        self.timeout = int(config['timeout'])
        self.timeout_dc = None

        self.env = os.environ
        self.env['DEBIAN_FRONTEND'] = 'noninteractive'
        self.env['PYTHONPATH'] = os.path.dirname(__file__)
        self.env['LANG'] = 'en_US.utf8'
        self.env['PWD'] = '/root/'

        if tools_path:
            self.env["PATH"] += os.pathsep + tools_path

        log.debug("ENV: %s" % self.env)
        #reactor.callLater(0, self._loadCommands)
        self._commands = {}
        reactor.callWhenRunning(self._load_commands)
예제 #2
0
    def _processCommand(self, message):
        log.debug('Process Command')

        if self.public_key:
            if not self._verify_message(message):
                log.critical('[RSA CHECK: Failed] Command from %s has bad signature (Ignored)' % message.from_)
                result = (_E_UNVERIFIED_COMMAND, '', 'Bad signature', 0)
                self._onCallFinished(result, message)
                return
        else:
            # No public key, RSA functions are not available on this system
            log.warn('[RSA CHECK: No available] WARNING: Running unverified Command from %s' % message.from_)

        flush_callback = self._Flush
        message.command_replaced = message.command.replace('.', '_')
        d = self.command_runner.run_command(message.command_replaced, message.command_args, flush_callback, message)

        if d:
            d.addCallbacks(self._onCallFinished, self._onCallFailed,
                           callbackKeywords={'message': message},
                           errbackKeywords={'message': message},
            )
            return d

        else:
            log.info("Command Ignored: Unknown command: %s" % message.command)
            result = (_E_RUNNING_COMMAND, '', "Unknown command: %s" % message.command, 0)
            self._onCallFinished(result, message)

        return
예제 #3
0
    def processEnded(self, status):
        log.debug("Process ended")
        self.flush_callback = None

        # Cancel flush callbacks
        self.flush_callback = None
        self._cancel_flush(self.flush_later)
        self._cancel_flush(self.flush_later_forced)

        # Get command retval
        t = type(status.value)
        if t is ProcessDone:
            exit_code = 0

        elif t is ProcessTerminated:
            exit_code = status.value.exitCode

        else:
            raise status

        if not self.timeout_dc.called:
            self.timeout_dc.cancel()

        for d in self.deferreds:
            d.callback((exit_code, self.stdout, self.stderr, self.timeout_dc.called))
예제 #4
0
    def _send(self, result, message):
        log.debug('Send Response')
        message.toResult(*result)

        del result

        self.send(message.toEtree())
예제 #5
0
    def __init__(self, config):
        if sys.platform.startswith("win32"):
            self._python_runner = config["python_interpreter_windows"]
            self.command_paths = [
                os.path.join(os.path.dirname(__file__), "../../..")
            ]  # Built-in commands (on root dir)
            tools_path = config.get("tools_path_windows")

        else:
            self._python_runner = config["python_interpreter_linux"]
            self.command_paths = [
                os.path.join(os.path.dirname(__file__), "..", "plugins")
            ]  # Built-in commands (absolute path)
            tools_path = config.get("tools_path_linux")

        self.timeout = int(config["timeout"])
        self.timeout_dc = None

        self.env = os.environ
        self.env["DEBIAN_FRONTEND"] = "noninteractive"
        self.env["LANG"] = "en_US.utf8"
        self.env["PWD"] = "/root/"

        if tools_path:
            self.env["PATH"] += os.pathsep + tools_path

        log.debug("ENV: %s" % self.env)

        self._commands = {}
        reactor.callWhenRunning(self._load_commands)
예제 #6
0
    def __init__(self, config):
        """
        XMPP agent class.
        """
        log.info("Starting Agent...")

        log.info("Loading Commands...")
        self.command_runner = CommandRunner(config['Plugins'])

        log.info("Setting up Certificate")
        self.verify = ECVerify()

        log.info("Setting up Memory checker")

        self.running_commands = {}
        self.num_running_commands = 0
        self.timestamp = 0

        self.memory_checker = LoopingCall(self._check_memory, self.running_commands)
        self.memory_checker.start(_CHECK_RAM_INTERVAL)
        
        self.keepalive = LoopingCall(self._reconnect)

        log.debug("Loading XMPP...")
        Client.__init__(
            self,
            config['XMPP'],
            [("/iq[@type='set']", self.__onIq), ],
            resource='ecm_agent-%d' % AGENT_VERSION_PROTOCOL)
예제 #7
0
 def _onCallFailed(self, failure, *argv, **kwargs):
     log.error("onCallFailed")
     log.debug(failure)
     if 'message' in kwargs:
         message = kwargs['message']
         result = (2, '', failure, 0)
         self._onCallFinished(result, message)
예제 #8
0
    def _get_config2(self, unique_id):
        hostname = self._get_hostname()
        address = self._get_ip()
        uuid = self._get_stored_uuid()
        account = self.get_stored_account()
        agent_groups = self.get_stored_agent_groups

        params = "?uuid=%s&ipaddress=%s&hostname=%s&unique_id=%s&account=%s" \
                 % (uuid, address, hostname, unique_id, account)

        auth_url = ECMANAGED_AUTH_URL + '/' + params

        auth_content = None

        try:
            auth_content = yield getPage(auth_url)
        except:
            log.debug("getPage failed")

        if not auth_content:
            try:
                auth_content = urllib2.urlopen(auth_url).read()
            except:
                pass

        if auth_content:
            for line in auth_content.splitlines():
                if line:
                    returnValue(line)

        returnValue('')
예제 #9
0
    def __init__(self, config):
        """
        XMPP agent class.
        """
        log.info("Starting agent...")
        self.config = config

        log.info("Setting up certificate")
        self.public_key = None
        try:
            if Crypto.version_info[:2] >= (2, 2):
                _public_key = self._read_pub_key()
                if _public_key:
                    key = PublicKey.RSA.importKey(_public_key)
                    self.public_key = key.publickey()
        except:
            pass

        if not self.public_key:
            log.warn('PyCrypto not available or version is < 2.2: Please upgrade: http://www.pycrypto.org/')

        log.info("Loading commands...")
        self.command_runner = CommandRunner(config['Plugins'])

        log.debug("Loading XMPP...")
        observers = [
            ('/iq', self.__onIq),
        ]
        Client.__init__(self,
                        self.config['XMPP'],
                        observers,
                        resource='ecm_agent-%d' % AGENT_VERSION_PROTOCOL
        )
예제 #10
0
    def _flush(self):
        if not self.flush_callback:
            return

        total_out = len(self.stdout) + len(self.stderr)

        if total_out - self.last_send_data_size > FLUSH_MIN_LENGTH:
            curr_time = time()
            if self.last_send_data_time + FLUSH_TIME < curr_time:
                self.last_send_data_size = total_out
                self.last_send_data_time = curr_time

                log.debug("Scheduling a flush response: %s" % self.stdout)
                self._cancel_flush(self.flush_later_forced)
                self.flush_later = reactor.callLater(
                    1, self.flush_callback, (None, self.stdout, self.stderr, 0, total_out), self.message
                )

        if not self.flush_later:
            self._cancel_flush(self.flush_later_forced)
            self.flush_later_forced = reactor.callLater(
                FLUSH_TIME, self.flush_callback, (None, self.stdout, self.stderr, 0, total_out), self.message
            )

        del total_out
예제 #11
0
    def _send(self, result, message):
        log.debug('Send Response')
        mem_clean('agent._send')
        message.toResult(*result)

        del result
        mem_clean('agent._send')
        self.send(message.toEtree())
예제 #12
0
    def connectionMade(self):
        log.debug("Process started.")
        self.timeout_dc = reactor.callLater(self.timeout, self.transport.signalProcess, 'KILL')

        # Pass the call arguments via stdin in json format
        self.transport.write(base64.b64encode(json.dumps(self.command_args)))

        # And close stdin to signal we are done writing args.
        self.transport.closeStdin()
예제 #13
0
 def _onPossibleErrorIq(self, elem):
     sender = elem['from']
     for el in elem.elements():
         if el.name == 'error' and el['code'] == '404':
             log.warn('Received a 404 code from the server, setting the target user as offline')
             if sender in self._online_contacts:
                 self._online_contacts.remove(sender)
             else:
                 log.debug('Received a 404 from %s which not (anymore?) in the online contacts list.')
예제 #14
0
def mem_clean(where=''):
    _collect = collect()
    rss, vms = mem_usage()
    string = "_mem_clean: %s collected %d objects. (current mem: rss=%sMB | vms=%sMB)" % (where, _collect, rss, vms)

    log.debug(string)

    del _collect, where, vms, string

    return rss
예제 #15
0
    def _add_command(self, data, **kwargs):
        (exit_code, stdout, stderr, timeout_called) = data

        if exit_code == 0:
            for line in stdout.splitlines():
                self._commands[line.split()[0]] = kwargs['filename']
                log.debug("Command %s added" % line.split()[0])

        else:
            log.error('Error adding commands from %s: %s'
                    % (kwargs['filename'], data))
예제 #16
0
def mem_clean(where="", dolog=False):
    _collect = collect()
    rss, vms = mem_usage()
    string = "_mem_clean: %s collected %d objects. (current mem: rss=%sMB | vms=%sMB)" % (where, _collect, rss, vms)

    if dolog:
        log.info(string)

    else:
        log.debug(string)

    del _collect, where, dolog, rss, vms, string
예제 #17
0
    def run_command(self, message, flush_callback=None):
        if self._commands.get(message.command_name):
            log.debug("executing %s with args: %s" % (message.command_name, message.command_args))
            return self._run_process(
                self._commands[message.command_name],
                message.command_name,
                message.command_args,
                flush_callback,
                message,
            )

        return
예제 #18
0
    def _read_pub_key(self):
        log.debug('Reading public certificate')
        public_key = None
        try:
            cert_file = os.path.join(os.path.dirname(__file__), _CERTIFICATE_FILE)
            if os.path.isfile(cert_file):
                f = open(cert_file, 'r')
                public_key = f.read()
                f.close()
        except:
            log.critical("Unable to read certificate file")

        return public_key
예제 #19
0
    def check_config(self):
        uuid = self._get_stored_uuid()
        account_id = self.get_stored_account()

        if not uuid and not account_id:
            # Is not an update and no account is set
            log.error('Please configure agent with ./configure --account=XXXXX')
            raise Exception('Please configure agent with ./configure --account=XXXXX')

        unique_id = self._get_unique_id()

        if not unique_id:
            log.error('Could not obtain UNIQUE_ID. Please set up XMPP manually')
            raise Exception('Could not obtain UNIQUE_ID. Please set up XMPP manually')

        # Check all data valid for v3
        if uuid and not '@' in uuid and account_id and self.is_unique_id_same(unique_id):
            log.debug('UNIQUE ID has not changed. Skip UUID check')

        else:
            # Try to get uuid (one hour and a half loop: 360x15)
            json_data = None

            for i in range(360):
                log.info("Trying to get UUID via URL (meta-data v2)")
                json_data = yield self._get_config(unique_id)
                if json_data:
                    break

                sleep(15)

            # Decode metadata
            meta_data = self.parse_meta_data(json_data)

            if not meta_data:
                log.error('Could not obtain UUID. Please set up XMPP manually')
                raise Exception('Could not obtain UUID. Please set up XMPP manually')

            if not self['XMPP'].get('password'):
                self['XMPP']['password'] = hex(random.getrandbits(256))[2:-1]

            # Updates from v2 to v3 write account info
            if not account_id and meta_data.get('account'):
                self['XMPP']['account'] = meta_data.get('account')

            self['XMPP']['user'] = meta_data['uuid']
            self['XMPP']['unique_id'] = unique_id
            self.write()

        returnValue(True)
예제 #20
0
    def __onIq(self, msg):
        """
        A new IQ message has been received and we should process it.
        """
        log.debug('__onIq')
        message_type = msg['type']

        log.debug("q Message received: \n%s" % msg.toXml())
        log.debug("Message type: %s" % message_type)

        if message_type == 'set':
            #Parse and check message format
            message = IqMessage(msg)

            if hasattr(message, 'command') and hasattr(message, 'from_'):
                log.debug('online contacts: %s' % self._online_contacts)

                if message.from_ not in self._online_contacts:
                    log.warn('IQ sender not in roster (%s), dropping message'
                           % message.from_)
                else:
                    self._processCommand(message)
            else:
                log.warn('Unknown ecm_message received: "%s" Full XML:\n%s'
                       % (message_type, msg.toXml()))
        else:
            log.warn('Unknown IQ type received: "%s" Full XML:\n%s'
                   % (message_type, msg.toXml()))
예제 #21
0
    def __onIq(self, msg):
        """
        A new IQ message has been received and we should process it.
        """
        log.debug('__onIq')
        mem_clean('__onIq [start]')
        self.running_commands += 1

        log.debug("q Message received: \n%s" % msg.toXml())
        log.debug("Message type: %s" % msg['type'])

        if msg['type'] == 'set':
            message = IqMessage(msg)

            if hasattr(message, 'command') and hasattr(message, 'from_'):
                log.debug('online contacts: %s' % self._online_contacts)

                if message.from_ not in self._online_contacts:
                    log.warn('IQ sender not in roster (%s), dropping message' % message.from_)
                else:
                    self._processCommand(message)
            else:
                log.warn('Unknown ecm_message received: Full XML:\n%s' % (msg.toXml()))
                
            del message
            
        else:
            log.warn('Unknown IQ type received: Full XML:\n%s' % (msg.toXml()))

        del msg
        mem_clean('__onIq [end]')
예제 #22
0
    def processEnded(self, status):
        log.debug("process ended")
        t = type(status.value)

        if t is ProcessDone:
            exit_code = 0

        elif t is ProcessTerminated:
            exit_code = status.value.exitCode

        else:
            raise status

        for d in self.deferreds:
            d.callback((exit_code, self.stdout, self.stderr))
예제 #23
0
    def _load_commands(self):
        for path in self.command_paths:
            log.debug("Processing dir: %s" % path)
            try:
                if os.path.isdir(path):
                    for filename in os.listdir(path):
                        if not filename.startswith("plugin_"):
                            continue

                        log.debug("  Queuing plugin %s for process." % filename)
                        full_filename = os.path.join(path, filename)
                        d = self._run_process(full_filename, "", {})
                        d.addCallback(self._add_command, filename=full_filename)
            except:
                print sys.exc_info()
예제 #24
0
    def outReceived(self, data):
        log.debug("Out made: %s" % data)

        if _FINAL_OUTPUT_STRING in data:
            for line in data.split("\n"):
                if _FINAL_OUTPUT_STRING in line:
                    # Skip this line and stop flush callback
                    self.stdout = self.stderr = ''
                    self.flush_callback = None

                else:
                    self.stdout += line
        else:
            self.stdout += data

        self._flush()
예제 #25
0
    def check_uuid(self):
        mac = self._get_mac()

        # Always generate a new password if not is set
        if not self['XMPP']['password']:
            self['XMPP']['password'] = hex(random.getrandbits(128))[2:-1]

        if mac:
            if str(mac) == str(self._getStoredMAC()):
                log.debug("MAC has not changed. Skip UUID check")

            else:
                # Try to get uuid
                uuid = None
                for i in range(30):
                    try:
                        uuid = yield self._getUUID()
                        if uuid:
                            break

                    except:
                        pass
                    sleep(20)

                if not uuid:
                    log.error("ERROR: Could not obtain UUID. please set up XMPP manually in %s" % self.filename)
                    returnValue(False)

                if str(uuid) == str(self._getStoredUUID()):
                    log.debug("UUID has not changed.")

                    # Update mac
                    self['XMPP']['mac'] = mac
                    self.write()

                else:
                    log.info("UUID has changed, reconfiguring XMPP user/pass")
                    self['XMPP']['user'] = '******'.join((uuid, self['XMPP']['host']))

                    self['XMPP']['mac'] = mac
                    self.write()

            returnValue(True)

        else:
            log.error("ERROR: Could not obtain MAC. please set up XMPP manually in %s" % self.filename)
            returnValue(False)
예제 #26
0
    def check_uuid(self):
        unique_id = self._get_unique_id()

        if unique_id:
            if str(unique_id) == str(self._get_stored_unique_id()):
                log.debug("UNIQUE ID has not changed. Skip UUID check")

            else:
                # Try to get uuid (one hour and a half loop: 360x15)
                uuid = None
                for i in range(360):
                    try:
                        uuid = yield self._get_uuid()
                        if uuid:
                            break

                    except Exception:
                        pass

                    sleep(15)

                if not uuid:
                    log.error("ERROR: Could not obtain UUID. please set up XMPP manually in %s" % self.filename)
                    raise Exception("Could not obtain UUID")

                if str(uuid) == str(self._get_stored_uuid()):
                    log.debug("UUID has not changed.")
                    self["XMPP"]["unique_id"] = unique_id
                    self.write()

                else:
                    log.info("UUID has changed, reconfiguring XMPP user/pass")
                    self["XMPP"]["user"] = "******".join((uuid, self["XMPP"]["host"]))
                    self["XMPP"]["unique_id"] = unique_id
                    self.write()

            returnValue(True)

        else:
            log.error("ERROR: Could not obtain UNIQUE_ID. please set up XMPP manually in %s" % self.filename)
            raise Exception("Could not obtain UUID")
예제 #27
0
    def _onPresence(self, elem):
        """
        A new presence message has been received,
        let's see who has (dis)connected.
        """
        log.debug('_onPresence')
        presence = XMPPPresence(elem)
        if presence.available:
            log.debug("%s is now available" % presence.sender)
            #Store full jid.
            self._online_contacts.add(presence.sender)

        else:
            log.debug("%s is not available anymore" % presence.sender)
            if presence.jid in self._online_contacts:
                self._online_contacts.remove(presence.sender)
예제 #28
0
 def outReceived(self, data):
     log.debug("Out made")
     self.stdout += data
예제 #29
0
 def errReceived(self, data):
     log.debug("Err made: %s" % data)
     self.stderr += data
예제 #30
0
 def connectionMade(self):
     log.debug("Process started.")