示例#1
0
    def testSerialization(self):
        test_dict = dict(
            key1=1,  # Integer.
            key2="foo",  # String.
            key3=u"\u4f60\u597d",  # Unicode.
            key5=rdfvalue.RDFDatetime("2012/12/11"),  # RDFValue.
            key6=None,  # Support None Encoding.
            key7=structs.Enum(5, name="Test"),  # Integer like objects.
        )

        # Initialize through keywords.
        sample = rdfvalue.Dict(**test_dict)
        self.CheckTestDict(test_dict, sample)

        # Initialize through dict.
        sample = rdfvalue.Dict(test_dict)
        self.CheckTestDict(test_dict, sample)

        # Initialize through a serialized form.
        serialized = sample.SerializeToString()
        self.assertIsInstance(serialized, str)

        sample = rdfvalue.Dict(serialized)
        self.CheckTestDict(test_dict, sample)

        # Convert to a dict.
        self.CheckTestDict(test_dict, sample.ToDict())
示例#2
0
    def testNestedDictsOpaqueTypes(self):
        class UnSerializable(object):
            pass

        test_dict = dict(key1={"A": 1},
                         key2=rdfvalue.Dict({"A": 1}),
                         key3=[1, UnSerializable(), 3, [1, 2, [3]]],
                         key4=[[], None, ["abc"]],
                         key5=UnSerializable(),
                         key6=["a", UnSerializable(), "b"])

        self.assertRaises(TypeError, rdfvalue.Dict, **test_dict)

        sample = rdfvalue.Dict()
        for key, value in test_dict.iteritems():
            sample.SetItem(key, value, raise_on_error=False)

        # Need to do some manual checking here since this is a lossy conversion.
        self.assertEqual(test_dict["key1"], sample["key1"])
        self.assertEqual(test_dict["key2"], sample["key2"])

        self.assertEqual(1, sample["key3"][0])
        self.assertTrue("Unsupported type" in sample["key3"][1])
        self.assertItemsEqual(test_dict["key3"][2:], sample["key3"][2:])

        self.assertEqual(test_dict["key4"], sample["key4"])
        self.assertTrue("Unsupported type" in sample["key5"])
        self.assertEqual("a", sample["key6"][0])
        self.assertTrue("Unsupported type" in sample["key6"][1])
        self.assertEqual("b", sample["key6"][2])
示例#3
0
    def testNestedDicts(self):
        test_dict = dict(
            key1={"A": 1},
            key2=rdfvalue.Dict({"A": 1}),
        )

        sample = rdfvalue.Dict(**test_dict)
        self.CheckTestDict(test_dict, sample)
        self.CheckTestDict(test_dict, sample.ToDict())
示例#4
0
    def testNestedDictsMultipleTypes(self):
        test_dict = dict(key1={"A": 1},
                         key2=rdfvalue.Dict({"A": 1}),
                         key3=[1, 2, 3, [1, 2, [3]]],
                         key4=[[], None, ["abc"]])

        sample = rdfvalue.Dict(**test_dict)
        self.CheckTestDict(test_dict, sample)
        self.CheckTestDict(test_dict, sample.ToDict())
示例#5
0
    def testOverwriting(self):
        req = rdfvalue.Iterator(client_state=rdfvalue.Dict({"A": 1}))
        # There should be one element now.
        self.assertEqual(len(list(req.client_state.items())), 1)

        req.client_state = rdfvalue.Dict({"B": 2})
        # Still one element.
        self.assertEqual(len(list(req.client_state.items())), 1)

        req.client_state = rdfvalue.Dict({})

        # And now it's gone.
        self.assertEqual(len(list(req.client_state.items())), 0)
示例#6
0
    def testUpdateConfig(self):
        """Ensure we can retrieve and update the config."""

        # Only mock the pieces we care about.
        client_mock = action_mocks.ActionMock("GetConfiguration",
                                              "UpdateConfiguration")

        loc = "http://www.example.com"
        new_config = rdfvalue.Dict({
            "Client.control_urls": [loc],
            "Client.foreman_check_frequency": 3600,
            "Client.poll_min": 1
        })

        # Write the config.
        for _ in test_lib.TestFlowHelper("UpdateConfiguration",
                                         client_mock,
                                         client_id=self.client_id,
                                         token=self.token,
                                         config=new_config):
            pass

        # Now retrieve it again to see if it got written.
        for _ in test_lib.TestFlowHelper("Interrogate",
                                         client_mock,
                                         token=self.token,
                                         client_id=self.client_id):
            pass

        fd = aff4.FACTORY.Open(self.client_id, token=self.token)
        config_dat = fd.Get(fd.Schema.GRR_CONFIGURATION)
        self.assertEqual(config_dat["Client.control_urls"], [loc])
        self.assertEqual(config_dat["Client.poll_min"], 1)
示例#7
0
文件: checks.py 项目: zzzzpaul/grr
 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 = checks.Matcher(self.match, self.hint)
     self.resource = [rdfvalue.Dict(**r) for r in resource]
     self.target = 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)
示例#8
0
    def ParseMultiple(self, stats, file_objects, knowledge_base):
        """Parse the found release files."""
        _ = knowledge_base

        # Collate files into path: contents dictionary.
        found_files = self._Combine(stats, file_objects)

        # Determine collected files and apply weighting.
        weights = [w for w in self.WEIGHTS if w.path in found_files]
        weights = sorted(weights, key=lambda x: x.weight)

        for _, path, handler in weights:
            contents = found_files[path]
            obj = handler(contents)

            complete, result = obj.Parse()
            if result is None:
                continue
            elif complete:
                yield rdfvalue.Dict({
                    'os_release': result.release,
                    'os_major_version': result.major,
                    'os_minor_version': result.minor
                })
                break
        else:
            # No successful parse.
            yield rdfvalue.Anomaly(type='PARSER_ANOMALY',
                                   symptom='Unable to determine distribution.')
示例#9
0
 def Parse(self, stat, knowledge_base):
     _ = stat, knowledge_base
     test_dict = {
         "environ_temp": rdfvalue.RDFString("tempvalue"),
         "environ_path": rdfvalue.RDFString("pathvalue")
     }
     yield rdfvalue.Dict(test_dict)
示例#10
0
    def testVolatilityModules(self):
        """Tests the end to end volatility memory analysis."""
        image_path = os.path.join(self.base_path, "win7_trial_64bit.raw")
        if not os.access(image_path, os.R_OK):
            logging.warning(
                "Unable to locate test memory image. Skipping test.")
            return

        self.CreateClient()
        self.CreateSignedDriver()

        class ClientMock(test_lib.MemoryClientMock):
            """A mock which returns the image as the driver path."""
            def GetMemoryInformation(self, _):
                """Mock out the driver loading code to pass the memory image."""
                reply = rdfvalue.MemoryInformation(device=rdfvalue.PathSpec(
                    path=image_path, pathtype=rdfvalue.PathSpec.PathType.OS))

                reply.runs.Append(offset=0, length=1000000000)

                return [reply]

        request = rdfvalue.VolatilityRequest()
        request.args["pslist"] = {}
        request.args["modules"] = {}

        # To speed up the test we provide these values. In real life these values
        # will be provided by the kernel driver.
        request.session = rdfvalue.Dict(dtb=0x187000, kdbg=0xF80002803070)

        # Allow the real VolatilityAction to run against the image.
        for _ in test_lib.TestFlowHelper("AnalyzeClientMemory",
                                         ClientMock("VolatilityAction"),
                                         token=self.token,
                                         client_id=self.client_id,
                                         request=request,
                                         output="analysis/memory"):
            pass

        fd = aff4.FACTORY.Open(self.client_id.Add("analysis/memory/pslist"),
                               token=self.token)

        result = fd.Get(fd.Schema.RESULT)

        # Pslist should have 32 rows.
        self.assertEqual(len(result.sections[0].table.rows), 32)

        # And should include the DumpIt binary.
        self.assert_("DumpIt.exe" in str(result))

        fd = aff4.FACTORY.Open(self.client_id.Add("analysis/memory/modules"),
                               token=self.token)
        result = fd.Get(fd.Schema.RESULT)

        # Modules should have 133 lines.
        self.assertEqual(len(result.sections[0].table.rows), 133)

        # And should include the DumpIt kernel driver.
        self.assert_("DumpIt.sys" in str(result))
示例#11
0
 def GetConfiguration(self, _):
     return [
         rdfvalue.Dict({
             "Client.control_urls": ["http://localhost:8001/control"],
             "Client.poll_min":
             1.0
         })
     ]
示例#12
0
    def Run(self, args):
        """Run the WMI query and return the data."""
        query = args.query
        base_object = args.base_object or r"winmgmts:\root\cimv2"

        if not query.upper().startswith("SELECT "):
            raise RuntimeError("Only SELECT WMI queries allowed.")

        # Now return the data to the server
        for response_dict in RunWMIQuery(query, baseobj=base_object):
            self.SendReply(rdfvalue.Dict(response_dict))
示例#13
0
    def testDictBehaviour(self):
        tested = rdfvalue.Dict(a=1)

        now = rdfvalue.RDFDatetime().Now()
        tested["b"] = now

        self.assertEqual(tested["b"], now)
        self.assertEqual(tested["a"], 1)

        tested["b"] = rdfvalue.RDFURN("aff4:/users/")
        self.assertEqual(len(tested), 2)
        self.assertEqual(tested["b"].SerializeToString(), "aff4:/users")
示例#14
0
  def testGetConfig(self):
    """Check GetConfig client action works."""
    # Use UpdateConfig to generate a config.
    location = ["http://example.com"]
    request = rdfvalue.Dict()
    request["Client.control_urls"] = location
    request["Client.foreman_check_frequency"] = 3600

    self.RunAction("UpdateConfiguration", request)
    # Check that our GetConfig actually gets the real data.
    self.RunAction("GetConfiguration")

    self.assertEqual(config_lib.CONFIG["Client.foreman_check_frequency"], 3600)
    self.assertEqual(config_lib.CONFIG["Client.control_urls"], location)
示例#15
0
    def Run(self, request):
        """Munge the iterator to the server and abstract it away."""
        # Pass the client_state as a dict to the action. This is often more
        # efficient than manipulating a protobuf.
        client_state = request.iterator.client_state.ToDict()

        # Derived classes should implement this.
        self.Iterate(request, client_state)

        # Update the iterator client_state from the dict.
        request.iterator.client_state = rdfvalue.Dict(client_state)

        # Return the iterator
        self.SendReply(request.iterator,
                       message_type=rdfvalue.GrrMessage.Type.ITERATOR)
示例#16
0
    def testArgs(self):
        """Test passing arguments."""
        utils.TEST_VAL = "original"
        python_code = """
magic_return_str = py_args['test']
utils.TEST_VAL = py_args[43]
"""
        signed_blob = rdfvalue.SignedBlob()
        signed_blob.Sign(python_code, self.signing_key)
        pdict = rdfvalue.Dict({"test": "dict_arg", 43: "dict_arg2"})
        request = rdfvalue.ExecutePythonRequest(python_code=signed_blob,
                                                py_args=pdict)
        result = self.RunAction("ExecutePython", request)[0]
        self.assertEqual(result.return_val, "dict_arg")
        self.assertEqual(utils.TEST_VAL, "dict_arg2")
    def testInterfaceParsing(self):
        parser = wmi_parser.WMIInterfacesParser()
        rdf_dict = rdfvalue.Dict()
        wmi_properties = (
            client_fixture.WMIWin32NetworkAdapterConfigurationMock.__dict__.
            iteritems())
        for key, value in wmi_properties:
            if not key.startswith("__"):
                try:
                    rdf_dict[key] = value
                except TypeError:
                    rdf_dict[key] = "Failed to encode: %s" % value

        result_list = list(parser.Parse(None, rdf_dict, None))
        self.assertEqual(len(result_list), 2)
        for result in result_list:
            if isinstance(result, rdfvalue.Interface):
                self.assertEqual(len(result.addresses), 4)
                self.assertItemsEqual(
                    [x.human_readable_address for x in result.addresses], [
                        "192.168.1.20", "ffff::ffff:aaaa:1111:aaaa",
                        "dddd:0:8888:6666:bbbb:aaaa:eeee:bbbb",
                        "dddd:0:8888:6666:bbbb:aaaa:ffff:bbbb"
                    ])

                self.assertItemsEqual([
                    x.human_readable_address for x in result.dhcp_server_list
                ], ["192.168.1.1"])

                self.assertEqual(
                    result.dhcp_lease_expires.AsMicroSecondsFromEpoch(),
                    1409008979123456)
                self.assertEqual(
                    result.dhcp_lease_obtained.AsMicroSecondsFromEpoch(),
                    1408994579123456)

            elif isinstance(result, rdfvalue.DNSClientConfiguration):
                self.assertItemsEqual(
                    result.dns_server,
                    ["192.168.1.1", "192.168.255.81", "192.168.128.88"])

                self.assertItemsEqual(result.dns_suffix, [
                    "blah.example.com", "ad.example.com",
                    "internal.example.com", "example.com"
                ])
示例#18
0
    def testUpdateConfigBlacklist(self):
        """Tests that disallowed fields are not getting updated."""

        config_lib.CONFIG.Set("Client.control_urls", ["http://something.com/"])
        config_lib.CONFIG.Set("Client.server_serial_number", 1)

        location = ["http://www.example.com"]
        request = rdfvalue.Dict()
        request["Client.control_urls"] = location
        request["Client.server_serial_number"] = 10

        self.RunAction("UpdateConfiguration", request)

        # Location can be set.
        self.assertEqual(config_lib.CONFIG["Client.control_urls"], location)

        # But the server serial number can not be updated.
        self.assertEqual(config_lib.CONFIG["Client.server_serial_number"], 1)
示例#19
0
    def ProcessFileStats(self, responses):
        """Extract DataBlob from Stat response."""
        if not responses.success:
            return
        system_root_paths = ["Windows", "WinNT", "WINNT35", "WTSRV"]

        for response in responses:
            if response.pathspec.path[4:] in system_root_paths:
                systemdrive = response.pathspec.path[1:3]
                systemroot = "%s\\%s" % (systemdrive,
                                         response.pathspec.path[4:])
                self.SendReply(
                    rdfvalue.Dict({
                        "environ_systemroot": systemroot,
                        "environ_systemdrive": systemdrive
                    }))
                self.state.bootstrap_initialized = True
                break
示例#20
0
 def testRdfFormatterFanOut(self):
     rdf = rdfvalue.Dict()
     user1 = rdfvalue.KnowledgeBaseUser(username="******")
     user2 = rdfvalue.KnowledgeBaseUser(username="******")
     rdf["cataclysm"] = "GreyGoo"
     rdf["thinkers"] = [user1, user2]
     rdf["reference"] = {
         "ecophage": ["bots", ["nanobots", ["picobots"]]],
         "doomsday": {
             "books": ["cats cradle", "prey"]
         }
     }
     template = ("{cataclysm}; {thinkers.username}; {reference.ecophage}; "
                 "{reference.doomsday}")
     hinter = hints.Hinter(template=template)
     expected = ("GreyGoo; drexler,joy; bots,nanobots,picobots; "
                 "books:cats cradle,prey")
     result = hinter.Render(rdf)
     self.assertEqual(expected, result)
示例#21
0
    def testUpdateConfiguration(self):
        """Test that we can update the config."""
        # A unique name on the filesystem for the writeback.
        self.config_file = os.path.join(self.temp_dir, "ConfigActionTest.yaml")

        # In a real client, the writeback location should be set to something real,
        # but for this test we make it the same as the config file..
        config_lib.CONFIG.SetWriteBack(self.config_file)

        # Make sure the file is gone
        self.assertRaises(IOError, open, self.config_file)

        location = ["http://www.example1.com/", "http://www.example2.com/"]
        request = rdfvalue.Dict()
        request["Client.control_urls"] = location
        request["Client.foreman_check_frequency"] = 3600

        result = self.RunAction("UpdateConfiguration", request)

        self.assertEqual(result, [])
        self.assertEqual(config_lib.CONFIG["Client.foreman_check_frequency"],
                         3600)

        # Test the config file got written.
        data = open(self.config_file).read()
        self.assertTrue("control_urls: {0}".format(",".join(location)) in data)

        self.urls = []

        # Now test that our location was actually updated.

        def FakeUrlOpen(req, timeout=10):
            _ = timeout
            self.urls.append(req.get_full_url())
            return StringIO.StringIO()

        comms.urllib2.urlopen = FakeUrlOpen
        client_context = comms.GRRHTTPClient(worker=MockClientWorker)
        client_context.MakeRequest("", comms.Status())

        self.assertTrue(location[0] in self.urls[0])
        self.assertTrue(location[1] in self.urls[1])
示例#22
0
 def WmiQuery(self, query):
     if query.query == u"SELECT * FROM Win32_LogicalDisk":
         self.response_count += 1
         return client_fixture.WMI_SAMPLE
     elif query.query.startswith("Select * "
                                 "from Win32_NetworkAdapterConfiguration"):
         self.response_count += 1
         rdf_dict = rdfvalue.Dict()
         wmi_properties = (
             client_fixture.WMIWin32NetworkAdapterConfigurationMock.
             __dict__.iteritems())
         for key, value in wmi_properties:
             if not key.startswith("__"):
                 try:
                     rdf_dict[key] = value
                 except TypeError:
                     rdf_dict[key] = "Failed to encode: %s" % value
         return [rdf_dict]
     else:
         return None
示例#23
0
文件: windows.py 项目: zzzzpaul/grr
def RunWMIQuery(query, baseobj=r"winmgmts:\root\cimv2"):
    """Run a WMI query and return a result.

  Args:
    query: the WMI query to run.
    baseobj: the base object for the WMI query.

  Yields:
    rdfvalue.Dicts containing key value pairs from the resulting COM objects.
  """
    pythoncom.CoInitialize()  # Needs to be called if using com from a thread.
    wmi_obj = win32com.client.GetObject(baseobj)
    # This allows our WMI to do some extra things, in particular
    # it gives it access to find the executable path for all processes.
    wmi_obj.Security_.Privileges.AddAsString("SeDebugPrivilege")

    # Run query
    try:
        query_results = wmi_obj.ExecQuery(query)
    except pythoncom.com_error as e:
        raise RuntimeError("Failed to run WMI query \'%s\' err was %s" %
                           (query, e))

    # Extract results from the returned COMObject and return dicts.
    try:
        for result in query_results:
            response = rdfvalue.Dict()
            for prop in result.Properties_:
                if prop.Name not in IGNORE_PROPS:
                    # Protodict can handle most of the types we care about, but we may
                    # get some objects that we don't know how to serialize, so we tell the
                    # dict to set the value to an error message and keep going
                    response.SetItem(prop.Name,
                                     prop.Value,
                                     raise_on_error=False)
            yield response

    except pythoncom.com_error as e:
        raise RuntimeError("WMI query data error on query \'%s\' err was %s" %
                           (e, query))
    def SetupRequest(self, plugin):
        # Only run this test if the image file is found.
        image_path = os.path.join(self.base_path, "win7_trial_64bit.raw")
        if not os.access(image_path, os.R_OK):
            logging.warning(
                "Unable to locate test memory image. Skipping test.")
            return False

        self.request = rdfvalue.VolatilityRequest(
            device=rdfvalue.PathSpec(path=image_path,
                                     pathtype=rdfvalue.PathSpec.PathType.OS),
            # To speed up the test we provide these values. In real life these
            # values will be provided by the kernel driver.
            session=rdfvalue.Dict(dtb=0x187000, kdbg=0xF80002803070))

        # In this test we explicitly do not set the profile to use so we can see if
        # the profile autodetection works.

        # Add the plugin to the request.
        self.request.args[plugin] = None

        return True
    def testParameters(self):
        if not self.SetupRequest("pslist"):
            return

        args = {"pslist": {"pid": 2860}}

        self.request.args = rdfvalue.Dict(args)

        result = self.RunAction("VolatilityAction", self.request)

        # There should be 1 result back.
        self.assertEqual(len(result), 1)

        # There should be one section.
        self.assertEqual(len(result[0].sections), 1)

        rows = result[0].sections[0].table.rows
        # Pslist should now have 1 result.
        self.assertEqual(len(rows), 1)

        name = rows[0].values[1].GetValue()

        self.assertTrue("DumpIt.exe" in name)
示例#26
0
    def ProcessRegStat(self, responses):
        """Check SystemRoot registry value."""
        if responses.success:
            systemroot = responses.First().registry_data.GetValue()
            if systemroot:
                systemdrive = systemroot[0:2]
                if re.match(r"^[A-Za-z]:$", systemdrive):
                    self.SendReply(
                        rdfvalue.Dict({
                            "environ_systemroot": systemroot,
                            "environ_systemdrive": systemdrive
                        }))
                    self.state.bootstrap_initialized = True
                    return

        # If registry querying didn't work, we try to guess common paths instead.
        system_drive_opts = ["C:", "D:"]
        for drive in system_drive_opts:
            pathspec = rdfvalue.PathSpec(
                path=drive, pathtype=rdfvalue.PathSpec.PathType.OS)
            self.CallClient("ListDirectory",
                            pathspec=pathspec,
                            request_data={"bootstrap_var": "system_root"},
                            next_state="ProcessFileStats")
示例#27
0
from grr.lib import config_lib
from grr.lib import flags
from grr.lib import flow
from grr.lib import parsers
from grr.lib import rdfvalue
from grr.lib import test_lib
from grr.lib import utils

# pylint: mode=test

WMI_SAMPLE = [
    rdfvalue.Dict({
        u"Version": u"65.61.49216",
        u"InstallDate2": u"",
        u"Name": u"Google Chrome",
        u"Vendor": u"Google, Inc.",
        u"Description": u"Google Chrome",
        u"IdentifyingNumber": u"{35790B21-ACFE-33F5-B320-9DA320D96682}",
        u"InstallDate": u"20130710"
    }),
    rdfvalue.Dict({
        u"Version": u"7.0.1",
        u"InstallDate2": u"",
        u"Name": u"Parity Agent",
        u"Vendor": u"Bit9, Inc.",
        u"Description": u"Parity Agent",
        u"IdentifyingNumber": u"{ADC7EB41-4CC2-4FBA-8FBE-9338A9FB7666}",
        u"InstallDate": u"20130710"
    }),
    rdfvalue.Dict({
        u"Version": u"8.0.61000",
示例#28
0
    def CallState(self,
                  messages=None,
                  next_state="",
                  client_id=None,
                  request_data=None,
                  start_time=None):
        """This method is used to asynchronously schedule a new hunt state.

    The state will be invoked in a later time and receive all the messages
    we send.

    Args:
      messages: A list of rdfvalues to send. If the last one is not a
              GrrStatus, we append an OK Status.

      next_state: The state in this hunt to be invoked with the responses.

      client_id: ClientURN to use in scheduled requests.

      request_data: Any dict provided here will be available in the
                    RequestState protobuf. The Responses object maintains a
                    reference to this protobuf for use in the execution of the
                    state method. (so you can access this data by
                    responses.request).

      start_time: Schedule the state at this time. This delays notification
                  and messages for processing into the future.
    Raises:
      ValueError: on arguments error.
    """

        if messages is None:
            messages = []

        if not next_state:
            raise ValueError("next_state can't be empty.")

        # Now we construct a special response which will be sent to the hunt
        # flow. Randomize the request_id so we do not overwrite other messages in
        # the queue.
        request_state = rdfvalue.RequestState(
            id=utils.PRNG.GetULong(),
            session_id=self.context.session_id,
            client_id=client_id,
            next_state=next_state)

        if request_data:
            request_state.data = rdfvalue.Dict().FromDict(request_data)

        self.QueueRequest(request_state, timestamp=start_time)

        # Add the status message if needed.
        if not messages or not isinstance(messages[-1], rdfvalue.GrrStatus):
            messages.append(rdfvalue.GrrStatus())

        # Send all the messages
        for i, payload in enumerate(messages):
            if isinstance(payload, rdfvalue.RDFValue):
                msg = rdfvalue.GrrMessage(
                    session_id=self.session_id,
                    request_id=request_state.id,
                    response_id=1 + i,
                    auth_state=rdfvalue.GrrMessage.AuthorizationState.
                    AUTHENTICATED,
                    payload=payload,
                    type=rdfvalue.GrrMessage.Type.MESSAGE)

                if isinstance(payload, rdfvalue.GrrStatus):
                    msg.type = rdfvalue.GrrMessage.Type.STATUS
            else:
                raise flow_runner.FlowRunnerError(
                    "Bad message %s of type %s." % (payload, type(payload)))

            self.QueueResponse(msg, timestamp=start_time)

        # Add the status message if needed.
        if not messages or not isinstance(messages[-1], rdfvalue.GrrStatus):
            messages.append(rdfvalue.GrrStatus())

        # Notify the worker about it.
        self.QueueNotification(session_id=self.session_id,
                               timestamp=start_time)
示例#29
0
    def CallFlow(self,
                 flow_name=None,
                 next_state=None,
                 sync=True,
                 request_data=None,
                 client_id=None,
                 base_session_id=None,
                 output=None,
                 **kwargs):
        """Creates a new flow and send its responses to a state.

    This creates a new flow. The flow may send back many responses which will be
    queued by the framework until the flow terminates. The final status message
    will cause the entire transaction to be committed to the specified state.

    Args:
       flow_name: The name of the flow to invoke.

       next_state: The state in this flow, that responses to this
       message should go to.

       sync: If True start the flow inline on the calling thread, else schedule
         a worker to actually start the child flow.

       request_data: Any dict provided here will be available in the
             RequestState protobuf. The Responses object maintains a reference
             to this protobuf for use in the execution of the state method. (so
             you can access this data by responses.request). There is no
             format mandated on this data but it may be a serialized protobuf.

       client_id: If given, the flow is started for this client.

       base_session_id: A URN which will be used to build a URN.

       output: A relative output name for the child collection. Normally
         subflows do not write their own collections, but this can be specified
         to change this behaviour.

       **kwargs: Arguments for the child flow.

    Raises:
       FlowRunnerError: If next_state is not one of the allowed next states.

    Returns:
       The URN of the child flow which was created.
    """
        if self.process_requests_in_order:
            # Check that the next state is allowed
            if next_state and next_state not in self.context.next_states:
                raise FlowRunnerError(
                    "Flow %s: State '%s' called to '%s' which is "
                    "not declared in decorator." %
                    (self.__class__.__name__, self.context.current_state,
                     next_state))

        client_id = client_id or self.args.client_id

        # This looks very much like CallClient() above - we prepare a request state,
        # and add it to our queue - any responses from the child flow will return to
        # the request state and the stated next_state. Note however, that there is
        # no client_id or actual request message here because we directly invoke the
        # child flow rather than queue anything for it.
        state = rdfvalue.RequestState(id=self.GetNextOutboundId(),
                                      session_id=utils.SmartUnicode(
                                          self.session_id),
                                      client_id=client_id,
                                      next_state=next_state,
                                      response_count=0)

        if request_data:
            state.data = rdfvalue.Dict().FromDict(request_data)

        # If the urn is passed explicitly (e.g. from the hunt runner) use that,
        # otherwise use the urn from the flow_runner args. If both are None, create
        # a new collection and give the urn to the flow object.
        logs_urn = self._GetLogsCollectionURN(
            kwargs.pop("logs_collection_urn", None)
            or self.args.logs_collection_urn)

        # If we were called with write_intermediate_results, propagate down to
        # child flows.  This allows write_intermediate_results to be set to True
        # either at the top level parent, or somewhere in the middle of
        # the call chain.
        write_intermediate = (kwargs.pop("write_intermediate_results", False)
                              or getattr(self.args,
                                         "write_intermediate_results", False))

        # Create the new child flow but do not notify the user about it.
        child_urn = self.flow_obj.StartFlow(
            client_id=client_id,
            flow_name=flow_name,
            base_session_id=base_session_id or self.session_id,
            event_id=self.context.get("event_id"),
            request_state=state,
            token=self.token,
            notify_to_user=False,
            parent_flow=self.flow_obj,
            _store=self.data_store,
            sync=sync,
            output=output,
            queue=self.args.queue,
            write_intermediate_results=write_intermediate,
            logs_collection_urn=logs_urn,
            creator=self.context.creator,
            **kwargs)

        self.QueueRequest(state)

        return child_urn
示例#30
0
    def CallClient(self,
                   action_name,
                   request=None,
                   next_state=None,
                   client_id=None,
                   request_data=None,
                   start_time=None,
                   **kwargs):
        """Calls the client asynchronously.

    This sends a message to the client to invoke an Action. The run
    action may send back many responses. These will be queued by the
    framework until a status message is sent by the client. The status
    message will cause the entire transaction to be committed to the
    specified state.

    Args:
       action_name: The function to call on the client.

       request: The request to send to the client. If not specified (Or None) we
             create a new RDFValue using the kwargs.

       next_state: The state in this flow, that responses to this
             message should go to.

       client_id: rdfvalue.ClientURN to send the request to.

       request_data: A dict which will be available in the RequestState
             protobuf. The Responses object maintains a reference to this
             protobuf for use in the execution of the state method. (so you can
             access this data by responses.request). Valid values are
             strings, unicode and protobufs.

       start_time: Call the client at this time. This Delays the client request
         for into the future.

       **kwargs: These args will be used to construct the client action semantic
         protobuf.

    Raises:
       FlowRunnerError: If next_state is not one of the allowed next states.
       RuntimeError: The request passed to the client does not have the correct
                     type.
    """
        if client_id is None:
            client_id = self.args.client_id

        if client_id is None:
            raise FlowRunnerError(
                "CallClient() is used on a flow which was not "
                "started with a client.")

        if not isinstance(client_id, rdfvalue.ClientURN):
            # Try turning it into a ClientURN
            client_id = rdfvalue.ClientURN(client_id)

        # Retrieve the correct rdfvalue to use for this client action.
        try:
            action = actions.ActionPlugin.classes[action_name]
        except KeyError:
            raise RuntimeError("Client action %s not found." % action_name)

        if action.in_rdfvalue is None:
            if request:
                raise RuntimeError("Client action %s does not expect args." %
                                   action_name)
        else:
            if request is None:
                # Create a new rdf request.
                request = action.in_rdfvalue(**kwargs)
            else:
                # Verify that the request type matches the client action requirements.
                if not isinstance(request, action.in_rdfvalue):
                    raise RuntimeError("Client action expected %s but got %s" %
                                       (action.in_rdfvalue, type(request)))

        outbound_id = self.GetNextOutboundId()

        # Create a new request state
        state = rdfvalue.RequestState(id=outbound_id,
                                      session_id=self.session_id,
                                      next_state=next_state,
                                      client_id=client_id)

        if request_data is not None:
            state.data = rdfvalue.Dict(request_data)

        # Send the message with the request state
        msg = rdfvalue.GrrMessage(session_id=utils.SmartUnicode(
            self.session_id),
                                  name=action_name,
                                  request_id=outbound_id,
                                  priority=self.args.priority,
                                  require_fastpoll=self.args.require_fastpoll,
                                  queue=client_id.Queue(),
                                  payload=request)

        if self.context.remaining_cpu_quota:
            msg.cpu_limit = int(self.context.remaining_cpu_quota)

        cpu_usage = self.context.client_resources.cpu_usage
        if self.context.args.cpu_limit:
            msg.cpu_limit = max(
                self.context.args.cpu_limit - cpu_usage.user_cpu_time -
                cpu_usage.system_cpu_time, 0)

            if msg.cpu_limit == 0:
                raise FlowRunnerError("CPU limit exceeded.")

        if self.context.args.network_bytes_limit:
            msg.network_bytes_limit = max(
                self.context.args.network_bytes_limit -
                self.context.network_bytes_sent, 0)
            if msg.network_bytes_limit == 0:
                raise FlowRunnerError("Network limit exceeded.")

        state.request = msg

        self.QueueRequest(state, timestamp=start_time)