| Total Complexity | 150 | 
| Total Lines | 990 | 
| Duplicated Lines | 78.99 % | 
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like ospd_openvas.wrapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # -*- coding: utf-8 -*-  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 2 | # Description:  | 
            ||
| 3 | # Setup for the OSP OpenVAS Server  | 
            ||
| 4 | #  | 
            ||
| 5 | # Authors:  | 
            ||
| 6 | # Juan José Nicola <[email protected]>  | 
            ||
| 7 | #  | 
            ||
| 8 | # Copyright:  | 
            ||
| 9 | # Copyright (C) 2018 Greenbone Networks GmbH  | 
            ||
| 10 | #  | 
            ||
| 11 | # This program is free software; you can redistribute it and/or  | 
            ||
| 12 | # modify it under the terms of the GNU General Public License  | 
            ||
| 13 | # as published by the Free Software Foundation; either version 2  | 
            ||
| 14 | # of the License, or (at your option) any later version.  | 
            ||
| 15 | #  | 
            ||
| 16 | # This program is distributed in the hope that it will be useful,  | 
            ||
| 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
            ||
| 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  | 
            ||
| 19 | # GNU General Public License for more details.  | 
            ||
| 20 | #  | 
            ||
| 21 | # You should have received a copy of the GNU General Public License  | 
            ||
| 22 | # along with this program; if not, write to the Free Software  | 
            ||
| 23 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA  | 
            ||
| 24 | |||
| 25 | import subprocess  | 
            ||
| 26 | import time  | 
            ||
| 27 | import signal  | 
            ||
| 28 | import uuid  | 
            ||
| 29 | from lxml.etree import tostring, SubElement, Element  | 
            ||
| 30 | import psutil  | 
            ||
| 31 | |||
| 32 | from ospd.ospd import OSPDaemon, logger  | 
            ||
| 33 | from ospd.misc import main as daemon_main  | 
            ||
| 34 | from ospd.misc import target_str_to_list  | 
            ||
| 35 | from ospd_openvas import __version__  | 
            ||
| 36 | |||
| 37 | import ospd_openvas.nvticache as nvti  | 
            ||
| 38 | import ospd_openvas.openvas_db as openvas_db  | 
            ||
| 39 | |||
| 40 | OSPD_DESC = """  | 
            ||
| 41 | This scanner runs 'OpenVAS Scanner' to scan the target hosts.  | 
            ||
| 42 | |||
| 43 | OpenVAS (Open Vulnerability Assessment System) is a powerful scanner  | 
            ||
| 44 | for vulnerabilities in IT infrastrucutres. The capabilities include  | 
            ||
| 45 | unauthzenticated scanning as well as authneticated scanning for  | 
            ||
| 46 | various types of systems and services.  | 
            ||
| 47 | |||
| 48 | For more details about OpenVAS see the OpenVAS homepage:  | 
            ||
| 49 | http://www.openvas.org/  | 
            ||
| 50 | |||
| 51 | The current version of ospd-openvas is a simple frame, which sends  | 
            ||
| 52 | the server parameters to the Greenbone Vulnerability Manager (GVM) and checks  | 
            ||
| 53 | the existence of OpenVAS Scanner binary. But it can not run scans yet.  | 
            ||
| 54 | """  | 
            ||
| 55 | |||
| 56 | MAIN_KBINDEX = None  | 
            ||
| 57 | |||
| 58 | OSPD_PARAMS = { | 
            ||
| 59 |     'auto_enable_dependencies': { | 
            ||
| 60 | 'type': 'boolean',  | 
            ||
| 61 | 'name': 'auto_enable_dependencies',  | 
            ||
| 62 | 'default': 1,  | 
            ||
| 63 | 'mandatory': 1,  | 
            ||
| 64 | 'description': 'Automatically enable the plugins that are depended on',  | 
            ||
| 65 | },  | 
            ||
| 66 |     'cgi_path': { | 
            ||
| 67 | 'type': 'string',  | 
            ||
| 68 | 'name': 'cgi_path',  | 
            ||
| 69 | 'default': '/cgi-bin:/scripts',  | 
            ||
| 70 | 'mandatory': 1,  | 
            ||
| 71 | 'description': 'Look for default CGIs in /cgi-bin and /scripts',  | 
            ||
| 72 | },  | 
            ||
| 73 |     'checks_read_timeout': { | 
            ||
| 74 | 'type': 'integer',  | 
            ||
| 75 | 'name': 'checks_read_timeout',  | 
            ||
| 76 | 'default': 5,  | 
            ||
| 77 | 'mandatory': 1,  | 
            ||
| 78 |         'description': ('Number  of seconds that the security checks will ' + | 
            ||
| 79 | 'wait for when doing a recv()'),  | 
            ||
| 80 | },  | 
            ||
| 81 |     'drop_privileges': { | 
            ||
| 82 | 'type': 'boolean',  | 
            ||
| 83 | 'name': 'drop_privileges',  | 
            ||
| 84 | 'default': 0,  | 
            ||
| 85 | 'mandatory': 1,  | 
            ||
| 86 | 'description': '',  | 
            ||
| 87 | },  | 
            ||
| 88 |     'network_scan': { | 
            ||
| 89 | 'type': 'boolean',  | 
            ||
| 90 | 'name': 'network_scan',  | 
            ||
| 91 | 'default': 0,  | 
            ||
| 92 | 'mandatory': 1,  | 
            ||
| 93 | 'description': '',  | 
            ||
| 94 | },  | 
            ||
| 95 |     'non_simult_ports': { | 
            ||
| 96 | 'type': 'string',  | 
            ||
| 97 | 'name': 'non_simult_ports',  | 
            ||
| 98 | 'default': '139, 445, 3389, Services/irc',  | 
            ||
| 99 | 'mandatory': 1,  | 
            ||
| 100 |         'description': ('Prevent to make two connections on the same given ' + | 
            ||
| 101 | 'ports at the same time.'),  | 
            ||
| 102 | },  | 
            ||
| 103 |     'open_sock_max_attempts': { | 
            ||
| 104 | 'type': 'integer',  | 
            ||
| 105 | 'name': 'open_sock_max_attempts',  | 
            ||
| 106 | 'default': 5,  | 
            ||
| 107 | 'mandatory': 0,  | 
            ||
| 108 |         'description': ('Number of unsuccessful retries to open the socket ' + | 
            ||
| 109 | 'before to set the port as closed.'),  | 
            ||
| 110 | },  | 
            ||
| 111 |     'timeout_retry': { | 
            ||
| 112 | 'type': 'integer',  | 
            ||
| 113 | 'name': 'timeout_retry',  | 
            ||
| 114 | 'default': 5,  | 
            ||
| 115 | 'mandatory': 0,  | 
            ||
| 116 |         'description': ('Number of retries when a socket connection attempt ' + | 
            ||
| 117 | 'timesout.'),  | 
            ||
| 118 | },  | 
            ||
| 119 |     'optimize_test': { | 
            ||
| 120 | 'type': 'integer',  | 
            ||
| 121 | 'name': 'optimize_test',  | 
            ||
| 122 | 'default': 5,  | 
            ||
| 123 | 'mandatory': 0,  | 
            ||
| 124 |         'description': ('By default, openvassd does not trust the remote ' + | 
            ||
| 125 | 'host banners.'),  | 
            ||
| 126 | },  | 
            ||
| 127 |     'plugins_timeout': { | 
            ||
| 128 | 'type': 'integer',  | 
            ||
| 129 | 'name': 'plugins_timeout',  | 
            ||
| 130 | 'default': 5,  | 
            ||
| 131 | 'mandatory': 0,  | 
            ||
| 132 | 'description': 'This is the maximum lifetime, in seconds of a plugin.',  | 
            ||
| 133 | },  | 
            ||
| 134 |     'report_host_details': { | 
            ||
| 135 | 'type': 'boolean',  | 
            ||
| 136 | 'name': 'report_host_details',  | 
            ||
| 137 | 'default': 1,  | 
            ||
| 138 | 'mandatory': 1,  | 
            ||
| 139 | 'description': '',  | 
            ||
| 140 | },  | 
            ||
| 141 |     'safe_checks': { | 
            ||
| 142 | 'type': 'boolean',  | 
            ||
| 143 | 'name': 'safe_checks',  | 
            ||
| 144 | 'default': 1,  | 
            ||
| 145 | 'mandatory': 1,  | 
            ||
| 146 |         'description': ('Disable the plugins with potential to crash ' + | 
            ||
| 147 | 'the remote services'),  | 
            ||
| 148 | },  | 
            ||
| 149 |     'scanner_plugins_timeout': { | 
            ||
| 150 | 'type': 'integer',  | 
            ||
| 151 | 'name': 'scanner_plugins_timeout',  | 
            ||
| 152 | 'default': 36000,  | 
            ||
| 153 | 'mandatory': 1,  | 
            ||
| 154 | 'description': 'Like plugins_timeout, but for ACT_SCANNER plugins.',  | 
            ||
| 155 | },  | 
            ||
| 156 |     'time_between_request': { | 
            ||
| 157 | 'type': 'integer',  | 
            ||
| 158 | 'name': 'time_between_request',  | 
            ||
| 159 | 'default': 0,  | 
            ||
| 160 | 'mandatory': 0,  | 
            ||
| 161 |         'description': ('Allow to set a wait time between two actions ' + | 
            ||
| 162 | '(open, send, close).'),  | 
            ||
| 163 | },  | 
            ||
| 164 |     'unscanned_closed': { | 
            ||
| 165 | 'type': 'boolean',  | 
            ||
| 166 | 'name': 'unscanned_closed',  | 
            ||
| 167 | 'default': 1,  | 
            ||
| 168 | 'mandatory': 1,  | 
            ||
| 169 | 'description': '',  | 
            ||
| 170 | },  | 
            ||
| 171 |     'unscanned_closed_udp': { | 
            ||
| 172 | 'type': 'boolean',  | 
            ||
| 173 | 'name': 'unscanned_closed_udp',  | 
            ||
| 174 | 'default': 1,  | 
            ||
| 175 | 'mandatory': 1,  | 
            ||
| 176 | 'description': '',  | 
            ||
| 177 | },  | 
            ||
| 178 |     'use_mac_addr': { | 
            ||
| 179 | 'type': 'boolean',  | 
            ||
| 180 | 'name': 'use_mac_addr',  | 
            ||
| 181 | 'default': 0,  | 
            ||
| 182 | 'mandatory': 0,  | 
            ||
| 183 | 'description': 'To test the local network. ' +  | 
            ||
| 184 | 'Hosts will be referred to by their MAC address.',  | 
            ||
| 185 | },  | 
            ||
| 186 |     'vhosts': { | 
            ||
| 187 | 'type': 'string',  | 
            ||
| 188 | 'name': 'vhosts',  | 
            ||
| 189 | 'default': '',  | 
            ||
| 190 | 'mandatory': 0,  | 
            ||
| 191 | 'description': '',  | 
            ||
| 192 | },  | 
            ||
| 193 |     'vhosts_ip': { | 
            ||
| 194 | 'type': 'string',  | 
            ||
| 195 | 'name': 'vhosts_ip',  | 
            ||
| 196 | 'default': '',  | 
            ||
| 197 | 'mandatory': 0,  | 
            ||
| 198 | 'description': '',  | 
            ||
| 199 | },  | 
            ||
| 200 | }  | 
            ||
| 201 | |||
| 202 | |||
| 203 | View Code Duplication | class OSPDopenvas(OSPDaemon):  | 
            |
| 204 | |||
| 205 | """ Class for ospd-openvas daemon. """  | 
            ||
| 206 | |||
| 207 | def __init__(self, certfile, keyfile, cafile):  | 
            ||
| 208 | """ Initializes the ospd-openvas daemon's internal data. """  | 
            ||
| 209 | |||
| 210 | super(OSPDopenvas, self).__init__(certfile=certfile, keyfile=keyfile,  | 
            ||
| 211 | cafile=cafile)  | 
            ||
| 212 | self.server_version = __version__  | 
            ||
| 213 | self.scanner_info['name'] = 'openvassd'  | 
            ||
| 214 | self.scanner_info['version'] = '' # achieved during self.check()  | 
            ||
| 215 | self.scanner_info['description'] = OSPD_DESC  | 
            ||
| 216 | for name, param in OSPD_PARAMS.items():  | 
            ||
| 217 | self.add_scanner_param(name, param)  | 
            ||
| 218 | |||
| 219 | if openvas_db.db_init() is False:  | 
            ||
| 220 |             logger.error('OpenVAS Redis Error: Not possible ' | 
            ||
| 221 | 'to find db_connection.')  | 
            ||
| 222 | raise Exception  | 
            ||
| 223 | |||
| 224 | self.pending_feed = None  | 
            ||
| 225 | ctx = openvas_db.db_find(nvti.NVTICACHE_STR)  | 
            ||
| 226 | if not ctx:  | 
            ||
| 227 | self.redis_nvticache_init()  | 
            ||
| 228 | ctx = openvas_db.db_find(nvti.NVTICACHE_STR)  | 
            ||
| 229 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 230 | self.load_vts()  | 
            ||
| 231 | |||
| 232 | def parse_param(self):  | 
            ||
| 233 | """ Set OSPD_PARAMS with the params taken from the openvas_scanner. """  | 
            ||
| 234 | global OSPD_PARAMS  | 
            ||
| 235 |         bool_dict = {'no': 0, 'yes': 1} | 
            ||
| 236 | |||
| 237 | result = subprocess.check_output(['openvassd', '-s'],  | 
            ||
| 238 | stderr=subprocess.STDOUT)  | 
            ||
| 239 |         result = result.decode('ascii') | 
            ||
| 240 | param_list = dict()  | 
            ||
| 241 |         for conf in result.split('\n'): | 
            ||
| 242 |             elem = conf.split('=') | 
            ||
| 243 | if len(elem) == 2:  | 
            ||
| 244 | value = str.strip(elem[1])  | 
            ||
| 245 | if str.strip(elem[1]) in bool_dict:  | 
            ||
| 246 | value = bool_dict[value]  | 
            ||
| 247 | param_list[str.strip(elem[0])] = value  | 
            ||
| 248 | for elem in OSPD_PARAMS:  | 
            ||
| 249 | if elem in param_list:  | 
            ||
| 250 | OSPD_PARAMS[elem]['default'] = param_list[elem]  | 
            ||
| 251 | |||
| 252 | def redis_nvticache_init(self):  | 
            ||
| 253 | """ Loads NVT's metadata into Redis DB. """  | 
            ||
| 254 | try:  | 
            ||
| 255 |             logger.debug('Loading NVTs in Redis DB') | 
            ||
| 256 | subprocess.check_call(['openvassd', '-C'])  | 
            ||
| 257 | except subprocess.CalledProcessError as err:  | 
            ||
| 258 |             logger.error('OpenVAS Scanner failed to load NVTs.') | 
            ||
| 259 | raise err  | 
            ||
| 260 | |||
| 261 | def check_feed(self):  | 
            ||
| 262 | """ Check if there is a feed update. Wait until all the running  | 
            ||
| 263 | scans finished. Set a flag to anounce there is a pending feed update,  | 
            ||
| 264 | which avoid to start a new scan.  | 
            ||
| 265 | """  | 
            ||
| 266 | _running_scan = False  | 
            ||
| 267 | for scan_id in self.scan_processes:  | 
            ||
| 268 | if self.scan_processes[scan_id].is_alive():  | 
            ||
| 269 | _running_scan = True  | 
            ||
| 270 | |||
| 271 | if self.pending_feed:  | 
            ||
| 272 | _pending_feed = True  | 
            ||
| 273 | else:  | 
            ||
| 274 | _pending_feed = self.get_vts_version() != nvti.get_feed_version()  | 
            ||
| 275 | |||
| 276 | if _running_scan and _pending_feed:  | 
            ||
| 277 | if not self.pending_feed:  | 
            ||
| 278 | self.pending_feed = True  | 
            ||
| 279 | logger.debug(  | 
            ||
| 280 | 'There is a running scan. Therefore the feed '  | 
            ||
| 281 | 'update will be performed later.')  | 
            ||
| 282 | elif not _running_scan and _pending_feed:  | 
            ||
| 283 | self.vts = dict()  | 
            ||
| 284 | self.load_vts()  | 
            ||
| 285 | |||
| 286 | def scheduler(self):  | 
            ||
| 287 | """This method is called periodically to run tasks."""  | 
            ||
| 288 | self.check_feed()  | 
            ||
| 289 | |||
| 290 | def load_vts(self):  | 
            ||
| 291 | """ Load the NVT's metadata into the vts  | 
            ||
| 292 | global dictionary. """  | 
            ||
| 293 |         logger.debug('Loading vts in memory.') | 
            ||
| 294 | oids = dict(nvti.get_oids())  | 
            ||
| 295 | for filename, vt_id in oids.items():  | 
            ||
| 296 | _vt_params = nvti.get_nvt_params(vt_id)  | 
            ||
| 297 | _vt_refs = nvti.get_nvt_refs(vt_id)  | 
            ||
| 298 | _custom = nvti.get_nvt_metadata(vt_id)  | 
            ||
| 299 |             _name = _custom.pop('name') | 
            ||
| 300 |             _vt_creation_time = _custom.pop('creation_date') | 
            ||
| 301 |             _vt_modification_time = _custom.pop('last_modification') | 
            ||
| 302 | |||
| 303 | _summary=None  | 
            ||
| 304 | _impact=None  | 
            ||
| 305 | _affected=None  | 
            ||
| 306 | _insight=None  | 
            ||
| 307 | _solution=None  | 
            ||
| 308 | _solution_t=None  | 
            ||
| 309 | _vuldetect=None  | 
            ||
| 310 | _qod_t=None  | 
            ||
| 311 | _qod_v=None  | 
            ||
| 312 | |||
| 313 | if 'summary' in _custom:  | 
            ||
| 314 |                 _summary  = _custom.pop('summary') | 
            ||
| 315 | if 'impact' in _custom:  | 
            ||
| 316 |                 _impact   = _custom.pop('impact') | 
            ||
| 317 | if 'affected' in _custom:  | 
            ||
| 318 |                 _affected = _custom.pop('affected') | 
            ||
| 319 | if 'insight' in _custom :  | 
            ||
| 320 |                 _insight  = _custom.pop('insight') | 
            ||
| 321 | if 'solution' in _custom:  | 
            ||
| 322 |                 _solution  = _custom.pop('solution') | 
            ||
| 323 | if 'solution_type' in _custom:  | 
            ||
| 324 |                     _solution_t  = _custom.pop('solution_type') | 
            ||
| 325 | |||
| 326 | if 'vuldetect' in _custom:  | 
            ||
| 327 |                 _vuldetect  = _custom.pop('vuldetect') | 
            ||
| 328 | if 'qod_type' in _custom:  | 
            ||
| 329 |                 _qod_t  = _custom.pop('qod_type') | 
            ||
| 330 | elif 'qod' in _custom:  | 
            ||
| 331 |                 _qod_v  = _custom.pop('qod') | 
            ||
| 332 | |||
| 333 | _severity = dict()  | 
            ||
| 334 | if 'severity_base_vector' in _custom:  | 
            ||
| 335 |                 _severity_vector = _custom.pop('severity_base_vector') | 
            ||
| 336 | else:  | 
            ||
| 337 |                 _severity_vector = _custom.pop('cvss_base_vector') | 
            ||
| 338 | _severity['severity_base_vector'] = _severity_vector  | 
            ||
| 339 | if 'severity_type' in _custom:  | 
            ||
| 340 |                 _severity_type = custom.pop('severity_type') | 
            ||
| 341 | else:  | 
            ||
| 342 | _severity_type = 'cvss_base_v2'  | 
            ||
| 343 | _severity['severity_type'] = _severity_type  | 
            ||
| 344 | if 'severity_origin' in _custom:  | 
            ||
| 345 |                 _severity['severity_origin'] = _custom.pop('severity_origin') | 
            ||
| 346 | |||
| 347 | _vt_dependencies = list()  | 
            ||
| 348 | if 'dependencies' in _custom:  | 
            ||
| 349 |                 _deps = _custom.pop('dependencies') | 
            ||
| 350 |                 _deps_list = _deps.split(', ') | 
            ||
| 351 | for dep in _deps_list:  | 
            ||
| 352 |                     _vt_dependencies.append(oids.get('filename:' + dep)) | 
            ||
| 353 | |||
| 354 | ret = self.add_vt(  | 
            ||
| 355 | vt_id,  | 
            ||
| 356 | name=_name,  | 
            ||
| 357 | vt_params=_vt_params,  | 
            ||
| 358 | vt_refs=_vt_refs,  | 
            ||
| 359 | custom=_custom,  | 
            ||
| 360 | vt_creation_time=_vt_creation_time,  | 
            ||
| 361 | vt_modification_time=_vt_modification_time,  | 
            ||
| 362 | vt_dependencies=_vt_dependencies,  | 
            ||
| 363 | summary=_summary,  | 
            ||
| 364 | impact=_impact,  | 
            ||
| 365 | affected=_affected,  | 
            ||
| 366 | insight=_insight,  | 
            ||
| 367 | solution=_solution,  | 
            ||
| 368 | solution_t=_solution_t,  | 
            ||
| 369 | detection=_vuldetect,  | 
            ||
| 370 | qod_t=_qod_t,  | 
            ||
| 371 | qod_v=_qod_v,  | 
            ||
| 372 | severities=_severity  | 
            ||
| 373 | )  | 
            ||
| 374 | if ret == -1:  | 
            ||
| 375 |                 logger.info("Dupplicated VT with OID: {0}".format(vt_id)) | 
            ||
| 376 | if ret == -2:  | 
            ||
| 377 |                 logger.info("{0}: Invalid OID.".format(vt_id)) | 
            ||
| 378 | |||
| 379 | _feed_version = nvti.get_feed_version()  | 
            ||
| 380 | self.set_vts_version(vts_version=_feed_version)  | 
            ||
| 381 | self.pending_feed = False  | 
            ||
| 382 |         logger.debug('Finish loading up vts.') | 
            ||
| 383 | |||
| 384 | @staticmethod  | 
            ||
| 385 | def get_custom_vt_as_xml_str(vt_id, custom):  | 
            ||
| 386 | """ Return an xml element with custom metadata formatted as string."""  | 
            ||
| 387 | |||
| 388 |         nvt = Element('vt') | 
            ||
| 389 | for key, val in custom.items():  | 
            ||
| 390 | xml_key = SubElement(nvt, key)  | 
            ||
| 391 | xml_key.text = val  | 
            ||
| 392 | |||
| 393 | itera = nvt.iter()  | 
            ||
| 394 | metadata = ''  | 
            ||
| 395 | for elem in itera:  | 
            ||
| 396 | if elem.tag != 'vt':  | 
            ||
| 397 |                 metadata += (tostring(elem).decode('utf-8')) | 
            ||
| 398 | return metadata  | 
            ||
| 399 | |||
| 400 | @staticmethod  | 
            ||
| 401 | def get_severities_vt_as_xml_str(vt_id, severities):  | 
            ||
| 402 | """ Return an xml element with severities as string."""  | 
            ||
| 403 | |||
| 404 |         _severity = Element('severity') | 
            ||
| 405 | if 'severity_base_vector' in severities:  | 
            ||
| 406 |             _severity.text = severities.pop('severity_base_vector') | 
            ||
| 407 | if 'severity_origin' in severities:  | 
            ||
| 408 |             _severity.set('origin', severities.pop('severity_origin')) | 
            ||
| 409 | if 'severity_type' in severities:  | 
            ||
| 410 |             _severity.set('type', severities.pop('severity_type')) | 
            ||
| 411 | |||
| 412 |         return tostring(_severity).decode('utf-8') | 
            ||
| 413 | |||
| 414 | @staticmethod  | 
            ||
| 415 | def get_params_vt_as_xml_str(vt_id, vt_params):  | 
            ||
| 416 | """ Return an xml element with params formatted as string."""  | 
            ||
| 417 |         vt_params_xml = Element('vt_params') | 
            ||
| 418 | for prefs in vt_params.items():  | 
            ||
| 419 |             vt_param = Element('vt_param') | 
            ||
| 420 |             vt_param.set('type', prefs[1]['type']) | 
            ||
| 421 |             vt_param.set('id', prefs[0]) | 
            ||
| 422 | xml_name = SubElement(vt_param, 'name')  | 
            ||
| 423 | xml_name.text = prefs[1]['name']  | 
            ||
| 424 | if prefs[1]['default']:  | 
            ||
| 425 | xml_def = SubElement(vt_param, 'default')  | 
            ||
| 426 | xml_def.text = prefs[1]['default']  | 
            ||
| 427 | vt_params_xml.append(vt_param)  | 
            ||
| 428 | |||
| 429 |         params_list = vt_params_xml.findall("vt_param") | 
            ||
| 430 | params = ''  | 
            ||
| 431 | for param in params_list:  | 
            ||
| 432 |             params += (tostring(param).decode('utf-8')) | 
            ||
| 433 | return params  | 
            ||
| 434 | |||
| 435 | @staticmethod  | 
            ||
| 436 | def get_refs_vt_as_xml_str(vt_id, vt_refs):  | 
            ||
| 437 | """ Return an xml element with references formatted as string."""  | 
            ||
| 438 |         vt_refs_xml = Element('vt_refs') | 
            ||
| 439 | for ref_type, ref_values in vt_refs.items():  | 
            ||
| 440 | for value in ref_values:  | 
            ||
| 441 |                 vt_ref = Element('ref') | 
            ||
| 442 | if ref_type == "xref" and value:  | 
            ||
| 443 |                     for xref in value.split(', '): | 
            ||
| 444 | try:  | 
            ||
| 445 |                             _type, _id = xref.split(':', 1) | 
            ||
| 446 | except ValueError:  | 
            ||
| 447 | logger.error(  | 
            ||
| 448 | 'Not possible to parse xref %s for vt %s' % (  | 
            ||
| 449 | xref, vt_id))  | 
            ||
| 450 | continue  | 
            ||
| 451 |                         vt_ref.set('type', _type.lower()) | 
            ||
| 452 |                         vt_ref.set('id', _id) | 
            ||
| 453 | elif value:  | 
            ||
| 454 |                     vt_ref.set('type', ref_type.lower()) | 
            ||
| 455 |                     vt_ref.set('id', value) | 
            ||
| 456 | else:  | 
            ||
| 457 | continue  | 
            ||
| 458 | vt_refs_xml.append(vt_ref)  | 
            ||
| 459 | |||
| 460 |         refs_list = vt_refs_xml.findall("ref") | 
            ||
| 461 | refs = ''  | 
            ||
| 462 | for ref in refs_list:  | 
            ||
| 463 |             refs += (tostring(ref).decode('utf-8')) | 
            ||
| 464 | return refs  | 
            ||
| 465 | |||
| 466 | @staticmethod  | 
            ||
| 467 | def get_dependencies_vt_as_xml_str(vt_id, dep_list):  | 
            ||
| 468 | """ Return an xml element with dependencies as string."""  | 
            ||
| 469 |         vt_deps_xml = Element('vt_deps') | 
            ||
| 470 | for dep in dep_list:  | 
            ||
| 471 |             _vt_dep = Element('dependency') | 
            ||
| 472 | try:  | 
            ||
| 473 |                 _vt_dep.set('vt_id', dep) | 
            ||
| 474 | except TypeError:  | 
            ||
| 475 |                 logger.error('Not possible to add dependency %s for vt %s' % ( | 
            ||
| 476 | dep, vt_id))  | 
            ||
| 477 | continue  | 
            ||
| 478 | vt_deps_xml.append(_vt_dep)  | 
            ||
| 479 | |||
| 480 |         _deps_list = vt_deps_xml.findall("dependency") | 
            ||
| 481 | deps = ''  | 
            ||
| 482 | for _dep in _deps_list:  | 
            ||
| 483 |             deps += (tostring(_dep).decode('utf-8')) | 
            ||
| 484 | return deps  | 
            ||
| 485 | |||
| 486 | @staticmethod  | 
            ||
| 487 | def get_creation_time_vt_as_xml_str(vt_id, creation_time):  | 
            ||
| 488 | """ Return creation time as string."""  | 
            ||
| 489 | return creation_time  | 
            ||
| 490 | |||
| 491 | @staticmethod  | 
            ||
| 492 | def get_modification_time_vt_as_xml_str(vt_id, modification_time):  | 
            ||
| 493 | """ Return modification time as string."""  | 
            ||
| 494 | return modification_time  | 
            ||
| 495 | |||
| 496 | @staticmethod  | 
            ||
| 497 | def get_summary_vt_as_xml_str(vt_id, summary):  | 
            ||
| 498 | """ Return summary as string."""  | 
            ||
| 499 |         _summary = Element('summary') | 
            ||
| 500 | _summary.text = summary  | 
            ||
| 501 |         return tostring(_summary).decode('utf-8') | 
            ||
| 502 | |||
| 503 | @staticmethod  | 
            ||
| 504 | def get_impact_vt_as_xml_str(vt_id, impact):  | 
            ||
| 505 | """ Return impact as string."""  | 
            ||
| 506 |         _impact = Element('impact') | 
            ||
| 507 | _impact.text = impact  | 
            ||
| 508 |         return tostring(_impact).decode('utf-8') | 
            ||
| 509 | |||
| 510 | @staticmethod  | 
            ||
| 511 | def get_affected_vt_as_xml_str(vt_id, affected):  | 
            ||
| 512 | """ Return affected as string."""  | 
            ||
| 513 |         _affected = Element('affected') | 
            ||
| 514 | _affected.text = affected  | 
            ||
| 515 |         return tostring(_affected).decode('utf-8') | 
            ||
| 516 | |||
| 517 | @staticmethod  | 
            ||
| 518 | def get_insight_vt_as_xml_str(vt_id, insight):  | 
            ||
| 519 | """ Return insight as string."""  | 
            ||
| 520 |         _insight = Element('insight') | 
            ||
| 521 | _insight.text = insight  | 
            ||
| 522 |         return tostring(_insight).decode('utf-8') | 
            ||
| 523 | |||
| 524 | @staticmethod  | 
            ||
| 525 | def get_solution_vt_as_xml_str(vt_id, solution, solution_type=None):  | 
            ||
| 526 | """ Return solution as string."""  | 
            ||
| 527 |         _solution = Element('solution') | 
            ||
| 528 | _solution.text = solution  | 
            ||
| 529 | if solution_type:  | 
            ||
| 530 |             _solution.set('type', solution_type) | 
            ||
| 531 |         return tostring(_solution).decode('utf-8') | 
            ||
| 532 | |||
| 533 | @staticmethod  | 
            ||
| 534 | def get_detection_vt_as_xml_str(vt_id, vuldetect=None, qod_type=None, qod=None):  | 
            ||
| 535 | """ Return detection as string."""  | 
            ||
| 536 |         _detection = Element('detection') | 
            ||
| 537 | if vuldetect:  | 
            ||
| 538 | _detection.text = vuldetect  | 
            ||
| 539 | if qod_type:  | 
            ||
| 540 |             _detection.set('qod_type', qod_type) | 
            ||
| 541 | elif qod:  | 
            ||
| 542 |             _detection.set('qod', qod) | 
            ||
| 543 | |||
| 544 |         return tostring(_detection).decode('utf-8') | 
            ||
| 545 | |||
| 546 | def check(self):  | 
            ||
| 547 | """ Checks that openvassd command line tool is found and  | 
            ||
| 548 | is executable. """  | 
            ||
| 549 | try:  | 
            ||
| 550 | result = subprocess.check_output(['openvassd', '-V'],  | 
            ||
| 551 | stderr=subprocess.STDOUT)  | 
            ||
| 552 |             result = result.decode('ascii') | 
            ||
| 553 | except OSError:  | 
            ||
| 554 | # The command is not available  | 
            ||
| 555 | return False  | 
            ||
| 556 | |||
| 557 | if result is None:  | 
            ||
| 558 | return False  | 
            ||
| 559 | |||
| 560 |         version = result.split('\n') | 
            ||
| 561 |         if version[0].find('OpenVAS') < 0: | 
            ||
| 562 | return False  | 
            ||
| 563 | |||
| 564 | self.parse_param()  | 
            ||
| 565 | self.scanner_info['version'] = version[0]  | 
            ||
| 566 | |||
| 567 | return True  | 
            ||
| 568 | |||
| 569 | def update_progress(self, scan_id, target, msg):  | 
            ||
| 570 | """ Calculate porcentage and update the scan status  | 
            ||
| 571 | for the progress bar. """  | 
            ||
| 572 | host_progress_dict = dict()  | 
            ||
| 573 | prog = str.split(msg, '/')  | 
            ||
| 574 | if float(prog[1]) == 0:  | 
            ||
| 575 | return  | 
            ||
| 576 | host_prog = (float(prog[0]) / float(prog[1])) * 100  | 
            ||
| 577 | host_progress_dict[target] = host_prog  | 
            ||
| 578 | total_host = len(target_str_to_list(target))  | 
            ||
| 579 | self.set_scan_target_progress(scan_id, target,  | 
            ||
| 580 | sum(host_progress_dict.values()) / total_host)  | 
            ||
| 581 | |||
| 582 | def get_openvas_status(self, scan_id, target):  | 
            ||
| 583 | """ Get all status entries from redis kb. """  | 
            ||
| 584 | res = openvas_db.get_status()  | 
            ||
| 585 | while res:  | 
            ||
| 586 | self.update_progress(scan_id, target, res)  | 
            ||
| 587 | res = openvas_db.get_status()  | 
            ||
| 588 | |||
| 589 | def get_openvas_result(self, scan_id):  | 
            ||
| 590 | """ Get all result entries from redis kb. """  | 
            ||
| 591 | res = openvas_db.get_result()  | 
            ||
| 592 | ctx = openvas_db.db_find(nvti.NVTICACHE_STR)  | 
            ||
| 593 | while res:  | 
            ||
| 594 |             msg = res.split('|||') | 
            ||
| 595 |             host_aux = openvas_db.item_get_single('internal/ip') | 
            ||
| 596 | roid = msg[3]  | 
            ||
| 597 | |||
| 598 | rqod = ''  | 
            ||
| 599 |             if self.vts[roid].get('qod_type'): | 
            ||
| 600 |                 qod_t = self.vts[roid].get('qod_type') | 
            ||
| 601 | rqod = nvti.QoD_TYPES[qod_t]  | 
            ||
| 602 |             elif self.vts[roid].get('qod'): | 
            ||
| 603 |                 rqod = self.vts[roid].get('qod') | 
            ||
| 604 | |||
| 605 |             rseverity = self.vts[roid]['severities'].get('cvss_base') | 
            ||
| 606 |             rname = self.vts[roid].get('name') | 
            ||
| 607 | |||
| 608 | if msg[0] == 'ERRMSG':  | 
            ||
| 609 | self.add_scan_error(scan_id, host=host_aux,  | 
            ||
| 610 | name=rname, value=msg[4], port=msg[2])  | 
            ||
| 611 | if msg[0] == 'LOG':  | 
            ||
| 612 | self.add_scan_log(scan_id, host=host_aux, name=rname,  | 
            ||
| 613 | value=msg[4], port=msg[2], qod=rqod,  | 
            ||
| 614 | test_id=roid)  | 
            ||
| 615 | if msg[0] == 'HOST_DETAIL':  | 
            ||
| 616 | self.add_scan_log(scan_id, host=host_aux, name=rname,  | 
            ||
| 617 | value=msg[4])  | 
            ||
| 618 | if msg[0] == 'ALARM':  | 
            ||
| 619 | self.add_scan_alarm(scan_id, host=host_aux, name=rname,  | 
            ||
| 620 | value=msg[4], port=msg[2],  | 
            ||
| 621 | test_id=roid, severity=rseverity,  | 
            ||
| 622 | qod=rqod)  | 
            ||
| 623 | res = openvas_db.get_result()  | 
            ||
| 624 | |||
| 625 | def get_openvas_timestamp_scan_host(self, scan_id, target):  | 
            ||
| 626 | """ Get start and end timestamp of a host scan from redis kb. """  | 
            ||
| 627 | timestamp = openvas_db.get_host_scan_scan_end_time()  | 
            ||
| 628 | if timestamp:  | 
            ||
| 629 | self.add_scan_log(scan_id, host=target, name='HOST_END',  | 
            ||
| 630 | value=timestamp)  | 
            ||
| 631 | return  | 
            ||
| 632 | timestamp = openvas_db.get_host_scan_scan_start_time()  | 
            ||
| 633 | if timestamp:  | 
            ||
| 634 | self.add_scan_log(scan_id, host=target, name='HOST_START',  | 
            ||
| 635 | value=timestamp)  | 
            ||
| 636 | return  | 
            ||
| 637 | |||
| 638 | def scan_is_finished(self, scan_id):  | 
            ||
| 639 | """ Check if the scan has finished. """  | 
            ||
| 640 |         status = openvas_db.item_get_single(('internal/%s' % scan_id)) | 
            ||
| 641 | return status == 'finished'  | 
            ||
| 642 | |||
| 643 | def scan_is_stopped(self, scan_id):  | 
            ||
| 644 | """ Check if the parent process has received the stop_scan order.  | 
            ||
| 645 | @in scan_id: ID to identify the scan to be stopped.  | 
            ||
| 646 | @return 1 if yes, None in other case.  | 
            ||
| 647 | """  | 
            ||
| 648 | ctx = openvas_db.kb_connect(dbnum=MAIN_KBINDEX)  | 
            ||
| 649 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 650 |         status = openvas_db.item_get_single(('internal/%s' % scan_id)) | 
            ||
| 651 | return status == 'stop_all'  | 
            ||
| 652 | |||
| 653 | @staticmethod  | 
            ||
| 654 | def stop_scan(global_scan_id):  | 
            ||
| 655 | """ Set a key in redis to indicate the wrapper is stopped.  | 
            ||
| 656 | It is done through redis because it is a new multiprocess  | 
            ||
| 657 | instance and it is not possible to reach the variables  | 
            ||
| 658 | of the grandchild process. Send SIGUSR2 to openvas to stop  | 
            ||
| 659 | each running scan."""  | 
            ||
| 660 | ctx = openvas_db.kb_connect()  | 
            ||
| 661 | for current_kbi in range(0, openvas_db.MAX_DBINDEX):  | 
            ||
| 662 |             ctx.execute_command('SELECT '+ str(current_kbi)) | 
            ||
| 663 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 664 | scan_id = openvas_db.item_get_single(  | 
            ||
| 665 |                 ('internal/%s/globalscanid' % global_scan_id)) | 
            ||
| 666 | if scan_id:  | 
            ||
| 667 |                 openvas_db.item_set_single(('internal/%s' % scan_id), | 
            ||
| 668 | ['stop_all', ])  | 
            ||
| 669 |                 ovas_pid = openvas_db.item_get_single('internal/ovas_pid') | 
            ||
| 670 | parent = psutil.Process(int(ovas_pid))  | 
            ||
| 671 | openvas_db.release_db(current_kbi)  | 
            ||
| 672 | parent.send_signal(signal.SIGUSR2)  | 
            ||
| 673 |                 logger.debug('Stopping process: {0}'.format(parent)) | 
            ||
| 674 | |||
| 675 | def get_vts_in_groups(self, ctx, filters):  | 
            ||
| 676 | """ Return a list of vts which match with the given filter.  | 
            ||
| 677 | |||
| 678 | @input filters A list of filters. Each filter has key, operator and  | 
            ||
| 679 | a value. They are separated by a space.  | 
            ||
| 680 | Supported keys: family  | 
            ||
| 681 | @return Return a list of vts which match with the given filter.  | 
            ||
| 682 | """  | 
            ||
| 683 | vts_list = list()  | 
            ||
| 684 | families = dict()  | 
            ||
| 685 | oids = nvti.get_oids()  | 
            ||
| 686 | for filename, oid in oids:  | 
            ||
| 687 |             family = self.vts[oid]['custom'].get('family') | 
            ||
| 688 | if family not in families:  | 
            ||
| 689 | families[family] = list()  | 
            ||
| 690 | families[family].append(oid)  | 
            ||
| 691 | |||
| 692 | for elem in filters:  | 
            ||
| 693 |             key, value = elem.split('=') | 
            ||
| 694 | if key == 'family' and value in families:  | 
            ||
| 695 | vts_list.extend(families[value])  | 
            ||
| 696 | return vts_list  | 
            ||
| 697 | |||
| 698 | def get_vt_param_type(self, vtid, vt_param_id):  | 
            ||
| 699 | """ Return the type of the vt parameter from the vts dictionary. """  | 
            ||
| 700 |         vt_params_list = self.vts[vtid].get("vt_params") | 
            ||
| 701 | return vt_params_list[vt_param_id]["type"]  | 
            ||
| 702 | |||
| 703 | @staticmethod  | 
            ||
| 704 | def check_param_type(vt_param_value, param_type):  | 
            ||
| 705 | """ Check if the value of a vt parameter matches with  | 
            ||
| 706 | the type founded.  | 
            ||
| 707 | """  | 
            ||
| 708 | if (param_type in ['entry',  | 
            ||
| 709 | 'file',  | 
            ||
| 710 | 'password',  | 
            ||
| 711 | 'radio',  | 
            ||
| 712 | 'sshlogin', ] and isinstance(vt_param_value, str)):  | 
            ||
| 713 | return None  | 
            ||
| 714 | elif (param_type == 'checkbox' and  | 
            ||
| 715 | (vt_param_value == 'yes' or vt_param_value == 'no')):  | 
            ||
| 716 | return None  | 
            ||
| 717 | elif param_type == 'integer':  | 
            ||
| 718 | try:  | 
            ||
| 719 | int(vt_param_value)  | 
            ||
| 720 | except ValueError:  | 
            ||
| 721 | return 1  | 
            ||
| 722 | return None  | 
            ||
| 723 | |||
| 724 | return 1  | 
            ||
| 725 | |||
| 726 | def process_vts(self, vts):  | 
            ||
| 727 | """ Add single VTs and their parameters. """  | 
            ||
| 728 | vts_list = []  | 
            ||
| 729 | vts_params = []  | 
            ||
| 730 |         vtgroups = vts.pop('vt_groups') | 
            ||
| 731 | |||
| 732 | ctx = openvas_db.db_find(nvti.NVTICACHE_STR)  | 
            ||
| 733 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 734 | if vtgroups:  | 
            ||
| 735 | vts_list = self.get_vts_in_groups(ctx, vtgroups)  | 
            ||
| 736 | |||
| 737 | for vtid, vt_params in vts.items():  | 
            ||
| 738 | vts_list.append(vtid)  | 
            ||
| 739 |             nvt_name = self.vts[vtid].get('name') | 
            ||
| 740 | for vt_param_id, vt_param_value in vt_params.items():  | 
            ||
| 741 | param_type = self.get_vt_param_type(vtid, vt_param_id)  | 
            ||
| 742 | if vt_param_id == 'timeout':  | 
            ||
| 743 | type_aux = 'integer'  | 
            ||
| 744 | else:  | 
            ||
| 745 | type_aux = param_type  | 
            ||
| 746 | if self.check_param_type(vt_param_value, type_aux):  | 
            ||
| 747 |                     logger.debug('Expected {} type for parameter value {}' | 
            ||
| 748 | .format(type_aux, str(vt_param_value)))  | 
            ||
| 749 |                 param = ["{0}[{1}]:{2}".format(nvt_name, param_type, | 
            ||
| 750 | vt_param_id),  | 
            ||
| 751 | str(vt_param_value)]  | 
            ||
| 752 | vts_params.append(param)  | 
            ||
| 753 | return vts_list, vts_params  | 
            ||
| 754 | |||
| 755 | @staticmethod  | 
            ||
| 756 | def build_credentials_as_prefs(credentials):  | 
            ||
| 757 | """ Parse the credential dictionary.  | 
            ||
| 758 | @param credentials: Dictionary with the credentials.  | 
            ||
| 759 | |||
| 760 | @return A list with the credentials in string format to be  | 
            ||
| 761 | added to the redis KB.  | 
            ||
| 762 | """  | 
            ||
| 763 | cred_prefs_list = []  | 
            ||
| 764 | for credential in credentials.items():  | 
            ||
| 765 | service = credential[0]  | 
            ||
| 766 | cred_params = credentials.get(service)  | 
            ||
| 767 |             cred_type = cred_params.get('type', '') | 
            ||
| 768 |             username = cred_params.get('username', '') | 
            ||
| 769 |             password = cred_params.get('password', '') | 
            ||
| 770 | |||
| 771 | if service == 'ssh':  | 
            ||
| 772 |                 port = cred_params.get('port', '') | 
            ||
| 773 |                 cred_prefs_list.append('auth_port_ssh|||' + | 
            ||
| 774 |                                        '{0}'.format(port)) | 
            ||
| 775 |                 cred_prefs_list.append('SSH Authorization[entry]:SSH login ' + | 
            ||
| 776 |                                        'name:|||{0}'.format(username)) | 
            ||
| 777 | if cred_type == 'up':  | 
            ||
| 778 |                     cred_prefs_list.append('SSH Authorization[password]:' + | 
            ||
| 779 | 'SSH password (unsafe!):|||' +  | 
            ||
| 780 |                                            '{0}'.format(password)) | 
            ||
| 781 | else:  | 
            ||
| 782 |                     private = cred_params.get('private', '') | 
            ||
| 783 |                     cred_prefs_list.append('SSH Authorization[password]:' + | 
            ||
| 784 | 'SSH key passphrase:|||' +  | 
            ||
| 785 |                                            '{0}'.format(password)) | 
            ||
| 786 |                     cred_prefs_list.append('SSH Authorization[file]:' + | 
            ||
| 787 | 'SSH private key:|||' +  | 
            ||
| 788 |                                            '{0}'.format(private)) | 
            ||
| 789 | if service == 'smb':  | 
            ||
| 790 |                 cred_prefs_list.append('SMB Authorization[entry]:SMB login:' + | 
            ||
| 791 |                                        '|||{0}'.format(username)) | 
            ||
| 792 |                 cred_prefs_list.append('SMB Authorization[password]:' + | 
            ||
| 793 | 'SMB password :|||' +  | 
            ||
| 794 |                                        '{0}'.format(password)) | 
            ||
| 795 | if service == 'esxi':  | 
            ||
| 796 |                 cred_prefs_list.append('ESXi Authorization[entry]:ESXi login ' + | 
            ||
| 797 |                                        'name:|||{0}'.format(username)) | 
            ||
| 798 |                 cred_prefs_list.append('ESXi Authorization[password]:' + | 
            ||
| 799 | 'ESXi login password:|||' +  | 
            ||
| 800 |                                        '{0}'.format(password)) | 
            ||
| 801 | |||
| 802 | if service == 'snmp':  | 
            ||
| 803 |                 community = cred_params.get('community', '') | 
            ||
| 804 |                 auth_algorithm = cred_params.get('auth_algorithm', '') | 
            ||
| 805 |                 privacy_password = cred_params.get('privacy_password', '') | 
            ||
| 806 |                 privacy_algorithm = cred_params.get('privacy_algorithm', '') | 
            ||
| 807 | |||
| 808 |                 cred_prefs_list.append('SNMP Authorization[password]:' + | 
            ||
| 809 | 'SNMP Community:' +  | 
            ||
| 810 |                                        '{0}'.format(community)) | 
            ||
| 811 |                 cred_prefs_list.append('SNMP Authorization[entry]:' + | 
            ||
| 812 | 'SNMPv3 Username:' +  | 
            ||
| 813 |                                        '{0}'.format(username)) | 
            ||
| 814 |                 cred_prefs_list.append('SNMP Authorization[password]:' + | 
            ||
| 815 | 'SNMPv3 Password:' +  | 
            ||
| 816 |                                        '{0}'.format(password)) | 
            ||
| 817 |                 cred_prefs_list.append('SNMP Authorization[radio]:' + | 
            ||
| 818 | 'SNMPv3 Authentication Algorithm:' +  | 
            ||
| 819 |                                        '{0}'.format(auth_algorithm)) | 
            ||
| 820 |                 cred_prefs_list.append('SNMP Authorization[password]:' + | 
            ||
| 821 | 'SNMPv3 Privacy Password:' +  | 
            ||
| 822 |                                        '{0}'.format(privacy_password)) | 
            ||
| 823 |                 cred_prefs_list.append('SNMP Authorization[radio]:' + | 
            ||
| 824 | 'SNMPv3 Privacy Algorithm:' +  | 
            ||
| 825 |                                        '{0}'.format(privacy_algorithm)) | 
            ||
| 826 | |||
| 827 | return cred_prefs_list  | 
            ||
| 828 | |||
| 829 | def exec_scan(self, scan_id, target):  | 
            ||
| 830 | """ Starts the OpenVAS scanner for scan_id scan. """  | 
            ||
| 831 | if self.pending_feed:  | 
            ||
| 832 | logger.info(  | 
            ||
| 833 | '%s: There is a pending feed update. '  | 
            ||
| 834 | 'The scan can not be started.' % scan_id)  | 
            ||
| 835 | self.add_scan_error(  | 
            ||
| 836 | scan_id, name='', host=target,  | 
            ||
| 837 |                 value=('It was not possible to start the scan,' | 
            ||
| 838 | 'because a pending feed update. Please try later'))  | 
            ||
| 839 | return 2  | 
            ||
| 840 | |||
| 841 | global MAIN_KBINDEX  | 
            ||
| 842 | ports = self.get_scan_ports(scan_id, target)  | 
            ||
| 843 | if not ports:  | 
            ||
| 844 | self.add_scan_error(scan_id, name='', host=target,  | 
            ||
| 845 | value='No port list defined.')  | 
            ||
| 846 | return 2  | 
            ||
| 847 | |||
| 848 | # Get scan options  | 
            ||
| 849 | options = self.get_scan_options(scan_id)  | 
            ||
| 850 | prefs_val = []  | 
            ||
| 851 | ctx = openvas_db.kb_new()  | 
            ||
| 852 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 853 | MAIN_KBINDEX = openvas_db.DB_INDEX  | 
            ||
| 854 | |||
| 855 | # To avoid interference between scan process during a parallel scanning  | 
            ||
| 856 | # new uuid is used internally for each scan.  | 
            ||
| 857 | openvas_scan_id = str(uuid.uuid4())  | 
            ||
| 858 |         openvas_db.item_add_single(('internal/%s' % openvas_scan_id), ['new', ]) | 
            ||
| 859 |         openvas_db.item_add_single(('internal/%s/globalscanid' % scan_id), [openvas_scan_id, ]) | 
            ||
| 860 | |||
| 861 | # Set scan preferences  | 
            ||
| 862 | for item in options.items():  | 
            ||
| 863 | item_type = ''  | 
            ||
| 864 | if item[0] in OSPD_PARAMS:  | 
            ||
| 865 |                 item_type = OSPD_PARAMS[item[0]].get('type') | 
            ||
| 866 | if item_type == 'boolean' and item[1] == 1:  | 
            ||
| 867 | val = 'yes'  | 
            ||
| 868 | else:  | 
            ||
| 869 | val = str(item[1])  | 
            ||
| 870 | prefs_val.append(item[0] + "|||" + val)  | 
            ||
| 871 |         openvas_db.item_add_single(str('internal/%s/scanprefs' % (openvas_scan_id)), | 
            ||
| 872 | prefs_val)  | 
            ||
| 873 | |||
| 874 | # Store MAIN_KBINDEX as global preference  | 
            ||
| 875 |         ov_maindbid = ('ov_maindbid|||%d' % MAIN_KBINDEX) | 
            ||
| 876 |         openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id), | 
            ||
| 877 | [ov_maindbid, ])  | 
            ||
| 878 | |||
| 879 | # Set target  | 
            ||
| 880 |         target_aux = ('TARGET|||%s' % target) | 
            ||
| 881 |         openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id), | 
            ||
| 882 | [target_aux, ])  | 
            ||
| 883 | # Set port range  | 
            ||
| 884 |         port_range = ('port_range|||%s' % ports) | 
            ||
| 885 |         openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id), | 
            ||
| 886 | [port_range, ])  | 
            ||
| 887 | |||
| 888 | # Set credentials  | 
            ||
| 889 | credentials = self.get_scan_credentials(scan_id, target)  | 
            ||
| 890 | if credentials:  | 
            ||
| 891 | cred_prefs = self.build_credentials_as_prefs(credentials)  | 
            ||
| 892 |             openvas_db.item_add_single(str('internal/%s/scanprefs' % openvas_scan_id), | 
            ||
| 893 | cred_prefs)  | 
            ||
| 894 | |||
| 895 | # Set plugins to run  | 
            ||
| 896 | nvts = self.get_scan_vts(scan_id)  | 
            ||
| 897 | if nvts != '':  | 
            ||
| 898 | nvts_list, nvts_params = self.process_vts(nvts)  | 
            ||
| 899 | # Select the scan KB again.  | 
            ||
| 900 |             ctx.execute_command('SELECT '+ str(MAIN_KBINDEX)) | 
            ||
| 901 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 902 | # Add nvts list  | 
            ||
| 903 | separ = ';'  | 
            ||
| 904 |             plugin_list = ('plugin_set|||%s' % separ.join(nvts_list)) | 
            ||
| 905 |             openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id), | 
            ||
| 906 | [plugin_list, ])  | 
            ||
| 907 | # Add nvts parameters  | 
            ||
| 908 | for elem in nvts_params:  | 
            ||
| 909 |                 item = ('%s|||%s' % (elem[0], elem[1])) | 
            ||
| 910 |                 openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id), | 
            ||
| 911 | [item, ])  | 
            ||
| 912 | else:  | 
            ||
| 913 | openvas_db.release_db(MAIN_KBINDEX)  | 
            ||
| 914 | self.add_scan_error(scan_id, name='', host=target,  | 
            ||
| 915 | value='No VTS to run.')  | 
            ||
| 916 | return 2  | 
            ||
| 917 | |||
| 918 | # Create a general log entry about executing OpenVAS  | 
            ||
| 919 | # It is important to send at least one result, otherwise  | 
            ||
| 920 | # the host details won't be stored.  | 
            ||
| 921 | self.add_scan_log(scan_id, host=target, name='OpenVAS summary',  | 
            ||
| 922 | value='An OpenVAS Scanner was started for %s.'  | 
            ||
| 923 | % target)  | 
            ||
| 924 | |||
| 925 | self.add_scan_log(scan_id, host=target, name='KB location Found',  | 
            ||
| 926 | value='KB location path was found: %s.'  | 
            ||
| 927 | % openvas_db.DB_ADDRESS)  | 
            ||
| 928 | |||
| 929 | self.add_scan_log(scan_id, host=target, name='Feed Update',  | 
            ||
| 930 | value='Feed version: %s.'  | 
            ||
| 931 | % nvti.get_feed_version())  | 
            ||
| 932 | |||
| 933 | cmd = ['openvassd', '--scan-start', openvas_scan_id]  | 
            ||
| 934 | try:  | 
            ||
| 935 | result = subprocess.Popen(cmd, shell=False)  | 
            ||
| 936 | except OSError:  | 
            ||
| 937 | # the command is not available  | 
            ||
| 938 | return False  | 
            ||
| 939 | |||
| 940 | ovas_pid = result.pid  | 
            ||
| 941 |         logger.debug('pid = {0}'.format(ovas_pid)) | 
            ||
| 942 |         openvas_db.item_add_single(('internal/ovas_pid'), [ovas_pid, ]) | 
            ||
| 943 | |||
| 944 | # Wait until the scanner starts and loads all the preferences.  | 
            ||
| 945 |         while openvas_db.item_get_single('internal/'+ openvas_scan_id) == 'new': | 
            ||
| 946 | time.sleep(1)  | 
            ||
| 947 | |||
| 948 | no_id_found = False  | 
            ||
| 949 | while True:  | 
            ||
| 950 | time.sleep(3)  | 
            ||
| 951 | |||
| 952 | # Check if the client stopped the whole scan  | 
            ||
| 953 | if self.scan_is_stopped(openvas_scan_id):  | 
            ||
| 954 | return 1  | 
            ||
| 955 | |||
| 956 | ctx = openvas_db.kb_connect(MAIN_KBINDEX)  | 
            ||
| 957 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 958 |             dbs = openvas_db.item_get_set('internal/dbindex') | 
            ||
| 959 | for i in list(dbs):  | 
            ||
| 960 | if i == MAIN_KBINDEX:  | 
            ||
| 961 | continue  | 
            ||
| 962 |                 ctx.execute_command('SELECT '+ str(i)) | 
            ||
| 963 | openvas_db.set_global_redisctx(ctx)  | 
            ||
| 964 |                 id_aux = ctx.execute_command('srandmember internal/scan_id') | 
            ||
| 965 | if not id_aux:  | 
            ||
| 966 | continue  | 
            ||
| 967 | if id_aux == openvas_scan_id:  | 
            ||
| 968 | no_id_found = False  | 
            ||
| 969 | self.get_openvas_timestamp_scan_host(scan_id, target)  | 
            ||
| 970 | self.get_openvas_result(scan_id)  | 
            ||
| 971 | self.get_openvas_status(scan_id, target)  | 
            ||
| 972 | if self.scan_is_finished(openvas_scan_id):  | 
            ||
| 973 |                         ctx.execute_command('SELECT '+ str(MAIN_KBINDEX)) | 
            ||
| 974 |                         openvas_db.remove_set_member('internal/dbindex', i) | 
            ||
| 975 | openvas_db.release_db(i)  | 
            ||
| 976 | |||
| 977 | # Scan end. No kb in use for this scan id  | 
            ||
| 978 | if no_id_found:  | 
            ||
| 979 | break  | 
            ||
| 980 | no_id_found = True  | 
            ||
| 981 | |||
| 982 | # Delete keys from KB related to this scan task.  | 
            ||
| 983 | openvas_db.release_db(MAIN_KBINDEX)  | 
            ||
| 984 | return 1  | 
            ||
| 985 | |||
| 986 | |||
| 987 | def main():  | 
            ||
| 988 | """ OSP openvas main function. """  | 
            ||
| 989 |     daemon_main('OSPD - openvas wrapper', OSPDopenvas) | 
            ||
| 990 | 
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.