def Handle(self, args, token=None): if not args.username: raise ValueError("username can't be empty.") user_urn = aff4.ROOT_URN.Add("users").Add(args.username) events.Events.PublishEvent("Audit", rdf_events.AuditEvent(user=token.username, action="USER_UPDATE", urn=user_urn), token=token) with aff4.FACTORY.Open(user_urn, aff4_type=users.GRRUser, mode="rw", token=token) as fd: if args.HasField("password"): fd.SetPassword(args.password) if args.user_type == args.UserType.USER_TYPE_ADMIN: fd.AddLabels(["admin"], owner="GRR") elif args.user_type == args.UserType.USER_TYPE_STANDARD: fd.RemoveLabels(["admin"], owner="GRR") return api_user.ApiGrrUser().InitFromAff4Object(fd)
def Handle(self, args, token=None): audit_description = ",".join([ token.username + u"." + utils.SmartUnicode(name) for name in args.labels ]) audit_events = [] try: for api_client_id in args.client_ids: audit_events.append( rdf_events.AuditEvent( user=token.username, action="CLIENT_ADD_LABEL", flow_name="handler.ApiAddClientsLabelsHandler", client=api_client_id.ToClientURN(), description=audit_description)) for api_client_id in args.client_ids: cid = unicode(api_client_id) try: data_store.REL_DB.AddClientLabels(cid, token.username, args.labels) idx = client_index.ClientIndex() idx.AddClientLabels(cid, args.labels) except db.UnknownClientError: # TODO(amoser): Remove after data migration. pass finally: events.Events.PublishMultipleEvents( {audit.AUDIT_EVENT: audit_events}, token=token)
def AddFakeAuditLog(description=None, client=None, user=None, action=None, flow_name=None, urn=None, router_method_name=None, http_request_path=None, token=None): events.Events.PublishEvent( "Audit", rdf_events.AuditEvent( description=description, client=client, urn=urn, user=user, action=action, flow_name=flow_name), token=token) if data_store.RelationalDBWriteEnabled(): data_store.REL_DB.WriteAPIAuditEntry( rdf_objects.APIAuditEntry( username=user, router_method_name=router_method_name, http_request_path=http_request_path, ))
def Handle(self, args, token=None): audit_description = ",".join([ token.username + u"." + utils.SmartUnicode(name) for name in args.labels ]) audit_events = [] try: for client_id in args.client_ids: cid = unicode(client_id) data_store.REL_DB.RemoveClientLabels(cid, token.username, args.labels) labels_to_remove = set(args.labels) existing_labels = data_store.REL_DB.ReadClientLabels(cid) for label in existing_labels: labels_to_remove.discard(label.name) if labels_to_remove: idx = client_index.ClientIndex() idx.RemoveClientLabels(cid, labels_to_remove) audit_events.append( rdf_events.AuditEvent( user=token.username, action="CLIENT_REMOVE_LABEL", flow_name="handler.ApiRemoveClientsLabelsHandler", client=client_id.ToClientURN(), description=audit_description)) finally: events.Events.PublishMultipleEvents( {audit.AUDIT_EVENT: audit_events}, token=token)
def AddUser(username, password=None, labels=None, token=None): """Implementation of the add_user command.""" if not username: raise UserError("Cannot add user: User must have a non-empty name") token = data_store.GetDefaultToken(token) user_urn = "aff4:/users/%s" % username try: if aff4.FACTORY.Open(user_urn, users.GRRUser, token=token): raise UserError("Cannot add user %s: User already exists." % username) except aff4.InstantiationError: pass fd = aff4.FACTORY.Create(user_urn, users.GRRUser, mode="rw", token=token) # Note this accepts blank passwords as valid. if password is None: password = getpass.getpass( prompt="Please enter password for user '%s': " % username) fd.SetPassword(password) if labels: fd.AddLabels(set(labels), owner="GRR") fd.Close() EPrint("Added user %s." % username) events.Events.PublishEvent("Audit", rdf_events.AuditEvent(user=token.username, action="USER_ADD", urn=user_urn), token=token)
def Handle(self, args, token=None): if not args.username: raise ValueError("username can't be empty.") user_urn = aff4.ROOT_URN.Add("users").Add(args.username) events.Events.PublishEvent("Audit", rdf_events.AuditEvent(user=token.username, action="USER_ADD", urn=user_urn), token=token) if aff4.FACTORY.ExistsWithType(user_urn, aff4_type=users.GRRUser, token=token): raise access_control.UnauthorizedAccess( "Cannot add user %s: User already exists." % args.username) with aff4.FACTORY.Create(user_urn, aff4_type=users.GRRUser, mode="rw", token=token) as fd: if args.HasField("password"): fd.SetPassword(args.password) if args.user_type == args.UserType.USER_TYPE_ADMIN: fd.AddLabels(["admin"], owner="GRR") return api_user.ApiGrrUser().InitFromAff4Object(fd)
def _CreateAuditEvent(self, event_action): flow_name = self.hunt_obj.args.flow_runner_args.flow_name event = rdf_events.AuditEvent(user=self.hunt_obj.token.username, action=event_action, urn=self.hunt_obj.urn, flow_name=flow_name, description=self.runner_args.description) events.Events.PublishEvent("Audit", event, token=self.hunt_obj.token)
def testWriteAuditEventMultipleEvents(self): timestamp = rdfvalue.RDFDatetime.Now() self.db.WriteAuditEvent( rdf_events.AuditEvent(urn=rdfvalue.RDFURN("foo"))) self.db.WriteAuditEvent( rdf_events.AuditEvent(urn=rdfvalue.RDFURN("bar"))) self.db.WriteAuditEvent( rdf_events.AuditEvent(urn=rdfvalue.RDFURN("baz"))) log = self.db.ReadAllAuditEvents() self.assertEqual(len(log), 3) self.assertEqual(log[0].urn, rdfvalue.RDFURN("foo")) self.assertEqual(log[1].urn, rdfvalue.RDFURN("bar")) self.assertEqual(log[2].urn, rdfvalue.RDFURN("baz")) self.assertGreater(log[0].timestamp, timestamp) self.assertGreater(log[1].timestamp, timestamp) self.assertGreater(log[2].timestamp, timestamp)
def BuildApprovalUrn(self, approval_id): """Builds approval object urn.""" event = rdf_events.AuditEvent(user=self.token.username, action="CLIENT_APPROVAL_REQUEST", client=self.subject_urn, description=self.reason) events.Events.PublishEvent("Audit", event, token=self.token) return self.ApprovalUrnBuilder(self.subject_urn.Path(), self.token.username, approval_id)
def AddFakeAuditLog(description=None, client=None, user=None, token=None, **kwargs): events.Events.PublishEvent( "Audit", rdf_events.AuditEvent( description=description, client=client, user=user, **kwargs), token=token)
def _EntryToEvent(entry, handlers, transformers): """Converts an APIAuditEntry to a legacy AuditEvent.""" event = rdf_events.AuditEvent(timestamp=entry.timestamp, user=entry.username, action=handlers[entry.router_method_name]) for fn in transformers: fn(entry, event) return event
def BuildApprovalUrn(self): """Builds approval object URN.""" events.Events.PublishEvent("Audit", rdf_events.AuditEvent( user=self.token.username, action="CRON_APPROVAL_GRANT", urn=self.subject_urn, description=self.reason), token=self.token) return self.ApprovalUrnBuilder(self.subject_urn.Path(), self.delegate, self.reason)
def BuildApprovalUrn(self, approval_id): """Builds approval object URN.""" # In this case subject_urn is a cron job's URN. events.Events.PublishEvent("Audit", rdf_events.AuditEvent( user=self.token.username, action="CRON_APPROVAL_REQUEST", urn=self.subject_urn, description=self.reason), token=self.token) return self.ApprovalUrnBuilder(self.subject_urn.Path(), self.token.username, approval_id)
def _HandleAff4(self, args, token): user_urn = aff4.ROOT_URN.Add("users").Add(args.username) events.Events.PublishEvent("Audit", rdf_events.AuditEvent(user=token.username, action="USER_DELETE", urn=user_urn), token=token) if not aff4.FACTORY.ExistsWithType( user_urn, aff4_type=users.GRRUser, token=token): raise api_call_handler_base.ResourceNotFoundError( "GRR user with username '%s' could not be found." % args.username) aff4.FACTORY.Delete(user_urn, token=token)
def Handle(self, args, token=None): audit_description = ",".join([ token.username + u"." + utils.SmartUnicode(name) for name in args.labels ]) audit_events = [] try: if data_store.AFF4Enabled(): index = client_index.CreateClientIndex(token=token) client_objs = aff4.FACTORY.MultiOpen( [cid.ToClientURN() for cid in args.client_ids], aff4_type=aff4_grr.VFSGRRClient, mode="rw", token=token) for client_obj in client_objs: index.RemoveClientLabels(client_obj) self.RemoveClientLabels(client_obj, args.labels) index.AddClient(client_obj) client_obj.Close() if data_store.RelationalDBWriteEnabled(): for client_id in args.client_ids: cid = unicode(client_id) data_store.REL_DB.RemoveClientLabels( cid, token.username, args.labels) labels_to_remove = set(args.labels) existing_labels = data_store.REL_DB.ReadClientLabels(cid) for label in existing_labels: labels_to_remove.discard(label.name) if labels_to_remove: idx = client_index.ClientIndex() idx.RemoveClientLabels(cid, labels_to_remove) for client_id in args.client_ids: audit_events.append( rdf_events.AuditEvent( user=token.username, action="CLIENT_REMOVE_LABEL", flow_name="handler.ApiRemoveClientsLabelsHandler", client=client_id.ToClientURN(), description=audit_description)) finally: events.Events.PublishMultipleEvents( {audit.AUDIT_EVENT: audit_events}, token=token)
def Handle(self, args, token=None): audit_description = ",".join([ token.username + u"." + utils.SmartUnicode(name) for name in args.labels ]) audit_events = [] try: for api_client_id in args.client_ids: audit_events.append( rdf_events.AuditEvent( user=token.username, action="CLIENT_ADD_LABEL", flow_name="handler.ApiAddClientsLabelsHandler", client=api_client_id.ToClientURN(), description=audit_description)) if data_store.AFF4Enabled(): index = client_index.CreateClientIndex(token=token) client_objs = aff4.FACTORY.MultiOpen( [cid.ToClientURN() for cid in args.client_ids], aff4_type=aff4_grr.VFSGRRClient, mode="rw", token=token) for client_obj in client_objs: client_obj.AddLabels(args.labels) index.AddClient(client_obj) client_obj.Close() if data_store.RelationalDBWriteEnabled(): for api_client_id in args.client_ids: cid = unicode(api_client_id) try: data_store.REL_DB.AddClientLabels( cid, token.username, args.labels) idx = client_index.ClientIndex() idx.AddClientLabels(cid, args.labels) except db.UnknownClientError: # TODO(amoser): Remove after data migration. pass finally: events.Events.PublishMultipleEvents( {audit.AUDIT_EVENT: audit_events}, token=token)
def DeleteUser(username, token=None): """Deletes an existing user.""" if not username: raise UserError("User must have a non-empty name") token = data_store.GetDefaultToken(token) user_urn = "aff4:/users/%s" % username try: aff4.FACTORY.Open(user_urn, users.GRRUser, token=token) except aff4.InstantiationError: EPrint("User %s not found." % username) return aff4.FACTORY.Delete(user_urn, token=token) EPrint("User %s has been deleted." % username) events.Events.PublishEvent("Audit", rdf_events.AuditEvent(user=token.username, action="USER_DELETE", urn=user_urn), token=token)
def testWriteAuditEventFieldSerialization(self): client_urn = rdf_client.ClientURN("C.4815162342000000") event = rdf_events.AuditEvent( action=rdf_events.AuditEvent.Action.RUN_FLOW, user="******", flow_name="foo", flow_args="bar", client=client_urn, urn=client_urn.Add("flows").Add("108"), description="lorem ipsum") self.db.WriteAuditEvent(event) log = self.db.ReadAllAuditEvents() self.assertEqual(len(log), 1) self.assertEqual(log[0].action, rdf_events.AuditEvent.Action.RUN_FLOW) self.assertEqual(log[0].user, "quux") self.assertEqual(log[0].flow_name, "foo") self.assertEqual(log[0].flow_args, "bar") self.assertEqual(log[0].client, client_urn) self.assertEqual(log[0].urn, client_urn.Add("flows").Add("108")) self.assertEqual(log[0].description, "lorem ipsum")
def StartAFF4Flow(args=None, runner_args=None, parent_flow=None, sync=True, token=None, **kwargs): """The main factory function for creating and executing a new flow. Args: args: An arg protocol buffer which is an instance of the required flow's args_type class attribute. runner_args: an instance of FlowRunnerArgs() protocol buffer which is used to initialize the runner for this flow. parent_flow: A parent flow or None if this is a top level flow. sync: If True, the Start method of this flow will be called inline. Otherwise we schedule the starting of this flow on another worker. token: Security credentials token identifying the user. **kwargs: If args or runner_args are not specified, we construct these protobufs from these keywords. Returns: the session id of the flow. Raises: RuntimeError: Unknown or invalid parameters were provided. """ # Build the runner args from the keywords. if runner_args is None: runner_args = rdf_flow_runner.FlowRunnerArgs() FilterArgsFromSemanticProtobuf(runner_args, kwargs) # Is the required flow a known flow? try: flow_cls = registry.AFF4FlowRegistry.FlowClassByName( runner_args.flow_name) except ValueError: stats.STATS.IncrementCounter("grr_flow_invalid_flow_count") raise RuntimeError("Unable to locate flow %s" % runner_args.flow_name) # If no token is specified, raise. if not token: raise access_control.UnauthorizedAccess("A token must be specified.") # For the flow itself we use a supervisor token. token = token.SetUID() # Extend the expiry time of this token indefinitely. Python on Windows only # supports dates up to the year 3000. token.expiry = rdfvalue.RDFDatetime.FromHumanReadable("2997-01-01") if flow_cls.category and not runner_args.client_id: raise RuntimeError("Flow with category (user-visible flow) has to be " "started on a client, but runner_args.client_id " "is missing.") # We create an anonymous AFF4 object first, The runner will then generate # the appropriate URN. flow_obj = aff4.FACTORY.Create(None, flow_cls, token=token) # Now parse the flow args into the new object from the keywords. if args is None: args = flow_obj.args_type() FilterArgsFromSemanticProtobuf(args, kwargs) # Check that the flow args are valid. args.Validate() # Store the flow args. flow_obj.args = args flow_obj.runner_args = runner_args # At this point we should exhaust all the keyword args. If any are left # over, we do not know what to do with them so raise. if kwargs: raise type_info.UnknownArg("Unknown parameters to StartAFF4Flow: %s" % kwargs) # Create a flow runner to run this flow with. if parent_flow: parent_runner = parent_flow.runner else: parent_runner = None runner = flow_obj.CreateRunner(parent_runner=parent_runner, runner_args=runner_args) logging.info(u"Scheduling %s(%s) on %s", flow_obj.urn, runner_args.flow_name, runner_args.client_id) if sync: # Just run the first state inline. NOTE: Running synchronously means # that this runs on the thread that starts the flow. The advantage is # that that Start method can raise any errors immediately. flow_obj.Start() else: # Running Asynchronously: Schedule the start method on another worker. runner.CallState(next_state="Start") # The flow does not need to actually remain running. if not flow_obj.outstanding_requests: flow_obj.Terminate() flow_obj.Close() # Publish an audit event, only for top level flows. if parent_flow is None: events.Events.PublishEvent("Audit", rdf_events.AuditEvent( user=token.username, action="RUN_FLOW", flow_name=runner_args.flow_name, urn=flow_obj.urn, client=runner_args.client_id), token=token) return flow_obj.urn
def StartFlow(client_id=None, cpu_limit=None, creator=None, flow_args=None, flow_cls=None, network_bytes_limit=None, original_flow=None, output_plugins=None, start_at=None, parent_flow_obj=None, parent_hunt_id=None, **kwargs): """The main factory function for creating and executing a new flow. Args: client_id: ID of the client this flow should run on. cpu_limit: CPU limit in seconds for this flow. creator: Username that requested this flow. flow_args: An arg protocol buffer which is an instance of the required flow's args_type class attribute. flow_cls: Class of the flow that should be started. network_bytes_limit: Limit on the network traffic this flow can generated. original_flow: A FlowReference object in case this flow was copied from another flow. output_plugins: An OutputPluginDescriptor object indicating what output plugins should be used for this flow. start_at: If specified, flow will be started not immediately, but at a given time. parent_flow_obj: A parent flow object. None if this is a top level flow. parent_hunt_id: String identifying parent hunt. Can't be passed together with parent_flow_obj. **kwargs: If args or runner_args are not specified, we construct these protobufs from these keywords. Returns: the flow id of the new flow. Raises: ValueError: Unknown or invalid parameters were provided. """ if parent_flow_obj is not None and parent_hunt_id is not None: raise ValueError( "parent_flow_obj and parent_hunt_id are mutually exclusive.") # Is the required flow a known flow? try: registry.FlowRegistry.FlowClassByName(flow_cls.__name__) except ValueError: stats_collector_instance.Get().IncrementCounter( "grr_flow_invalid_flow_count") raise ValueError("Unable to locate flow %s" % flow_cls.__name__) if not client_id: raise ValueError("Client_id is needed to start a flow.") # Now parse the flow args into the new object from the keywords. if flow_args is None: flow_args = flow_cls.args_type() FilterArgsFromSemanticProtobuf(flow_args, kwargs) # At this point we should exhaust all the keyword args. If any are left # over, we do not know what to do with them so raise. if kwargs: raise type_info.UnknownArg("Unknown parameters to StartFlow: %s" % kwargs) # Check that the flow args are valid. flow_args.Validate() rdf_flow = rdf_flow_objects.Flow(client_id=client_id, flow_class_name=flow_cls.__name__, args=flow_args, create_time=rdfvalue.RDFDatetime.Now(), creator=creator, output_plugins=output_plugins, original_flow=original_flow, flow_state="RUNNING") if parent_hunt_id is not None and parent_flow_obj is None: rdf_flow.flow_id = parent_hunt_id if IsLegacyHunt(parent_hunt_id): rdf_flow.flow_id = rdf_flow.flow_id[2:] else: rdf_flow.flow_id = RandomFlowId() # For better performance, only do conflicting IDs check for top-level flows. if not parent_flow_obj: try: data_store.REL_DB.ReadFlowObject(client_id, rdf_flow.flow_id) raise CanNotStartFlowWithExistingIdError(client_id, rdf_flow.flow_id) except db.UnknownFlowError: pass if parent_flow_obj: # A flow is a nested flow. parent_rdf_flow = parent_flow_obj.rdf_flow rdf_flow.long_flow_id = "%s/%s" % (parent_rdf_flow.long_flow_id, rdf_flow.flow_id) rdf_flow.parent_flow_id = parent_rdf_flow.flow_id rdf_flow.parent_hunt_id = parent_rdf_flow.parent_hunt_id rdf_flow.parent_request_id = parent_flow_obj.GetCurrentOutboundId() if parent_rdf_flow.creator: rdf_flow.creator = parent_rdf_flow.creator elif parent_hunt_id: # A flow is a root-level hunt-induced flow. rdf_flow.long_flow_id = "%s/%s" % (client_id, rdf_flow.flow_id) rdf_flow.parent_hunt_id = parent_hunt_id else: # A flow is a root-level non-hunt flow. rdf_flow.long_flow_id = "%s/%s" % (client_id, rdf_flow.flow_id) if output_plugins: rdf_flow.output_plugins_states = GetOutputPluginStates( output_plugins, rdf_flow.long_flow_id, token=access_control.ACLToken(username=rdf_flow.creator)) if network_bytes_limit is not None: rdf_flow.network_bytes_limit = network_bytes_limit if cpu_limit is not None: rdf_flow.cpu_limit = cpu_limit logging.info(u"Scheduling %s(%s) on %s (%s)", rdf_flow.long_flow_id, rdf_flow.flow_class_name, client_id, start_at or "now") rdf_flow.current_state = "Start" flow_obj = flow_cls(rdf_flow) if start_at is None: # Store an initial version of the flow straight away. This is needed so the # database doesn't raise consistency errors due to missing parent keys when # writing logs / errors / results which might happen in Start(). data_store.REL_DB.WriteFlowObject(flow_obj.rdf_flow) # Just run the first state inline. NOTE: Running synchronously means # that this runs on the thread that starts the flow. The advantage is # that that Start method can raise any errors immediately. flow_obj.Start() # The flow does not need to actually remain running. if not flow_obj.outstanding_requests: flow_obj.RunStateMethod("End") # Additional check for the correct state in case the End method raised and # terminated the flow. if flow_obj.IsRunning(): flow_obj.MarkDone() else: flow_obj.CallState("Start", start_time=start_at) flow_obj.PersistState() data_store.REL_DB.WriteFlowObject(flow_obj.rdf_flow) if parent_flow_obj is not None: # We can optimize here and not write requests/responses to the database # since we have to do this for the parent flow at some point anyways. parent_flow_obj.MergeQueuedMessages(flow_obj) else: flow_obj.FlushQueuedMessages() # Publish an audit event, only for top level flows. # TODO(amoser): split urn field into dedicated strings. events.Events.PublishEvent( "Audit", rdf_events.AuditEvent(user=creator, action="RUN_FLOW", flow_name=rdf_flow.flow_class_name, urn=rdf_flow.long_flow_id, client=client_id)) return rdf_flow.flow_id
def UpdateUser(username, password, add_labels=None, delete_labels=None, token=None): """Implementation of the update_user command.""" if not username: raise UserError("User must have a non-empty name") token = data_store.GetDefaultToken(token) user_urn = "aff4:/users/%s" % username try: fd = aff4.FACTORY.Open(user_urn, users.GRRUser, mode="rw", token=token) except aff4.InstantiationError: raise UserError("User %s does not exist." % username) # Note this accepts blank passwords as valid. if password: if not isinstance(password, basestring): password = getpass.getpass( prompt="Please enter password for user '%s': " % username) fd.SetPassword(password) # Use sets to dedup input. current_labels = set() # Build a list of existing labels. for label in fd.GetLabels(): current_labels.add(label.name) # Build a list of labels to be added. expanded_add_labels = set() if add_labels: for label in add_labels: # Split up any space or comma separated labels in the list. labels = label.split(",") expanded_add_labels.update(labels) # Build a list of labels to be removed. expanded_delete_labels = set() if delete_labels: for label in delete_labels: # Split up any space or comma separated labels in the list. labels = label.split(",") expanded_delete_labels.update(labels) # Set subtraction to remove labels being added and deleted at the same time. clean_add_labels = expanded_add_labels - expanded_delete_labels clean_del_labels = expanded_delete_labels - expanded_add_labels # Create final list using difference to only add new labels. final_add_labels = clean_add_labels - current_labels # Create final list using intersection to only remove existing labels. final_del_labels = clean_del_labels & current_labels if final_add_labels: fd.AddLabels(final_add_labels, owner="GRR") if final_del_labels: fd.RemoveLabels(final_del_labels, owner="GRR") fd.Close() EPrint("Updated user %s" % username) ShowUser(username, token=token) events.Events.PublishEvent("Audit", rdf_events.AuditEvent(user=token.username, action="USER_UPDATE", urn=user_urn), token=token)
def StartFlow(client_id=None, cpu_limit=7200, creator=None, flow_args=None, flow_cls=None, network_bytes_limit=None, original_flow=None, output_plugins=None, parent_flow_obj=None, **kwargs): """The main factory function for creating and executing a new flow. Args: client_id: ID of the client this flow should run on. cpu_limit: CPU limit in seconds for this flow. creator: Username that requested this flow. flow_args: An arg protocol buffer which is an instance of the required flow's args_type class attribute. flow_cls: Class of the flow that should be started. network_bytes_limit: Limit on the network traffic this flow can generated. original_flow: A FlowReference object in case this flow was copied from another flow. output_plugins: An OutputPluginDescriptor object indicating what output plugins should be used for this flow. parent_flow_obj: A parent flow object. None if this is a top level flow. **kwargs: If args or runner_args are not specified, we construct these protobufs from these keywords. Returns: the flow id of the new flow. Raises: ValueError: Unknown or invalid parameters were provided. """ # Is the required flow a known flow? try: registry.FlowRegistry.FlowClassByName(flow_cls.__name__) except ValueError: stats.STATS.IncrementCounter("grr_flow_invalid_flow_count") raise ValueError("Unable to locate flow %s" % flow_cls.__name__) if not client_id: raise ValueError("Client_id is needed to start a flow.") # Now parse the flow args into the new object from the keywords. if flow_args is None: flow_args = flow_cls.args_type() FilterArgsFromSemanticProtobuf(flow_args, kwargs) # At this point we should exhaust all the keyword args. If any are left # over, we do not know what to do with them so raise. if kwargs: raise type_info.UnknownArg("Unknown parameters to StartFlow: %s" % kwargs) # Check that the flow args are valid. flow_args.Validate() rdf_flow = rdf_flow_objects.Flow(client_id=client_id, flow_class_name=flow_cls.__name__, args=flow_args, create_time=rdfvalue.RDFDatetime.Now(), creator=creator, output_plugins=output_plugins, original_flow=original_flow, flow_state="RUNNING") rdf_flow.flow_id = "%08X" % utils.PRNG.GetUInt32() if parent_flow_obj: parent_rdf_flow = parent_flow_obj.rdf_flow rdf_flow.long_flow_id = "%s/%s" % (parent_rdf_flow.long_flow_id, rdf_flow.flow_id) rdf_flow.parent_flow_id = parent_rdf_flow.flow_id rdf_flow.parent_request_id = parent_flow_obj.GetCurrentOutboundId() if parent_rdf_flow.creator: rdf_flow.creator = parent_rdf_flow.creator else: rdf_flow.long_flow_id = "%s/%s" % (client_id, rdf_flow.flow_id) if output_plugins: rdf_flow.output_plugins_states = GetOutputPluginStates( output_plugins, rdf_flow.long_flow_id, token=access_control.ACLToken(username=rdf_flow.creator)) if network_bytes_limit is not None: rdf_flow.network_bytes_limit = network_bytes_limit if cpu_limit is not None: rdf_flow.cpu_limit = cpu_limit logging.info(u"Scheduling %s(%s) on %s", rdf_flow.long_flow_id, rdf_flow.flow_class_name, client_id) flow_obj = flow_cls(rdf_flow) # Just run the first state inline. NOTE: Running synchronously means # that this runs on the thread that starts the flow. The advantage is # that that Start method can raise any errors immediately. flow_obj.Start() flow_obj.PersistState() # The flow does not need to actually remain running. if not flow_obj.outstanding_requests: flow_obj.RunStateMethod("End") flow_obj.MarkDone() data_store.REL_DB.WriteFlowObject(flow_obj.rdf_flow) if parent_flow_obj is not None: # We can optimize here and not write requests/responses to the database # since we have to do this for the parent flow at some point anyways. parent_flow_obj.MergeQueuedMessages(flow_obj) else: flow_obj.FlushQueuedMessages() # Publish an audit event, only for top level flows. # TODO(amoser): split urn field into dedicated strings. events.Events.PublishEvent( "Audit", rdf_events.AuditEvent(user=creator, action="RUN_FLOW", flow_name=rdf_flow.flow_class_name, urn=rdf_flow.long_flow_id, client=client_id)) return rdf_flow.flow_id
def Handle(self, args, token=None): hunt_urn = args.hunt_id.ToURN() try: hunt = aff4.FACTORY.Open(hunt_urn, aff4_type=implementation.GRRHunt, mode="rw", token=token) except aff4.InstantiationError: raise HuntNotFoundError("Hunt with id %s could not be found" % args.hunt_id) current_state = hunt.Get(hunt.Schema.STATE) hunt_changes = [] runner = hunt.GetRunner() if args.HasField("client_limit"): hunt_changes.append( "Client Limit: Old=%s, New=%s" % (runner.runner_args.client_limit, args.client_limit)) runner.runner_args.client_limit = args.client_limit if args.HasField("client_rate"): hunt_changes.append( "Client Rate: Old=%s, New=%s" % (runner.runner_args.client_rate, args.client_limit)) runner.runner_args.client_rate = args.client_rate if args.HasField("expires"): hunt_changes.append("Expires: Old=%s, New=%s" % (runner.context.expires, args.expires)) runner.context.expires = args.expires if hunt_changes and current_state != "PAUSED": raise HuntNotModifiableError( "Hunt's client limit/client rate/expiry time attributes " "can only be changed if hunt's current state is " "PAUSED") if args.HasField("state"): hunt_changes.append("State: Old=%s, New=%s" % (current_state, args.state)) if args.state == ApiHunt.State.STARTED: if current_state != "PAUSED": raise HuntNotStartableError( "Hunt can only be started from PAUSED state.") hunt.Run() elif args.state == ApiHunt.State.STOPPED: if current_state not in ["PAUSED", "STARTED"]: raise HuntNotStoppableError( "Hunt can only be stopped from STARTED or " "PAUSED states.") hunt.Stop() else: raise InvalidHuntStateError( "Hunt's state can only be updated to STARTED or STOPPED") # Publish an audit event. # TODO(user): this should be properly tested. event = rdf_events.AuditEvent(user=token.username, action="HUNT_MODIFIED", urn=hunt_urn, description=", ".join(hunt_changes)) events.Events.PublishEvent("Audit", event, token=token) hunt.Close() hunt = aff4.FACTORY.Open(hunt_urn, aff4_type=implementation.GRRHunt, mode="rw", token=token) return ApiHunt().InitFromAff4Object(hunt, with_full_summary=True)