1# -*- coding: utf-8 -*- 2# Copyright (C) 2017-2021 Greenbone Networks GmbH 3# 4# SPDX-License-Identifier: GPL-3.0-or-later 5# 6# This program is free software: you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation, either version 3 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19# GMP script for gvm-pyshell to send emails with delta reports. 20 21import base64 22import datetime 23import sched 24import smtplib 25import sys 26import time 27 28from email.mime.base import MIMEBase 29from email.mime.multipart import MIMEMultipart 30from email.utils import formatdate 31 32from argparse import Namespace 33from gvm.protocols.gmp import Gmp 34 35 36def check_args(args: Namespace) -> None: 37 len_args = len(args.script) - 1 38 if len_args != 0: 39 message = """ 40 This script, once started, will continuously send delta 41 reports via email for selected tasks. 42 43 Example for starting up the routine: 44 $ gvm-script --gmp-username name --gmp-password pass ssh --hostname <gsm> scripts/send-delta-emails.gmp.py 45 46 The routine follows this procedure: 47 48 Every <interval> minutes do: 49 Get all tasks where the tag <task_tag> is attached. 50 For each of these tasks get the finished reports: 51 If less than 2 reports, continue with next task 52 If latest report has tag "delta_alert_sent", continue with next task 53 Create a CSV report from the delta of latest vs. previous report 54 where filtered for only the new results. 55 Send the CSV as an attachment to the configured email address. 56 """ 57 print(message) 58 sys.exit() 59 60 61def execute_send_delta_emails(sc: sched.scheduler, **kwargs: dict) -> None: 62 gmp = kwargs.get('gmp') 63 task_tag = kwargs.get('task_tag') 64 interval = kwargs.get('interval') 65 email_subject = kwargs.get('email_subject') 66 to_addresses = kwargs.get('to_addresses') 67 from_address = kwargs.get('from_address') 68 mta_address = kwargs.get('mta_address') 69 mta_user = kwargs.get('mta_user') 70 mta_port = kwargs.get('mta_port') 71 mta_password = kwargs.get('mta_password') 72 report_tag_name = kwargs.get('report_tag_name') 73 74 print('Retrieving task list ...') 75 76 task_filter = f'tag={task_tag}' 77 tasks = gmp.get_tasks(filter_string=task_filter).xpath('task') 78 print(f'Found {str(len(tasks))} task(s) with tag "{task_tag}".') 79 80 for task in tasks: 81 task_id = task.xpath('@id')[0] 82 task_name = task.xpath('name/text()')[0] 83 print(f'Processing task "{task_name}" ({task_id})...') 84 85 reports = gmp.get_reports( 86 filter_string='task_id={task_id} and status=Done ' 87 'sort-reverse=date' 88 ).xpath('report') 89 print(f' Found {str(len(reports))} report(s).') 90 if len(reports) < 2: 91 print(' Delta-reporting requires at least 2 finished reports.') 92 continue 93 94 if reports[0].xpath( 95 'report/user_tags/tag/' 'name[text()="delta_alert_sent"]' 96 ): 97 print(' Delta report for latest finished report already sent') 98 continue 99 100 print( 101 ' Latest finished report not send yet. Preparing delta ' 102 'report...' 103 ) 104 105 delta_report = gmp.get_report( 106 report_id=reports[0].xpath('@id')[0], 107 delta_report_id=reports[1].xpath('@id')[0], 108 filter_string='delta_states=n', 109 format_id='c1645568-627a-11e3-a660-406186ea4fc5', 110 ) 111 112 csv_in_b64 = delta_report.xpath('report/text()')[0] 113 csv = base64.b64decode(csv_in_b64) 114 115 print(" Composing Email...") 116 alert_email = MIMEMultipart() 117 alert_email['Subject'] = email_subject 118 alert_email['To'] = ', '.join(to_addresses) 119 alert_email['From'] = from_address 120 alert_email['Date'] = formatdate(localtime=True) 121 122 report_attachment = MIMEBase('application', "octet-stream") 123 report_attachment.add_header( 124 'Content-Disposition', 'attachment', filename='delta.csv' 125 ) 126 report_attachment.set_payload(csv) 127 alert_email.attach(report_attachment) 128 129 print(" Sending Email...") 130 try: 131 with smtplib.SMTP(mta_address, mta_port) as smtp: 132 smtp.ehlo() 133 smtp.starttls() 134 smtp.ehlo() 135 smtp.login(mta_user, mta_password) # if required 136 smtp.sendmail( 137 from_address, to_addresses, alert_email.as_string() 138 ) 139 smtp.close() 140 print(" Email has been sent!") 141 142 gmp.create_tag( 143 name=report_tag_name, 144 resource_id=reports[0].xpath('@id')[0], 145 resource_type='report', 146 value=datetime.datetime.now(), 147 ) 148 except Exception: # pylint: disable=broad-except 149 print(" Unable to send the email. Error: ", sys.exc_info()[0]) 150 # raise # in case an error should stop the script 151 continue # ignore the problem for the time being 152 153 print(f"\nCheck will be repeated in {str(interval)} minutes...\n") 154 sc.enter( 155 interval * 60, 156 1, 157 execute_send_delta_emails, 158 argument=(sc,), 159 kwargs=kwargs, 160 ) 161 162 163def main(gmp: Gmp, args: Namespace) -> None: 164 # pylint: disable=undefined-variable 165 166 check_args(args) 167 168 interval = 1 # in minutes 169 task_tag = 'send_delta_alert' 170 report_tag_name = 'delta_alert_sent' 171 email_subject = 'Delta Report' 172 from_address = 'admin@example.com' 173 to_addresses = ['user1@example.com', 'user2@example.com'] 174 mta_address = 'mail.example.com' 175 mta_port = 25 176 mta_user = 'admin@example.com' 177 mta_password = 'mysecret' 178 179 print('send_delta_alerts starting up with following settings:') 180 print(f'User: {args.username}') 181 print(f'Interval: {str(interval)} minutes') 182 print(f'Task tag: {task_tag}') 183 print(f'Email subject: {email_subject}') 184 print(f'From Address: {from_address}') 185 print(f'To Addresses: {to_addresses}') 186 print(f'MTA Address: {mta_address}') 187 print(f'MTA Port: {str(mta_port)}') 188 print(f'MTA User: {mta_user}') 189 print('MTA Password: <will not be printed here>') 190 print() 191 192 print(f'Entering loop with interval {str(interval)} minutes ...') 193 194 schedule = sched.scheduler(time.time, time.sleep) 195 196 # Enter the scheduled execution with the given interval 197 schedule.enter( 198 0, 199 1, 200 execute_send_delta_emails, 201 argument=(schedule,), 202 kwargs={ 203 'gmp': gmp, 204 'task_tag': task_tag, 205 'interval': interval, 206 'email_subject': email_subject, 207 'to_addresses': to_addresses, 208 'from_address': from_address, 209 'mta_address': mta_address, 210 'mta_password': mta_password, 211 'mta_port': mta_port, 212 'mta_user': mta_user, 213 'report_tag_name': report_tag_name, 214 }, 215 ) 216 schedule.run() 217 218 219if __name__ == '__gmp__': 220 main(gmp, args) 221