def SendMail(self, responses): """Sends a mail when the client has responded.""" if responses.success: client = aff4.FACTORY.Open(self.client_id, token=self.token) hostname = client.Get(client.Schema.HOSTNAME) url = urllib.urlencode( (("c", self.client_id), ("main", "HostInformation"))) subject = "GRR Client on %s became available." % hostname email_alerts.SendEmail( self.args.email, "grr-noreply", subject, self.template % dict(client_id=self.client_id, admin_ui=config_lib.CONFIG["AdminUI.url"], hostname=hostname, urn=url, creator=self.token.username, signature=config_lib.CONFIG["Email.signature"]), is_html=True) else: flow.FlowError("Error while pinging client.")
def Start(self): """Create the Approval object and notify the Approval Granter.""" approval_urn = self.BuildApprovalUrn() subject_title = self.BuildSubjectTitle() # Create a new Approval object. approval_request = aff4.FACTORY.Create(approval_urn, aff4_type=self.approval_type, token=self.token) approval_request.Set(approval_request.Schema.REASON(self.args.reason)) approval_request.AddAttribute( approval_request.Schema.APPROVER(self.token.username)) # This is a break glass approval. break_glass = approval_request.Schema.BREAK_GLASS().Now() # By default a break_glass approval only lasts 24 hours. break_glass += 60 * 60 * 24 * 1e6 approval_request.Set(break_glass) approval_request.Close(sync=True) # Notify the user. fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add( self.token.username), "GRRUser", mode="rw", token=self.token) fd.Notify( "ViewObject", self.args.subject_urn, "An Emergency Approval has been granted to access " "%s." % subject_title, self.session_id) fd.Close() template = u""" <html><body><h1>Emergency Access Granted.</h1> The user %(username)s has requested emergency access to %(subject_title)s. for the purpose of: "%(reason)s". This access has been logged and granted for 24 hours. <p>Thanks,</p> <p>%(signature)s</p> </body></html>""" body = template % dict(client_id=self.client_id, username=self.token.username, subject_title=subject_title, reason=self.args.reason, signature=config_lib.CONFIG["Email.signature"]), email_alerts.SendEmail( config_lib.CONFIG["Monitoring.emergency_access_email"], self.token.username, u"Emergency approval granted for %s." % subject_title, utils.SmartStr(body), is_html=True, cc_addresses=config_lib.CONFIG["Email.approval_cc_address"])
def Start(self): """Create the Approval object and notify the Approval Granter.""" approval_urn = self.BuildApprovalUrn() subject_title = self.BuildSubjectTitle() approval_request = aff4.FACTORY.Create(approval_urn, self.approval_type, mode="w", token=self.token) approval_request.Set(approval_request.Schema.REASON(self.args.reason)) # We add ourselves as an approver as well (The requirement is that we have 2 # approvers, so the requester is automatically an approver). approval_request.AddAttribute( approval_request.Schema.APPROVER(self.token.username)) approval_request.Close() # Notify to the users. for user in self.args.approver.split(","): user = user.strip() fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add(user), "GRRUser", mode="rw", token=self.token) fd.Notify("GrantAccess", approval_urn, "Please grant access to %s" % subject_title, self.session_id) fd.Close() template = """ <html><body><h1>Approval to access %(subject_title)s requested.</h1> The user "%(username)s" has requested access to %(subject_title)s for the purpose of "%(reason)s". Please click <a href='%(admin_ui)s#%(approval_urn)s'> here </a> to review this request and then grant access. <p>Thanks,</p> <p>The GRR team. </body></html>""" url = urllib.urlencode((("acl", utils.SmartStr(approval_urn)), ("main", "GrantAccess"))) email_alerts.SendEmail( user, self.token.username, "Please grant %s approval to %s." % (self.token.username, subject_title), template % dict(username=self.token.username, reason=utils.SmartStr(self.args.reason), admin_ui=config_lib.CONFIG["AdminUI.url"], subject_title=subject_title, approval_urn=url), is_html=True)
def Start(self): """Create the Approval object and notify the Approval Granter.""" approval_urn = self.BuildApprovalUrn() subject_title = self.BuildSubjectTitle() access_urn = self.BuildAccessUrl() # This object must already exist. try: approval_request = aff4.FACTORY.Open(approval_urn, mode="rw", aff4_type=self.approval_type, token=self.token) except IOError: raise access_control.UnauthorizedAccess( "Approval object does not exist.", requested_access="rw") # We are now an approver for this request. approval_request.AddAttribute( approval_request.Schema.APPROVER(self.token.username)) approval_request.Close(sync=True) # Notify to the user. fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add( self.args.delegate), "GRRUser", mode="rw", token=self.token) fd.Notify( "ViewObject", self.args.subject_urn, "%s has granted you access to %s." % (self.token.username, subject_title), self.session_id) fd.Close() template = """ <html><body><h1>Access to %(subject_title)s granted.</h1> The user %(username)s has granted access to %(subject_title)s for the purpose of "%(reason)s". Please click <a href='%(admin_ui)s#%(subject_urn)s'>here</a> to access it. <p>Thanks,</p> <p>The GRR team. </body></html>""" email_alerts.SendEmail(self.args.delegate, self.token.username, "Access to %s granted." % subject_title, template % dict(subject_title=subject_title, username=self.token.username, reason=utils.SmartStr(self.args.reason), admin_ui=config_lib.CONFIG["AdminUI.url"], subject_urn=access_urn), is_html=True)
def MailReport(self, recipient, subject=None): """Mail the HTML report to recipient.""" dt = rdfvalue.RDFDatetime().Now().Format("%Y-%m-%dT%H-%MZ") subject = subject or "%s - %s" % (self.REPORT_NAME, dt) csv_data = self.AsCsv() filename = "%s-%s.csv" % (self.REPORT_NAME, dt) email_alerts.SendEmail(recipient, self.EMAIL_FROM, subject, "Please find the CSV report file attached", attachments={filename: csv_data.getvalue()}, is_html=False) logging.info("Report %s mailed to %s", self.REPORT_NAME, recipient)
def MailHTMLReport(self, recipient, subject=None): """Mail the HTML report to recipient.""" dt = rdfvalue.RDFDatetime().Now().Format("%Y-%m-%dT%H-%MZ") subject = subject or "%s - %s" % (self.REPORT_NAME, dt) report_text = self.AsHtmlTable() email_alerts.SendEmail( recipient, self.EMAIL_FROM, subject, self.EMAIL_TEMPLATE % dict(report_text=report_text, report_name=self.REPORT_NAME), is_html=True) logging.info("Report %s mailed to %s", self.REPORT_NAME, recipient)
def ProcessMessage(self, message=None, event=None): """Processes this event.""" _ = event client_id = message.source message = rdfvalue.DataBlob(message.args).string logging.info(self.logline, client_id, message) # Write crash data to AFF4. client = aff4.FACTORY.Open(client_id, token=self.token) client_info = client.Get(client.Schema.CLIENT_INFO) crash_details = rdfvalue.ClientCrash( client_id=client_id, client_info=client_info, crash_message=message, timestamp=long(time.time() * 1e6), crash_type=self.well_known_session_id) self.WriteAllCrashDetails(client_id, crash_details) # Also send email. if config_lib.CONFIG["Monitoring.alert_email"]: client = aff4.FACTORY.Open(client_id, token=self.token) hostname = client.Get(client.Schema.HOSTNAME) url = urllib.urlencode( (("c", client_id), ("main", "HostInformation"))) email_alerts.SendEmail( config_lib.CONFIG["Monitoring.alert_email"], "GRR server", self.subject % client_id, self.mail_template % dict(client_id=client_id, admin_ui=config_lib.CONFIG["AdminUI.url"], hostname=hostname, signature=config_lib.CONFIG["Email.signature"], urn=url, message=message), is_html=True)
def ProcessMessage(self, message=None, unused_event=None): """Process an event message.""" # Only accept authenticated messages auth_state = rdfvalue.GrrMessage.AuthorizationState.AUTHENTICATED if message.auth_state != auth_state: return change_email = config_lib.CONFIG.Get("AFF4.change_email") if not change_email: return urn = aff4.RDFURN(message.args) subject = "AFF4 change: %s" % utils.SmartStr(urn) email_alerts.SendEmail(change_email, "GRR server", subject, self.mail_template % dict( path=utils.SmartStr(urn)), is_html=True)
def ProcessResponse(self, response): """Sends an email for each response.""" if self.state.emails_sent >= self.state.args.email_limit: return client_id = response.source client = aff4.FACTORY.Open(client_id, token=self.token) hostname = client.Get(client.Schema.HOSTNAME) or "unknown hostname" subject = ("GRR Hunt results collection %s got a new result." % self.state.collection_urn) url = urllib.urlencode((("c", client_id), ("main", "HostInformation"))) response_htm = rendering.FindRendererForObject(response).RawHTML() self.state.emails_sent += 1 if self.state.emails_sent == self.state.args.email_limit: additional_message = self.too_many_mails_msg % self.state.args.email_limit else: additional_message = "" email_alerts.SendEmail( self.state.args.email, "grr-noreply", subject, self.template % dict( client_id=client_id, admin_ui=config_lib.CONFIG["AdminUI.url"], hostname=hostname, urn=url, creator=self.token.username, collection_urn=self.state.collection_urn, response=response_htm, additional_message=additional_message, ), is_html=True)
def ProcessResponse(self, response): """Sends an email for each response.""" emails_left = self.IncrementCounter() if emails_left < 0: return client_id = response.source client = aff4.FACTORY.Open(client_id, token=self.token) hostname = client.Get(client.Schema.HOSTNAME) or "unknown hostname" client_fragment_id = urllib.urlencode( (("c", client_id), ("main", "HostInformation"))) if emails_left == 0: additional_message = (self.too_many_mails_msg % self.state.args.emails_limit) else: additional_message = "" subject = ("GRR got a new result in %s." % self.state.source_urn) template_args = dict( client_id=client_id, client_fragment_id=client_fragment_id, admin_ui_url=config_lib.CONFIG["AdminUI.url"], source_urn=self.state.source_urn, additional_message=additional_message, signature=config_lib.CONFIG["Email.signature"], # Values that have to be escaped. hostname=cgi.escape(utils.SmartStr(hostname)), creator=cgi.escape(utils.SmartStr(self.token.username))) email_alerts.SendEmail(self.state.args.email_address, "grr-noreply", subject, self.template % template_args, is_html=True)
def End(self): self.Notify( "DownloadFile", self.state.output_archive_urn, "Hunt results ready for download (archived %d out of %d " "results, archive size is %s)" % (self.state.archived_files, self.state.total_files, self.state.output_size)) # TODO(user): it would be better to provide a direct download link in the # email here, but it requires more work. The notifications bar creates and # submits a form in javascript to achieve the same thing. template = """ <html><body> <p> The archive archive contains %(archived)s of %(total)s files for hunt %(hunt_id)s. Check the <a href='%(admin_ui)s/'>GRR notification bar</a> for download links. </p> <p>Thanks,</p> <p>%(signature)s</p> </body></html>""" subject = "Hunt results for %s ready for download." % ( self.args.hunt_urn.Basename()) creator = self.state.context.creator email_alerts.SendEmail( "%s@%s" % (creator, config_lib.CONFIG.Get("Logging.domain")), "grr-noreply@%s" % config_lib.CONFIG.Get("Logging.domain"), subject, template % dict(hunt_id=self.args.hunt_urn.Basename(), archived=self.state.archived_files, total=self.state.total_files, admin_ui=config_lib.CONFIG["AdminUI.url"], signature=config_lib.CONFIG["Email.signature"]), is_html=True)
def testSendEmail(self): testdomain = "test.com" config_lib.CONFIG.Set("Email.default_domain", testdomain) with mock.patch.object(smtplib, "SMTP") as mock_smtp: smtp_conn = mock_smtp.return_value # Single fully qualified address to_address = "*****@*****.**" from_address = "*****@*****.**" subject = "test" message = "" email_alerts.SendEmail(to_address, from_address, subject, message) c_from, c_to, _ = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual([to_address], c_to) # Multiple unqualified to addresses, one cc to_address = "testto,abc,def" to_address_expected = [ x + testdomain for x in ["testto@", "abc@", "def@", "testcc@"] ] cc_address = "testcc" email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s" % testdomain in message) # Multiple unqualified to addresses, two cc, message_id set to_address_expected = [ x + testdomain for x in ["testto@", "abc@", "def@", "testcc@", "testcc2@"] ] cc_address = "testcc,testcc2" email_msg_id = "123123" email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address, message_id=email_msg_id) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s,testcc2@%s" % (testdomain, testdomain) in message) self.assertTrue("Message-ID: %s" % email_msg_id) # Multiple unqualified to addresses, two cc, no default domain to_address_expected = ["testto", "abc", "def", "testcc", "testcc2"] config_lib.CONFIG.Set("Email.default_domain", None) email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s,testcc2@%s" % (testdomain, testdomain) in message)
def testSendEmail(self): testdomain = "test.com" config_lib.CONFIG.Set("Logging.domain", testdomain) smtp_conn = self.mock_smtp.return_value # Single fully qualified address to_address = "*****@*****.**" from_address = "*****@*****.**" subject = "test" message = "" email_alerts.SendEmail(to_address, from_address, subject, message) c_from, c_to, msg = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual([to_address], c_to) self.assertFalse("CC:" in msg) # Single fully qualified address as rdf_standard.DomainEmailAddress to_address = rdf_standard.DomainEmailAddress("testto@%s" % testdomain) from_address = "*****@*****.**" subject = "test" message = "" email_alerts.SendEmail(to_address, from_address, subject, message) c_from, c_to, msg = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual([to_address], c_to) self.assertFalse("CC:" in msg) # Multiple unqualified to addresses, one cc to_address = "testto,abc,def" to_address_expected = [ x + testdomain for x in ["testto@", "abc@", "def@"] ] cc_address = "testcc" email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s" % testdomain in message) # Multiple unqualified to addresses as DomainEmailAddress, one cc to_address = [ rdf_standard.DomainEmailAddress("testto@%s" % testdomain), rdf_standard.DomainEmailAddress("abc@%s" % testdomain), rdf_standard.DomainEmailAddress("def@%s" % testdomain) ] to_address_expected = [ x + testdomain for x in ["testto@", "abc@", "def@"] ] cc_address = "testcc" email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s" % testdomain in message) # Multiple unqualified to addresses, two cc, message_id set to_address = "testto,abc,def" to_address_expected = [ x + testdomain for x in ["testto@", "abc@", "def@"] ] cc_address = "testcc,testcc2" email_msg_id = "123123" email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address, message_id=email_msg_id) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s,testcc2@%s" % (testdomain, testdomain) in message) self.assertTrue("Message-ID: %s" % email_msg_id) # Multiple address types, two cc, no default domain config_lib.CONFIG.Set("Logging.domain", None) to_address = [ "testto@localhost", "hij", rdf_standard.DomainEmailAddress("klm@localhost") ] to_address_expected = [ "testto@localhost", "hij@localhost", "klm@localhost" ] email_alerts.SendEmail(to_address, from_address, subject, message, cc_addresses=cc_address) c_from, c_to, message = smtp_conn.sendmail.call_args[0] self.assertEqual(from_address, c_from) self.assertEqual(to_address_expected, c_to) self.assertTrue("CC: testcc@%s,testcc2@%s" % (testdomain, testdomain) in message)
def Start(self): """Create the Approval object and notify the Approval Granter.""" approval_urn = self.BuildApprovalUrn() subject_title = self.BuildSubjectTitle() access_urn = self.BuildAccessUrl() # This object must already exist. try: approval_request = aff4.FACTORY.Open(approval_urn, mode="rw", aff4_type=self.approval_type, token=self.token) except IOError: raise access_control.UnauthorizedAccess( "Approval object does not exist.", requested_access="rw") # We are now an approver for this request. approval_request.AddAttribute( approval_request.Schema.APPROVER(self.token.username)) email_msg_id = utils.SmartStr( approval_request.Get(approval_request.Schema.EMAIL_MSG_ID)) email_cc = utils.SmartStr( approval_request.Get(approval_request.Schema.EMAIL_CC)) approval_request.Close(sync=True) # Notify to the user. fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add( self.args.delegate), "GRRUser", mode="rw", token=self.token) fd.Notify( "ViewObject", self.args.subject_urn, "%s has granted you access to %s." % (self.token.username, subject_title), self.session_id) fd.Close() template = u""" <html><body><h1>Access to %(subject_title)s granted.</h1> The user %(username)s has granted access to %(subject_title)s for the purpose of "%(reason)s". Please click <a href='%(admin_ui)s#%(subject_urn)s'>here</a> to access it. <p>Thanks,</p> <p>%(signature)s</p> </body></html>""" body = template % dict(subject_title=subject_title, username=self.token.username, reason=self.args.reason, admin_ui=config_lib.CONFIG["AdminUI.url"], subject_urn=access_urn, signature=config_lib.CONFIG["Email.signature"]) # Email subject should match approval request, and we add message id # references so they are grouped together in a thread by gmail. subject = u"Approval for %s to access %s." % (utils.SmartStr( self.args.delegate), subject_title) headers = {"In-Reply-To": email_msg_id, "References": email_msg_id} email_alerts.SendEmail(utils.SmartStr(self.args.delegate), utils.SmartStr(self.token.username), subject, utils.SmartStr(body), is_html=True, cc_addresses=email_cc, headers=headers)
def Start(self): """Create the Approval object and notify the Approval Granter.""" approval_urn = self.BuildApprovalUrn() subject_title = self.BuildSubjectTitle() email_msg_id = email.utils.make_msgid() approval_request = aff4.FACTORY.Create(approval_urn, self.approval_type, mode="w", token=self.token) approval_request.Set(approval_request.Schema.REASON(self.args.reason)) approval_request.Set( approval_request.Schema.EMAIL_MSG_ID(email_msg_id)) cc_addresses = (self.args.email_cc_address, config_lib.CONFIG.Get("Email.approval_cc_address")) email_cc = ",".join(filter(None, cc_addresses)) # When we reply with the approval we want to cc all the people to whom the # original approval was sent, to avoid people approving stuff that was # already approved. if email_cc: reply_cc = ",".join((self.args.approver, email_cc)) else: reply_cc = self.args.approver approval_request.Set(approval_request.Schema.EMAIL_CC(reply_cc)) # We add ourselves as an approver as well (The requirement is that we have 2 # approvers, so the requester is automatically an approver). approval_request.AddAttribute( approval_request.Schema.APPROVER(self.token.username)) approval_request.Close() # Notify to the users. for user in self.args.approver.split(","): user = user.strip() fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add(user), "GRRUser", mode="rw", token=self.token) fd.Notify("GrantAccess", approval_urn, "Please grant access to %s" % subject_title, self.session_id) fd.Close() template = u""" <html><body><h1>Approval to access %(subject_title)s requested.</h1> The user "%(username)s" has requested access to %(subject_title)s for the purpose of "%(reason)s". Please click <a href='%(admin_ui)s#%(approval_urn)s'> here </a> to review this request and then grant access. <p>Thanks,</p> <p>%(signature)s</p> <p>%(image)s</p> </body></html>""" # If you feel like it, add a funny cat picture here :) image = "" url = urllib.urlencode( (("acl", utils.SmartStr(approval_urn)), ("main", "GrantAccess"))) body = template % dict(username=self.token.username, reason=self.args.reason, admin_ui=config_lib.CONFIG["AdminUI.url"], subject_title=subject_title, approval_urn=url, image=image, signature=config_lib.CONFIG["Email.signature"]) email_alerts.SendEmail(self.args.approver, utils.SmartStr(self.token.username), u"Approval for %s to access %s." % (self.token.username, subject_title), utils.SmartStr(body), is_html=True, cc_addresses=email_cc, message_id=email_msg_id)
def ProcessMessage(self, message=None, event=None): """Processes this event.""" _ = event client_id = message.source nanny_msg = "" flow_obj = aff4.FACTORY.Open(message.session_id, token=self.token) # Log. logging.info("Client crash reported, client %s.", client_id) # Export. stats.STATS.IncrementCounter("grr_client_crashes") # Write crash data to AFF4. client = aff4.FACTORY.Open(client_id, token=self.token) client_info = client.Get(client.Schema.CLIENT_INFO) status = rdfvalue.GrrStatus(message.args) crash_details = rdfvalue.ClientCrash( client_id=client_id, session_id=message.session_id, client_info=client_info, crash_message=status.error_message, timestamp=rdfvalue.RDFDatetime().Now(), crash_type=self.well_known_session_id) self.WriteAllCrashDetails(client_id, crash_details, flow_session_id=message.session_id) # Also send email. if config_lib.CONFIG["Monitoring.alert_email"]: if status.nanny_status: nanny_msg = "Nanny status: %s" % status.nanny_status client = aff4.FACTORY.Open(client_id, token=self.token) hostname = client.Get(client.Schema.HOSTNAME) url = urllib.urlencode( (("c", client_id), ("main", "HostInformation"))) renderer = rendering.FindRendererForObject(flow_obj.state) email_alerts.SendEmail( config_lib.CONFIG["Monitoring.alert_email"], "GRR server", "Client %s reported a crash." % client_id, self.mail_template % dict(client_id=client_id, admin_ui=config_lib.CONFIG["AdminUI.url"], hostname=hostname, state=renderer.RawHTML(), urn=url, nanny_msg=nanny_msg, signature=config_lib.CONFIG["Email.signature"]), is_html=True) if nanny_msg: msg = "Client crashed, " + nanny_msg else: msg = "Client crashed." # Now terminate the flow. flow.GRRFlow.TerminateFlow(message.session_id, reason=msg, token=self.token, force=True)