Ejemplo n.º 1
0
 def __init__(self):
     self.module_name = ""
     self.options = None
     self.options_globals = Config(
         os.path.join(CUCKOO_ROOT, "conf", "cuckoo.conf"))
     # Database pointer.
     self.db = Database()
     # Machine table is cleaned to be filled from configuration file at each start.
     self.db.clean_machines()
Ejemplo n.º 2
0
 def __init__(self):
     self.module_name = ""
     self.options = None
     self.options_globals = Config(os.path.join(CUCKOO_ROOT, "conf", "cuckoo.conf"))
     # Database pointer.
     self.db = Database()
     # Machine table is cleaned to be filled from configuration file at each start.
     self.db.clean_machines()
Ejemplo n.º 3
0
    def run(self):
        """Run manager thread."""
        success = self.launch_analysis()
        Database().complete(self.task.id, success)

        self.process_results()

        log.debug("Releasing database task #%d with status %s", self.task.id,
                  success)
        log.info("Task #%d: analysis procedure completed", self.task.id)
Ejemplo n.º 4
0
 def __init__(self, task_id):
     """@param analysis_path: analysis folder path.
     """
     self.task = Database().view_task(task_id).to_dict()
     self.analysis_path = os.path.join(CUCKOO_ROOT,
                                       "storage",
                                       "analyses",
                                       str(task_id))
     self.cfg = Config(cfg=os.path.join(CUCKOO_ROOT,
                                        "conf",
                                        "reporting.conf"))
Ejemplo n.º 5
0
    def run(self):
        """Run debug analysis.
        @return: debug information dict.
        """
        self.key = "debug"
        debug = {"log": "", "errors": []}

        if os.path.exists(self.log_path):
            try:
                debug["log"] = codecs.open(self.log_path, "rb", "utf-8").read()
            except ValueError as e:
                raise CuckooProcessingError("Error decoding %s: %s" %
                                            (self.log_path, e))
            except (IOError, OSError) as e:
                raise CuckooProcessingError("Error opening %s: %s" %
                                            (self.log_path, e))

        for error in Database().view_errors(int(self.task["id"])):
            debug["errors"].append(error.message)

        return debug
Ejemplo n.º 6
0
class MachineManager(object):
    """Base abstract class for analysis machine manager."""
    def __init__(self):
        self.module_name = ""
        self.options = None
        self.options_globals = Config(
            os.path.join(CUCKOO_ROOT, "conf", "cuckoo.conf"))
        # Database pointer.
        self.db = Database()
        # Machine table is cleaned to be filled from configuration file at each start.
        self.db.clean_machines()

    def set_options(self, options):
        """Set machine manager options.
        @param options: machine manager options dict.
        """
        self.options = options

    def initialize(self, module_name):
        """Read and load machines configuration, try to check the configuration.
        @param module_name: module name.
        """
        # Load.
        self._initialize(module_name)

        # Run initialization checks.
        self._initialize_check()

    def _initialize(self, module_name):
        """Read configuration.
        @param module_name: module name.
        """
        self.module_name = module_name
        mmanager_opts = self.options.get(module_name)

        for machine_id in mmanager_opts["machines"].strip().split(","):
            try:
                machine_opts = self.options.get(machine_id.strip())
                machine = Dictionary()
                machine.id = machine_id.strip()
                machine.label = machine_opts["label"].strip()
                machine.platform = machine_opts["platform"].strip()
                machine.ip = machine_opts["ip"].strip()

                self.db.add_machine(name=machine.id,
                                    label=machine.label,
                                    ip=machine.ip,
                                    platform=machine.platform)
            except (AttributeError, CuckooOperationalError):
                log.warning(
                    "Configuration details about machine %s are missing. Continue",
                    machine_id)
                continue

    def _initialize_check(self):
        """Runs checks against virtualization software when a machine manager 
        is initialized.
        @note: in machine manager modules you may override or superclass 
               his method.
        @raise CuckooMachineError: if a misconfiguration or a unkown vm state
                                   is found.
        """
        try:
            configured_vm = self._list()
        except NotImplementedError:
            return

        for machine in self.machines():
            if machine.label not in configured_vm:
                raise CuckooCriticalError(
                    "Configured machine {0} was not detected or it's not in proper state"
                    .format(machine.label))

        if not self.options_globals.timeouts.vm_state:
            raise CuckooCriticalError(
                "Virtual machine state change timeout setting not found, please add it to the config file"
            )

    def machines(self):
        """List virtual machines.
        @return: virtual machines list
        """
        return self.db.list_machines()

    def availables(self):
        """How many machines are free.
        @return: free machines count.
        """
        return self.db.count_machines_available()

    def acquire(self, machine_id=None, platform=None):
        """Acquire a machine to start analysis.
        @param machine_id: machine ID.
        @param platform: machine platform.
        @return: machine or None.
        """
        if machine_id:
            return self.db.lock_machine(name=machine_id)
        elif platform:
            return self.db.lock_machine(platform=platform)
        else:
            return self.db.lock_machine()

    def release(self, label=None):
        """Release a machine.
        @param label: machine name.
        """
        self.db.unlock_machine(label)

    def running(self):
        """Returns running virtual machines.
        @return: running virtual machines list.
        """
        return self.db.list_machines(locked=True)

    def shutdown(self):
        """Shutdown the machine manager. Kills all alive machines.
        @raise CuckooMachineError: if unable to stop machine.
        """
        if self.running().count() > 0:
            log.info("Still %s guests alive. Shutting down...",
                     self.running().count())
            for machine in self.running():
                try:
                    self.stop(machine.label)
                except CuckooMachineError as e:
                    log.warning(
                        "Unable to shutdown machine %s, please check "
                        "manually. Error: %s", machine.label, e)

    def set_status(self, label, status):
        """Set status for a virtual machine.
        @param label: virtual machine label
        @param status: new virtual machine status
        """
        self.db.set_machine_status(label, status)

    def start(self, label=None):
        """Start a machine.
        @param label: machine name.
        @raise NotImplementedError: this method is abstract.
        """
        raise NotImplementedError

    def stop(self, label=None):
        """Stop a machine.
        @param label: machine name.
        @raise NotImplementedError: this method is abstract.
        """
        raise NotImplementedError

    def _list(self):
        """Lists virtual machines configured.
        @raise NotImplementedError: this method is abstract.
        """
        raise NotImplementedError

    def dump_memory(self, path):
        """Takes a memory dump of a machine.
        @param path: path to where to store the memory dump.
        """
        raise NotImplementedError

    def _wait_status(self, label, state):
        """Waits for a vm status.
        @param label: virtual machine name.
        @param state: virtual machine status, accepts more than one states in a list.
        @raise CuckooMachineError: if default waiting timeout expire.
        """
        # This block was originally suggested by Loic Jaquemet.
        waitme = 0
        try:
            current = self._status(label)
        except NameError:
            return

        if isinstance(state, str):
            state = [state]
        while current not in state:
            log.debug(
                "Waiting %i cuckooseconds for machine %s to switch to status %s",
                waitme, label, state)
            if waitme > int(self.options_globals.timeouts.vm_state):
                raise CuckooMachineError(
                    "Timeout hit while for machine {0} to change status".
                    format(label))
            time.sleep(1)
            waitme += 1
            current = self._status(label)
Ejemplo n.º 7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("target",
                        type=str,
                        help="URL, path to the file or folder to analyze")
    parser.add_argument("--url",
                        action="store_true",
                        default=False,
                        help="Specify whether the target is an URL",
                        required=False)
    parser.add_argument("--package",
                        type=str,
                        action="store",
                        default="",
                        help="Specify an analysis package",
                        required=False)
    parser.add_argument("--custom",
                        type=str,
                        action="store",
                        default="",
                        help="Specify any custom value",
                        required=False)
    parser.add_argument("--timeout",
                        type=int,
                        action="store",
                        default=0,
                        help="Specify an analysis timeout",
                        required=False)
    parser.add_argument(
        "--options",
        type=str,
        action="store",
        default="",
        help=
        "Specify options for the analysis package (e.g. \"name=value,name2=value2\")",
        required=False)
    parser.add_argument(
        "--priority",
        type=int,
        action="store",
        default=1,
        help="Specify a priority for the analysis represented by an integer",
        required=False)
    parser.add_argument(
        "--machine",
        type=str,
        action="store",
        default="",
        help="Specify the identifier of a machine you want to use",
        required=False)
    parser.add_argument(
        "--platform",
        type=str,
        action="store",
        default="",
        help=
        "Specify the operating system platform you want to use (windows/darwin/linux)",
        required=False)
    parser.add_argument(
        "--memory",
        action="store_true",
        default=False,
        help="Enable to take a memory dump of the analysis machine",
        required=False)
    parser.add_argument(
        "--enforce-timeout",
        action="store_true",
        default=False,
        help="Enable to force the analysis to run for the full timeout period",
        required=False)

    try:
        args = parser.parse_args()
    except IOError as e:
        parser.error(e)
        return False

    db = Database()

    # Try to get input as utf-8.
    try:
        target = args.target.decode("utf-8")
    except UnicodeEncodeError:
        target = args.target

    if args.url:
        task_id = db.add_url(target,
                             package=args.package,
                             timeout=args.timeout,
                             options=args.options,
                             priority=args.priority,
                             machine=args.machine,
                             platform=args.platform,
                             custom=args.custom,
                             memory=args.memory,
                             enforce_timeout=args.enforce_timeout)

        print(
            bold(green("Success")) +
            ": URL \"{0}\" added as task with ID {1}".format(target, task_id))
    else:
        # Get absolute path to deal with relative.
        path = os.path.abspath(target)

        if not os.path.exists(path):
            print(
                bold(red("Error")) +
                ": the specified file/folder does not exist at path \"{0}\"".
                format(path))
            return False

        files = []
        if os.path.isdir(path):
            for dirname, dirnames, filenames in os.walk(path):
                for file_name in filenames:
                    file_path = os.path.join(dirname, file_name)

                    if os.path.isfile(file_path):
                        files.append(file_path)
        else:
            files.append(path)

        for file_path in files:
            task_id = db.add_path(file_path=file_path,
                                  package=args.package,
                                  timeout=args.timeout,
                                  options=args.options,
                                  priority=args.priority,
                                  machine=args.machine,
                                  platform=args.platform,
                                  custom=args.custom,
                                  memory=args.memory,
                                  enforce_timeout=args.enforce_timeout)

            if task_id:
                print(
                    bold(green("Success")) +
                    ": File \"{0}\" added as task with ID {1}".format(
                        file_path, task_id))
            else:
                print(bold(red("Error")) + ": adding task to database")
Ejemplo n.º 8
0
 def emit(self, record):
     if hasattr(record, "task_id"):
         db = Database()
         db.add_error(record.msg, int(record.task_id))
Ejemplo n.º 9
0
 def __init__(self):
     self.running = True
     self.cfg = Config()
     self.db = Database()
Ejemplo n.º 10
0
class Scheduler:
    """Tasks Scheduler.

    This class is responsible for the main execution loop of the tool. It
    prepares the analysis machines and keep waiting and loading for new
    analysis tasks.
    Whenever a new task is available, it launches AnalysisManager which will
    take care of running the full analysis process and operating with the
    assigned analysis machine.
    """

    def __init__(self):
        self.running = True
        self.cfg = Config()
        self.db = Database()

    def initialize(self):
        """Initialize the machine manager."""
        global mmanager

        mmanager_name = self.cfg.cuckoo.machine_manager

        log.info("Using \"%s\" machine manager", mmanager_name)

        # Get registered class name. Only one machine manager is imported,
        # therefore there should be only one class in the list.
        plugin = list_plugins("machinemanagers")[0]
        # Initialize the machine manager.
        mmanager = plugin()

        # Find its configuration file.
        conf = os.path.join(CUCKOO_ROOT, "conf", "%s.conf" % mmanager_name)

        if not os.path.exists(conf):
            raise CuckooCriticalError("The configuration file for machine "
                                      "manager \"{0}\" does not exist at path: "
                                      "{1}".format(mmanager_name, conf))

        # Provide a dictionary with the configuration options to the
        # machine manager instance.
        mmanager.set_options(Config(conf))
        # Initialize the machine manager.
        mmanager.initialize(mmanager_name)

        # At this point all the available machines should have been identified
        # and added to the list. If none were found, Cuckoo needs to abort the
        # execution.
        if mmanager.machines().count() == 0:
            raise CuckooCriticalError("No machines available")
        else:
            log.info("Loaded %s machine/s", mmanager.machines().count())


    def stop(self):
        """Stop scheduler."""
        self.running = False
        # Shutdown machine manager (used to kill machines that still alive).
        mmanager.shutdown()

    def start(self):
        """Start scheduler."""
        self.initialize()

        log.info("Waiting for analysis tasks...")

        # This loop runs forever.
        while self.running:
            time.sleep(1)

            # If no machines are available, it's pointless to fetch for
            # pending tasks. Loop over.
            if mmanager.availables() == 0:
                continue

            # Fetch a pending analysis task.
            task = self.db.fetch_and_process()

            if task:
                log.debug("Processing task #%s", task.id)

                # Initialize the analysis manager.
                analysis = AnalysisManager(task)
                # Start.
                analysis.start()
Ejemplo n.º 11
0
class Scheduler:
    """Tasks Scheduler.

    This class is responsible for the main execution loop of the tool. It
    prepares the analysis machines and keep waiting and loading for new
    analysis tasks.
    Whenever a new task is available, it launches AnalysisManager which will
    take care of running the full analysis process and operating with the
    assigned analysis machine.
    """
    def __init__(self):
        self.running = True
        self.cfg = Config()
        self.db = Database()

    def initialize(self):
        """Initialize the machine manager."""
        global mmanager

        mmanager_name = self.cfg.cuckoo.machine_manager

        log.info("Using \"%s\" machine manager", mmanager_name)

        # Get registered class name. Only one machine manager is imported,
        # therefore there should be only one class in the list.
        plugin = list_plugins("machinemanagers")[0]
        # Initialize the machine manager.
        mmanager = plugin()

        # Find its configuration file.
        conf = os.path.join(CUCKOO_ROOT, "conf", "%s.conf" % mmanager_name)

        if not os.path.exists(conf):
            raise CuckooCriticalError(
                "The configuration file for machine "
                "manager \"{0}\" does not exist at path: "
                "{1}".format(mmanager_name, conf))

        # Provide a dictionary with the configuration options to the
        # machine manager instance.
        mmanager.set_options(Config(conf))
        # Initialize the machine manager.
        mmanager.initialize(mmanager_name)

        # At this point all the available machines should have been identified
        # and added to the list. If none were found, Cuckoo needs to abort the
        # execution.
        if mmanager.machines().count() == 0:
            raise CuckooCriticalError("No machines available")
        else:
            log.info("Loaded %s machine/s", mmanager.machines().count())

    def stop(self):
        """Stop scheduler."""
        self.running = False
        # Shutdown machine manager (used to kill machines that still alive).
        mmanager.shutdown()

    def start(self):
        """Start scheduler."""
        self.initialize()

        log.info("Waiting for analysis tasks...")

        # This loop runs forever.
        while self.running:
            time.sleep(1)

            # If no machines are available, it's pointless to fetch for
            # pending tasks. Loop over.
            if mmanager.availables() == 0:
                continue

            # Fetch a pending analysis task.
            task = self.db.fetch_and_process()

            if task:
                log.debug("Processing task #%s", task.id)

                # Initialize the analysis manager.
                analysis = AnalysisManager(task)
                # Start.
                analysis.start()
Ejemplo n.º 12
0
    def launch_analysis(self):
        """Start analysis."""
        sniffer = None
        succeeded = False

        log.info("Starting analysis of %s \"%s\" (task=%d)",
                 self.task.category.upper(), self.task.target, self.task.id)

        # Initialize the the analysis folders.
        if not self.init_storage():
            return False

        if self.task.category == "file":
            # Store a copy of the original file.
            if not self.store_file():
                return False

        # Generate the analysis configuration file.
        options = self.build_options()

        # Acquire analysis machine.
        machine = self.acquire_machine()

        # At this point we can tell the Resultserver about it
        Resultserver().add_task(self.task, machine)

        # If enabled in the configuration, start the tcpdump instance.
        if self.cfg.sniffer.enabled:
            sniffer = Sniffer(self.cfg.sniffer.tcpdump)
            sniffer.start(interface=self.cfg.sniffer.interface,
                          host=machine.ip,
                          file_path=os.path.join(self.storage, "dump.pcap"))

        try:
            # Mark the selected analysis machine in the database as started.
            guest_log = Database().guest_start(self.task.id, machine.name,
                                               machine.label,
                                               mmanager.__class__.__name__)
            # Start the machine.
            mmanager.start(machine.label)
        except CuckooMachineError as e:
            log.error(str(e), extra={"task_id": self.task.id})

            # Stop the sniffer.
            if sniffer:
                sniffer.stop()

            return False
        else:
            try:
                # Initialize the guest manager.
                guest = GuestManager(machine.name, machine.ip,
                                     machine.platform)
                # Start the analysis.
                guest.start_analysis(options)
            except CuckooGuestError as e:
                log.error(str(e), extra={"task_id": self.task.id})

                # Stop the sniffer.
                if sniffer:
                    sniffer.stop()

                return False
            else:
                # Wait for analysis completion.
                try:
                    guest.wait_for_completion()
                    succeeded = True
                except CuckooGuestError as e:
                    log.error(str(e), extra={"task_id": self.task.id})
                    succeeded = False

                # Retrieve the analysis results and store them.
                try:
                    guest.save_results(self.storage)
                    succeeded = True
                except CuckooGuestError as e:
                    log.error(str(e), extra={"task_id": self.task.id})
                    succeeded = False
        finally:
            # Stop the sniffer.
            if sniffer:
                sniffer.stop()

            # Take a memory dump of the machine before shutting it off.
            if self.cfg.cuckoo.memory_dump or self.task.memory:
                try:
                    mmanager.dump_memory(
                        machine.label, os.path.join(self.storage,
                                                    "memory.dmp"))
                except NotImplementedError:
                    log.error("The memory dump functionality is not available "
                              "for current machine manager")
                except CuckooMachineError as e:
                    log.error(e)

            try:
                # Stop the analysis machine.
                mmanager.stop(machine.label)
            except CuckooMachineError as e:
                log.warning("Unable to stop machine %s: %s", machine.label, e)

            # Market the machine in the database as stopped.
            Database().guest_stop(guest_log)

            try:
                # Release the analysis machine.
                mmanager.release(machine.label)
            except CuckooMachineError as e:
                log.error(
                    "Unable to release machine %s, reason %s. "
                    "You might need to restore it manually", machine.label, e)

            # after all this, we can make the Resultserver forget about it
            Resultserver().del_task(self.task, machine)

        return succeeded
Ejemplo n.º 13
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("target", type=str, help="URL, path to the file or folder to analyze")
    parser.add_argument("--url", action="store_true", default=False, help="Specify whether the target is an URL", required=False)
    parser.add_argument("--package", type=str, action="store", default="", help="Specify an analysis package", required=False)
    parser.add_argument("--custom", type=str, action="store", default="", help="Specify any custom value", required=False)
    parser.add_argument("--timeout", type=int, action="store", default=0, help="Specify an analysis timeout", required=False)
    parser.add_argument("--options", type=str, action="store", default="", help="Specify options for the analysis package (e.g. \"name=value,name2=value2\")", required=False)
    parser.add_argument("--priority", type=int, action="store", default=1, help="Specify a priority for the analysis represented by an integer", required=False)
    parser.add_argument("--machine", type=str, action="store", default="", help="Specify the identifier of a machine you want to use", required=False)
    parser.add_argument("--platform", type=str, action="store", default="", help="Specify the operating system platform you want to use (windows/darwin/linux)", required=False)
    parser.add_argument("--memory", action="store_true", default=False, help="Enable to take a memory dump of the analysis machine", required=False)
    parser.add_argument("--enforce-timeout", action="store_true", default=False, help="Enable to force the analysis to run for the full timeout period", required=False)

    try:
        args = parser.parse_args()
    except IOError as e:
        parser.error(e)
        return False

    db = Database()

    # Try to get input as utf-8.
    try:
        target = args.target.decode("utf-8")
    except UnicodeEncodeError:
        target = args.target

    if args.url:
        task_id = db.add_url(target,
                             package=args.package,
                             timeout=args.timeout,
                             options=args.options,
                             priority=args.priority,
                             machine=args.machine,
                             platform=args.platform,
                             custom=args.custom,
                             memory=args.memory,
                             enforce_timeout=args.enforce_timeout)

        print(bold(green("Success")) + ": URL \"{0}\" added as task with ID {1}".format(target, task_id))
    else:
        # Get absolute path to deal with relative.
        path = os.path.abspath(target)

        if not os.path.exists(path):
            print(bold(red("Error")) + ": the specified file/folder does not exist at path \"{0}\"".format(path))
            return False

        files = []
        if os.path.isdir(path):
            for dirname, dirnames, filenames in os.walk(path):
                for file_name in filenames:
                    file_path = os.path.join(dirname, file_name)

                    if os.path.isfile(file_path):
                        files.append(file_path)
        else:
            files.append(path)

        for file_path in files:
            task_id = db.add_path(file_path=file_path,
                                  package=args.package,
                                  timeout=args.timeout,
                                  options=args.options,
                                  priority=args.priority,
                                  machine=args.machine,
                                  platform=args.platform,
                                  custom=args.custom,
                                  memory=args.memory,
                                  enforce_timeout=args.enforce_timeout)

            if task_id:
                print(bold(green("Success")) + ": File \"{0}\" added as task with ID {1}".format(file_path, task_id))
            else:
                print(bold(red("Error")) + ": adding task to database")
Ejemplo n.º 14
0
 def __init__(self, task_id):
     """@param task_id: ID of the analyses to process."""
     self.task = Database().view_task(task_id).to_dict()
     self.analysis_path = os.path.join(CUCKOO_ROOT, "storage", "analyses",
                                       str(task_id))
Ejemplo n.º 15
0
 def __init__(self):
     self.running = True
     self.cfg = Config()
     self.db = Database()
Ejemplo n.º 16
0
except ImportError:
    sys.stderr.write("ERROR: Bottle library is missing")
    sys.exit(1)

logging.basicConfig()
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))

from lib.dragon.core.database import Database
from lib.dragon.common.constants import CUCKOO_ROOT
from lib.dragon.common.utils import store_temp_file

# Templating engine.
env = Environment()
env.loader = FileSystemLoader(os.path.join(CUCKOO_ROOT, "data", "html"))
# Global db pointer.
db = Database()

@hook("after_request")
def custom_headers():
    """Set some custom headers across all HTTP responses."""
    response.headers["Server"] = "Machete Server"
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Pragma"] = "no-cache"
    response.headers["Cache-Control"] = "no-cache"
    response.headers["Expires"] = "0"

@route("/")
def index():
    context = {}
Ejemplo n.º 17
0
class MachineManager(object):
    """Base abstract class for analysis machine manager."""

    def __init__(self):
        self.module_name = ""
        self.options = None
        self.options_globals = Config(os.path.join(CUCKOO_ROOT, "conf", "cuckoo.conf"))
        # Database pointer.
        self.db = Database()
        # Machine table is cleaned to be filled from configuration file at each start.
        self.db.clean_machines()

    def set_options(self, options):
        """Set machine manager options.
        @param options: machine manager options dict.
        """
        self.options = options

    def initialize(self, module_name):
        """Read and load machines configuration, try to check the configuration.
        @param module_name: module name.
        """
        # Load.
        self._initialize(module_name)

        # Run initialization checks.
        self._initialize_check()

    def _initialize(self, module_name):
        """Read configuration.
        @param module_name: module name.
        """
        self.module_name = module_name
        mmanager_opts = self.options.get(module_name)

        for machine_id in mmanager_opts["machines"].strip().split(","):
            try:
                machine_opts = self.options.get(machine_id.strip())
                machine = Dictionary()
                machine.id = machine_id.strip()
                machine.label = machine_opts["label"].strip()
                machine.platform = machine_opts["platform"].strip()
                machine.ip = machine_opts["ip"].strip()

                self.db.add_machine(name=machine.id,
                                    label=machine.label,
                                    ip=machine.ip,
                                    platform=machine.platform)
            except (AttributeError, CuckooOperationalError):
                log.warning("Configuration details about machine %s are missing. Continue", machine_id)
                continue

    def _initialize_check(self):
        """Runs checks against virtualization software when a machine manager 
        is initialized.
        @note: in machine manager modules you may override or superclass 
               his method.
        @raise CuckooMachineError: if a misconfiguration or a unkown vm state
                                   is found.
        """
        try:
            configured_vm = self._list()
        except NotImplementedError:
            return

        for machine in self.machines():
            if machine.label not in configured_vm:
                raise CuckooCriticalError("Configured machine {0} was not detected or it's not in proper state".format(machine.label))

        if not self.options_globals.timeouts.vm_state:
            raise CuckooCriticalError("Virtual machine state change timeout setting not found, please add it to the config file")

    def machines(self):
        """List virtual machines.
        @return: virtual machines list
        """
        return self.db.list_machines()

    def availables(self):
        """How many machines are free.
        @return: free machines count.
        """
        return self.db.count_machines_available()

    def acquire(self, machine_id=None, platform=None):
        """Acquire a machine to start analysis.
        @param machine_id: machine ID.
        @param platform: machine platform.
        @return: machine or None.
        """
        if machine_id:
            return self.db.lock_machine(name=machine_id)
        elif platform:
            return self.db.lock_machine(platform=platform)
        else:
            return self.db.lock_machine()

    def release(self, label=None):
        """Release a machine.
        @param label: machine name.
        """
        self.db.unlock_machine(label)

    def running(self):
        """Returns running virtual machines.
        @return: running virtual machines list.
        """
        return self.db.list_machines(locked=True)

    def shutdown(self):
        """Shutdown the machine manager. Kills all alive machines.
        @raise CuckooMachineError: if unable to stop machine.
        """
        if self.running().count() > 0:
            log.info("Still %s guests alive. Shutting down...", self.running().count())
            for machine in self.running():
                try:
                    self.stop(machine.label)
                except CuckooMachineError as e:
                    log.warning("Unable to shutdown machine %s, please check "
                                "manually. Error: %s", machine.label, e)

    def set_status(self, label, status):
        """Set status for a virtual machine.
        @param label: virtual machine label
        @param status: new virtual machine status
        """
        self.db.set_machine_status(label, status)

    def start(self, label=None):
        """Start a machine.
        @param label: machine name.
        @raise NotImplementedError: this method is abstract.
        """
        raise NotImplementedError

    def stop(self, label=None):
        """Stop a machine.
        @param label: machine name.
        @raise NotImplementedError: this method is abstract.
        """
        raise NotImplementedError

    def _list(self):
        """Lists virtual machines configured.
        @raise NotImplementedError: this method is abstract.
        """
        raise NotImplementedError

    def dump_memory(self, path):
        """Takes a memory dump of a machine.
        @param path: path to where to store the memory dump.
        """
        raise NotImplementedError

    def _wait_status(self, label, state):
        """Waits for a vm status.
        @param label: virtual machine name.
        @param state: virtual machine status, accepts more than one states in a list.
        @raise CuckooMachineError: if default waiting timeout expire.
        """
        # This block was originally suggested by Loic Jaquemet.
        waitme = 0
        try:
            current = self._status(label)
        except NameError:
            return

        if isinstance(state, str):
            state = [state]
        while current not in state:
            log.debug("Waiting %i cuckooseconds for machine %s to switch to status %s", waitme, label, state)
            if waitme > int(self.options_globals.timeouts.vm_state):
                raise CuckooMachineError("Timeout hit while for machine {0} to change status".format(label))
            time.sleep(1)
            waitme += 1
            current = self._status(label)