Exemple #1
0
 def __init__(self,
              initializer=None,
              age=None,
              check_id=None,
              target=None,
              match=None,
              method=None,
              hint=None):
     super(Check, self).__init__(initializer=initializer, age=age)
     self.check_id = check_id
     self.match = MatchStrToList(match)
     self.hint = Hint(hint, reformat=False)
     self.target = target
     if method is None:
         method = []
     self.triggers = triggers.Triggers()
     self.matcher = Matcher(self.match, self.hint)
     for cfg in method:
         # Use the value of "target" as a default for each method, if defined.
         # Targets defined in methods or probes override this default value.
         if hint:
             cfg["hint"] = hints.Overlay(child=cfg.get("hint", {}),
                                         parent=hint)
         if target:
             cfg.setdefault("target", target)
         # Create the method and add its triggers to the check.
         m = Method(**cfg)
         self.method.append(m)
         self.triggers.Update(m.triggers, callback=m)
     self.artifacts = set([t.artifact for t in self.triggers.conditions])
Exemple #2
0
 def __init__(self, initializer=None, age=None, **kwargs):
     if isinstance(initializer, dict):
         conf = initializer
         initializer = None
     else:
         conf = kwargs
     super(Method, self).__init__(initializer=initializer, age=age)
     probe = conf.get("probe", {})
     resource = conf.get("resource", {})
     hint = conf.get("hint", {})
     target = conf.get("target", {})
     if hint:
         # Add the hint to children.
         for cfg in probe:
             cfg["hint"] = hints.Overlay(child=cfg.get("hint", {}),
                                         parent=hint)
     self.probe = [Probe(**cfg) for cfg in probe]
     self.hint = Hint(hint, reformat=False)
     self.match = MatchStrToList(kwargs.get("match"))
     self.matcher = Matcher(self.match, self.hint)
     self.resource = [rdf_protodict.Dict(**r) for r in resource]
     self.target = triggers.Target(**target)
     self.triggers = triggers.Triggers()
     for p in self.probe:
         # If the probe has a target, use it. Otherwise, use the method's target.
         target = p.target or self.target
         self.triggers.Add(p.artifact, target, p)
Exemple #3
0
 def testTriggerRegistry(self):
   t = triggers.Triggers()
   callback_1 = lambda: 1
   callback_2 = lambda: 2
   callback_3 = lambda: 3
   t.Add("GoodAI", target_1, callback_1)
   t.Add("BadAI", target_2, callback_2)
   self.assertItemsEqual([], t.Calls([bad_ai]))
   self.assertItemsEqual([callback_1], t.Calls([good_ai]))
   self.assertItemsEqual([callback_2], t.Calls([t800]))
   self.assertItemsEqual([callback_2], t.Calls([t1000]))
   meta_t = triggers.Triggers()
   meta_t.Update(t, callback_3)
   self.assertItemsEqual([], meta_t.Calls([bad_ai]))
   self.assertItemsEqual([callback_3], meta_t.Calls([good_ai]))
   self.assertItemsEqual([callback_3], meta_t.Calls([t800]))
   self.assertItemsEqual([callback_3], meta_t.Calls([t1000]))
Exemple #4
0
 def testTriggersMatchConditions(self):
   t = triggers.Triggers()
   t.Add("GoodAI", target_1)
   # Get no results if host data doesn't match. TermOS is too general.
   self.assertFalse(t.Match(*termos))
   # Get results if host data is as/more specific than the trigger.
   t.Add("BadAI", target_2)
   self.assertTrue(t.Match(*t800))
   # Adding a BadAI artifact target means any TermOS system should fire.
   t.Add("BadAI", target_1)
   self.assertTrue(t.Match(*termos))
Exemple #5
0
 def testTriggersSearchConditions(self):
   t = triggers.Triggers()
   t.Add("GoodAI", target_1)
   t.Add("BadAI", target_2)
   # Searches return no results if query data doesn't match.
   self.assertEqual([],
                    t.Search(
                        artifact="GoodAI", os_name="TermOS", label="t1000"))
   # Searches return results if query data matches.
   self.assertEqual([good_ai], [c.attr for c in t.Search(artifact="GoodAI")])
   self.assertItemsEqual(
       [t800, t1000], [c.attr for c in t.Search(artifact="BadAI")])
Exemple #6
0
 def testTriggersRequireArtifact(self):
   t = triggers.Triggers()
   self.assertRaises(triggers.DefinitionError, t.Add)
   self.assertRaises(triggers.DefinitionError, t.Add, None, target_1)
Exemple #7
0
 def Clear(cls):
     """Remove all checks and triggers from the registry."""
     cls.checks = {}
     cls.triggers = triggers.Triggers()
Exemple #8
0
class CheckRegistry(object):
    """A class to register the mapping between checks and host data.

  This is used to trigger all relevant checks when we collect the data.
  The method registry maps the combination of platform, environment and host
  data required by a given method.
  """
    checks = {}

    triggers = triggers.Triggers()

    @classmethod
    def Clear(cls):
        """Remove all checks and triggers from the registry."""
        cls.checks = {}
        cls.triggers = triggers.Triggers()

    @classmethod
    def RegisterCheck(cls, check, source="unknown", overwrite_if_exists=False):
        """Adds a check to the registry, refresh the trigger to check map."""
        if not overwrite_if_exists and check.check_id in cls.checks:
            raise DefinitionError("Check named %s already exists and "
                                  "overwrite_if_exists is set to False." %
                                  check.check_id)
        check.loaded_from = source
        cls.checks[check.check_id] = check
        cls.triggers.Update(check.triggers, check)

    @staticmethod
    def _AsList(arg):
        """Encapsulates an argument in a list, if it's not already iterable."""
        if isinstance(arg,
                      basestring) or not isinstance(arg, collections.Iterable):
            return [arg]
        else:
            return list(arg)

    @classmethod
    def Conditions(cls, artifact=None, os_name=None, cpe=None, labels=None):
        """Provide a series of condition tuples.

    A Target can specify multiple artifact, os_name, cpe or label entries. These
    are expanded to all distinct tuples. When an entry is undefined or None, it
    is treated as a single definition of None, meaning that the condition does
    not apply.

    Args:
      artifact: Names of artifacts that should trigger an action.
      os_name: Names of OS' that should trigger an action.
      cpe: CPE strings that should trigger an action.
      labels: Host labels that should trigger an action.

    Yields:
      a permuted series of (artifact, os_name, cpe, label) tuples.
    """
        artifact = cls._AsList(artifact)
        os_name = cls._AsList(os_name)
        cpe = cls._AsList(cpe)
        labels = cls._AsList(labels)
        for condition in itertools.product(artifact, os_name, cpe, labels):
            yield condition

    @classmethod
    def FindChecks(cls,
                   artifact=None,
                   os_name=None,
                   cpe=None,
                   labels=None,
                   restrict_checks=None):
        """Takes targeting info, identifies relevant checks.

    FindChecks will return results when a host has the conditions necessary for
    a check to occur. Conditions with partial results are not returned. For
    example, FindChecks will not return checks that if a check targets
    os_name=["Linux"], labels=["foo"] and a host only has the os_name=["Linux"]
    attribute.

    Args:
      artifact: 0+ artifact names.
      os_name: 0+ OS names.
      cpe: 0+ CPE identifiers.
      labels: 0+ GRR labels.
      restrict_checks: A list of check ids to restrict check processing to.

    Returns:
      the check_ids that apply.
    """
        check_ids = set()
        conditions = list(cls.Conditions(artifact, os_name, cpe, labels))
        for chk_id, chk in cls.checks.iteritems():
            if restrict_checks and chk_id not in restrict_checks:
                continue
            for condition in conditions:
                if chk.triggers.Match(*condition):
                    check_ids.add(chk_id)
                    break  # No need to keep checking other conditions.
        return check_ids

    @classmethod
    def SelectArtifacts(cls,
                        os_name=None,
                        cpe=None,
                        labels=None,
                        restrict_checks=None):
        """Takes targeting info, identifies artifacts to fetch.

    Args:
      os_name: 0+ OS names.
      cpe: 0+ CPE identifiers.
      labels: 0+ GRR labels.
      restrict_checks: A list of check ids whose artifacts should be fetched.

    Returns:
      the artifacts that should be collected.
    """
        results = set()
        for condition in cls.Conditions(None, os_name, cpe, labels):
            trigger = condition[1:]
            for chk in cls.checks.values():
                if restrict_checks and chk.check_id not in restrict_checks:
                    continue
                results.update(chk.triggers.Artifacts(*trigger))
        return results

    @classmethod
    def Process(cls,
                host_data,
                os_name=None,
                cpe=None,
                labels=None,
                exclude_checks=None,
                restrict_checks=None):
        """Runs checks over all host data.

    Args:
      host_data: The data collected from a host, mapped to artifact name.
      os_name: 0+ OS names.
      cpe: 0+ CPE identifiers.
      labels: 0+ GRR labels.
      exclude_checks: A list of check ids not to run. A check id in this list
                      will not get run even if included in restrict_checks.
      restrict_checks: A list of check ids that may be run, if appropriate.

    Yields:
      A CheckResult message for each check that was performed.
    """
        # All the conditions that apply to this host.
        artifacts = host_data.keys()
        check_ids = cls.FindChecks(artifacts, os_name, cpe, labels)
        conditions = list(cls.Conditions(artifacts, os_name, cpe, labels))
        for check_id in check_ids:
            # skip if check in list of excluded checks
            if exclude_checks and check_id in exclude_checks:
                continue
            if restrict_checks and check_id not in restrict_checks:
                continue
            try:
                chk = cls.checks[check_id]
                yield chk.Parse(conditions, host_data)
            except ProcessingError as e:
                logging.warn("Check ID %s raised: %s", check_id, e)