1# -*- coding: utf-8 -*- 2# Copyright (C) 2018-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 19import sys 20from argparse import ArgumentParser, Namespace, RawTextHelpFormatter 21from gvm.protocols.gmp import Gmp 22 23from gvmtools.helper import create_xml_tree, error_and_exit, yes_or_no 24 25HELP_TEXT = """ 26 This script pulls tasks data from an xml document and feeds it to \ 27 a desired GSM 28 Usage examples: 29 $ gvm-script --gmp-username name --gmp-password pass ssh --hostname 30 ... send-task.gmp.py +h 31 ... send-task.gmp.py ++x xml_file 32 """ 33 34 35def numerical_option(statement, list_range): 36 choice = int(input(statement)) 37 38 if choice in range(1, list_range + 1): 39 return choice 40 else: 41 return numerical_option( 42 f"Please enter valid number from 1 to {list_range}...", 43 list_range, 44 ) 45 46 47def interactive_options(gmp, task, keywords): 48 options_dict = {} 49 options_dict['config'] = gmp.get_scan_configs() 50 options_dict['scanner'] = gmp.get_scanners() 51 options_dict['target'] = gmp.get_targets() 52 53 for option_key, option_value in options_dict.items(): 54 object_dict, object_list = {}, [] 55 object_id = task.find(option_key).get('id') 56 object_xml = option_value 57 58 for i in object_xml.findall(option_key): 59 object_dict[i.find('name').text] = i.xpath('@id')[0] 60 object_list.append(i.find('name').text) 61 62 if object_id in object_dict.values(): 63 keywords[f'{option_key}_id'] = object_id 64 elif object_id not in object_dict.values() and len(object_dict) != 0: 65 response = yes_or_no( 66 f"\nRequired Field: failed to detect {option_key}_id: " 67 f"{task.xpath(f'{option_key}/@id')[0]}... " 68 "\nWould you like to select from available options, or exit " 69 "the script?" 70 ) 71 72 if response is True: 73 counter = 1 74 print(f"{option_key.capitalize()} options:") 75 for j in object_list: 76 print(f" {counter} - {j}") 77 counter += 1 78 answer = numerical_option( 79 "\nPlease enter the number of your choice.", 80 len(object_list), 81 ) 82 keywords[f'{option_key}_id'] = object_dict[ 83 object_list[answer - 1] 84 ] 85 else: 86 print("\nTerminating...") 87 sys.exit() 88 else: 89 error_and_exit( 90 f"Failed to detect {option_key}_id\nThis field is required " 91 "therefore the script is unable to continue.\n" 92 ) 93 94 95def parse_send_xml_tree(gmp, xml_tree): 96 task_xml_elements = xml_tree.xpath('task') 97 print(task_xml_elements) 98 if not task_xml_elements: 99 error_and_exit("No tasks found.") 100 tasks = [] 101 for task in task_xml_elements: 102 keywords = {'name': task.find('name').text} 103 104 if task.find('comment').text is not None: 105 keywords['comment'] = task.find('comment').text 106 107 interactive_options(gmp, task, keywords) 108 109 if task.find('schedule_periods') is not None: 110 keywords['schedule_periods'] = int( 111 task.find('schedule_periods').text 112 ) 113 114 if task.find('observers').text: 115 keywords['observers'] = task.find('observers').text 116 117 if task.xpath('schedule/@id')[0]: 118 keywords['schedule_id'] = task.xpath('schedule/@id')[0] 119 120 if task.xpath('preferences/preference'): 121 preferences, scanner_name_list, value_list = {}, [], [] 122 123 for preference in task.xpath('preferences/preference'): 124 scanner_name_list.append(preference.find('scanner_name').text) 125 if preference.find('value').text is not None: 126 value_list.append(preference.find('value').text) 127 else: 128 value_list.append('') 129 preferences['scanner_name'] = scanner_name_list 130 preferences['value'] = value_list 131 keywords['preferences'] = preferences 132 133 new_task = gmp.create_task(**keywords) 134 135 tasks.append(new_task.xpath('//@id')[0]) 136 return tasks 137 138 139def main(gmp: Gmp, args: Namespace) -> None: 140 # pylint: disable=undefined-variable, unused-argument 141 142 parser = ArgumentParser( 143 prefix_chars="+", 144 add_help=False, 145 formatter_class=RawTextHelpFormatter, 146 description=HELP_TEXT, 147 ) 148 149 parser.add_argument( 150 "+h", 151 "++help", 152 action="help", 153 help="Show this help message and exit.", 154 ) 155 156 parser.add_argument( 157 "+x", 158 "++xml-file", 159 dest='xml', 160 type=str, 161 required=True, 162 help='xml file containing tasks', 163 ) 164 165 script_args, _ = parser.parse_known_args() 166 167 # check_args(args) 168 169 print('\nSending task(s)...') 170 171 xml_tree = create_xml_tree(script_args.xml) 172 tasks = parse_send_xml_tree(gmp, xml_tree) 173 for task in tasks: 174 print(task) 175 print('\nTask(s) sent!\n') 176 177 178if __name__ == '__gmp__': 179 main(gmp, args) # pylint: disable=undefined-variable 180