Passed
Pull Request — master (#105)
by Juan José
01:22
created

ospd_openvas.daemon.OSPDopenvas.feed_is_outdated()   B

Complexity

Conditions 8

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 20
nop 2
dl 0
loc 31
rs 7.3333
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018 Greenbone Networks GmbH
3
#
4
# SPDX-License-Identifier: GPL-2.0-or-later
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (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, write to the Free Software
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20
# pylint: disable=too-many-lines
21
22
""" Setup for the OSP OpenVAS Server. """
23
24
import logging
25
import subprocess
26
import time
27
import uuid
28
29
from pathlib import Path
30
from lxml.etree import tostring, SubElement, Element
31
32
import psutil
33
34
from ospd.errors import OspdError
35
from ospd.ospd import OSPDaemon
36
from ospd.main import main as daemon_main
37
from ospd.cvss import CVSS
38
from ospd.vtfilter import VtsFilter
39
40
from ospd_openvas import __version__
41
from ospd_openvas.errors import OspdOpenvasError
42
43
from ospd_openvas.nvticache import NVTICache
44
from ospd_openvas.db import OpenvasDB
45
46
logger = logging.getLogger(__name__)
47
48
OSPD_DESC = """
49
This scanner runs 'OpenVAS Scanner' to scan the target hosts.
50
51
OpenVAS (Open Vulnerability Assessment Scanner) is a powerful scanner
52
for vulnerabilities in IT infrastrucutres. The capabilities include
53
unauthenticated scanning as well as authenticated scanning for
54
various types of systems and services.
55
56
For more details about OpenVAS see the OpenVAS homepage:
57
http://www.openvas.org/
58
59
The current version of ospd-openvas is a simple frame, which sends
60
the server parameters to the Greenbone Vulnerability Manager daemon (GVMd) and
61
checks the existence of OpenVAS scanner binary. But it can not run scans yet.
62
"""
63
64
OSPD_PARAMS = {
65
    'auto_enable_dependencies': {
66
        'type': 'boolean',
67
        'name': 'auto_enable_dependencies',
68
        'default': 1,
69
        'mandatory': 1,
70
        'description': 'Automatically enable the plugins that are depended on',
71
    },
72
    'cgi_path': {
73
        'type': 'string',
74
        'name': 'cgi_path',
75
        'default': '/cgi-bin:/scripts',
76
        'mandatory': 1,
77
        'description': 'Look for default CGIs in /cgi-bin and /scripts',
78
    },
79
    'checks_read_timeout': {
80
        'type': 'integer',
81
        'name': 'checks_read_timeout',
82
        'default': 5,
83
        'mandatory': 1,
84
        'description': (
85
            'Number  of seconds that the security checks will '
86
            + 'wait for when doing a recv()'
87
        ),
88
    },
89
    'drop_privileges': {
90
        'type': 'boolean',
91
        'name': 'drop_privileges',
92
        'default': 0,
93
        'mandatory': 1,
94
        'description': '',
95
    },
96
    'network_scan': {
97
        'type': 'boolean',
98
        'name': 'network_scan',
99
        'default': 0,
100
        'mandatory': 1,
101
        'description': '',
102
    },
103
    'non_simult_ports': {
104
        'type': 'string',
105
        'name': 'non_simult_ports',
106
        'default': '139, 445, 3389, Services/irc',
107
        'mandatory': 1,
108
        'description': (
109
            'Prevent to make two connections on the same given '
110
            + 'ports at the same time.'
111
        ),
112
    },
113
    'open_sock_max_attempts': {
114
        'type': 'integer',
115
        'name': 'open_sock_max_attempts',
116
        'default': 5,
117
        'mandatory': 0,
118
        'description': (
119
            'Number of unsuccessful retries to open the socket '
120
            + 'before to set the port as closed.'
121
        ),
122
    },
123
    'timeout_retry': {
124
        'type': 'integer',
125
        'name': 'timeout_retry',
126
        'default': 5,
127
        'mandatory': 0,
128
        'description': (
129
            'Number of retries when a socket connection attempt ' + 'timesout.'
130
        ),
131
    },
132
    'optimize_test': {
133
        'type': 'integer',
134
        'name': 'optimize_test',
135
        'default': 5,
136
        'mandatory': 0,
137
        'description': (
138
            'By default, openvas does not trust the remote ' + 'host banners.'
139
        ),
140
    },
141
    'plugins_timeout': {
142
        'type': 'integer',
143
        'name': 'plugins_timeout',
144
        'default': 5,
145
        'mandatory': 0,
146
        'description': 'This is the maximum lifetime, in seconds of a plugin.',
147
    },
148
    'report_host_details': {
149
        'type': 'boolean',
150
        'name': 'report_host_details',
151
        'default': 1,
152
        'mandatory': 1,
153
        'description': '',
154
    },
155
    'safe_checks': {
156
        'type': 'boolean',
157
        'name': 'safe_checks',
158
        'default': 1,
159
        'mandatory': 1,
160
        'description': (
161
            'Disable the plugins with potential to crash '
162
            + 'the remote services'
163
        ),
164
    },
165
    'scanner_plugins_timeout': {
166
        'type': 'integer',
167
        'name': 'scanner_plugins_timeout',
168
        'default': 36000,
169
        'mandatory': 1,
170
        'description': 'Like plugins_timeout, but for ACT_SCANNER plugins.',
171
    },
172
    'time_between_request': {
173
        'type': 'integer',
174
        'name': 'time_between_request',
175
        'default': 0,
176
        'mandatory': 0,
177
        'description': (
178
            'Allow to set a wait time between two actions '
179
            + '(open, send, close).'
180
        ),
181
    },
182
    'unscanned_closed': {
183
        'type': 'boolean',
184
        'name': 'unscanned_closed',
185
        'default': 1,
186
        'mandatory': 1,
187
        'description': '',
188
    },
189
    'unscanned_closed_udp': {
190
        'type': 'boolean',
191
        'name': 'unscanned_closed_udp',
192
        'default': 1,
193
        'mandatory': 1,
194
        'description': '',
195
    },
196
    'use_mac_addr': {
197
        'type': 'boolean',
198
        'name': 'use_mac_addr',
199
        'default': 0,
200
        'mandatory': 0,
201
        'description': 'To test the local network. '
202
        + 'Hosts will be referred to by their MAC address.',
0 ignored issues
show
Coding Style introduced by
Wrong continued indentation (add 15 spaces).
Loading history...
203
    },
204
    'vhosts': {
205
        'type': 'string',
206
        'name': 'vhosts',
207
        'default': '',
208
        'mandatory': 0,
209
        'description': '',
210
    },
211
    'vhosts_ip': {
212
        'type': 'string',
213
        'name': 'vhosts_ip',
214
        'default': '',
215
        'mandatory': 0,
216
        'description': '',
217
    },
218
}
219
220
OID_SSH_AUTH = "1.3.6.1.4.1.25623.1.0.103591"
221
OID_SMB_AUTH = "1.3.6.1.4.1.25623.1.0.90023"
222
OID_ESXI_AUTH = "1.3.6.1.4.1.25623.1.0.105058"
223
OID_SNMP_AUTH = "1.3.6.1.4.1.25623.1.0.105076"
224
225
226
def _from_bool_to_str(value):
227
    """ The OpenVAS scanner use yes and no as boolean values, whereas ospd
228
    uses 1 and 0."""
229
    return 'yes' if value == 1 else 'no'
230
231
232
class OpenVasVtsFilter(VtsFilter):
233
    """ Methods to overwrite the ones in the original class.
234
    Each method formats the value to be compatible with the filter
235
    """
236
237
    def format_vt_modification_time(self, value):
238
        """ Convert the datetime value in an 19 character string
239
        representing YearMonthDateHourMinuteSecond.
240
        e.g. 20190319122532
241
        """
242
243
        date = value[7:26].replace(" ", "")
244
        date = date.replace("-", "")
245
        date = date.replace(":", "")
246
        return date
247
248
249
class OSPDopenvas(OSPDaemon):
250
251
    """ Class for ospd-openvas daemon. """
252
253
    def __init__(self, *, niceness=None, **kwargs):
254
        """ Initializes the ospd-openvas daemon's internal data. """
255
256
        super().__init__(customvtfilter=OpenVasVtsFilter())
257
258
        self.server_version = __version__
259
260
        self._niceness = str(niceness)
261
262
        self.scanner_info['name'] = 'openvas'
263
        self.scanner_info['version'] = ''  # achieved during self.check()
264
        self.scanner_info['description'] = OSPD_DESC
265
266
        for name, param in OSPD_PARAMS.items():
267
            self.add_scanner_param(name, param)
268
269
        self._sudo_available = None
270
271
        self.scan_only_params = dict()
272
273
        self.main_kbindex = None
274
275
        self.openvas_db = OpenvasDB()
276
277
        self.nvti = NVTICache(self.openvas_db)
278
279
        self.pending_feed = None
280
281
    def init(self):
282
        self.openvas_db.db_init()
283
284
        ctx = self.openvas_db.db_find(self.nvti.NVTICACHE_STR)
285
286
        if not ctx:
287
            self.redis_nvticache_init()
288
            ctx = self.openvas_db.db_find(self.nvti.NVTICACHE_STR)
289
290
        self.openvas_db.set_redisctx(ctx)
291
292
        self.load_vts()
293
294
    def parse_param(self):
295
        """ Set OSPD_PARAMS with the params taken from the openvas_scanner. """
296
        bool_dict = {'no': 0, 'yes': 1}
297
298
        result = subprocess.check_output(
299
            ['openvas', '-s'], stderr=subprocess.STDOUT
300
        )
301
        result = result.decode('ascii')
302
        param_list = dict()
303
        for conf in result.split('\n'):
304
            elem = conf.split('=')
305
            if len(elem) == 2:
306
                value = str.strip(elem[1])
307
                if str.strip(elem[1]) in bool_dict:
308
                    value = bool_dict[value]
309
                param_list[str.strip(elem[0])] = value
310
        for elem in OSPD_PARAMS:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable OSPD_PARAMS does not seem to be defined.
Loading history...
311
            if elem in param_list:
312
                OSPD_PARAMS[elem]['default'] = param_list[elem]
313
        for elem in param_list:
314
            if elem not in OSPD_PARAMS:
315
                self.scan_only_params[elem] = param_list[elem]
316
317
    def redis_nvticache_init(self):
318
        """ Loads NVT's metadata into Redis DB. """
319
        try:
320
            logger.debug('Loading NVTs in Redis DB')
321
            subprocess.check_call(['openvas', '--update-vt-info'])
322
        except subprocess.CalledProcessError as err:
323
            logger.error('OpenVAS Scanner failed to load NVTs. %s', err)
324
325
    def feed_is_outdated(self, current_feed):
326
        """ Compare the current feed with the one in the disk.
327
328
        Return:
329
            False if there is no new feed.
330
            True if the feed version in disk is newer than the feed in
331
            redis cache.
332
            None if there is no feed
333
            the disk.
334
        """
335
        plugins_folder = self.scan_only_params.get('plugins_folder')
336
        if not plugins_folder:
337
            raise OspdOpenvasError("Error: Path to plugins folder not found.")
338
339
        feed_info_file = Path(plugins_folder) / 'plugin_feed_info.inc'
340
        if not feed_info_file.exists():
341
            self.parse_param()
342
            msg = 'Plugins feed file %s not found.' % feed_info_file
343
            logger.debug(msg)
344
            return None
345
346
        date = 0
347
        with open(str(feed_info_file)) as fcontent:
348
            for line in fcontent:
349
                if "PLUGIN_SET" in line:
350
                    date = line.split(' = ')[1]
351
                    date = date.replace(';', '')
352
                    date = date.replace('"', '')
353
        if int(current_feed) < int(date) or int(date) == 0:
354
            return True
355
        return False
356
357
    def check_feed(self):
358
        """ Check if there is a feed update. Wait until all the running
359
        scans finished. Set a flag to anounce there is a pending feed update,
360
        which avoid to start a new scan.
361
        """
362
        current_feed = self.nvti.get_feed_version()
363
        # Check if the feed is already accessible in the disk.
364
        if self.feed_is_outdated(current_feed) is None:
365
            self.pending_feed = True
366
            return
367
368
        # Check if the nvticache in redis is outdated
369
        if not current_feed or self.feed_is_outdated(current_feed):
370
            self.redis_nvticache_init()
371
            ctx = self.openvas_db.db_find(self.nvti.NVTICACHE_STR)
372
            self.openvas_db.set_redisctx(ctx)
373
            self.pending_feed = True
374
375
        _running_scan = False
376
        for scan_id in self.scan_processes:
377
            if self.scan_processes[scan_id].is_alive():
378
                _running_scan = True
379
380
        # Check if the NVT dict is outdated
381
        if self.pending_feed:
382
            _pending_feed = True
383
        else:
384
            _pending_feed = (
385
                self.get_vts_version() != self.nvti.get_feed_version()
386
            )
387
388
        if _running_scan and _pending_feed:
389
            if not self.pending_feed:
390
                self.pending_feed = True
391
                logger.debug(
392
                    'There is a running scan. Therefore the feed '
393
                    'update will be performed later.'
394
                )
395
        elif not _running_scan and _pending_feed:
396
            self.vts = dict()
397
            self.load_vts()
398
399
    def scheduler(self):
400
        """This method is called periodically to run tasks."""
401
        self.check_feed()
402
403
    def load_vts(self):
404
        """ Load the NVT's metadata into the vts
405
        global  dictionary. """
406
        logger.debug('Loading vts in memory.')
407
        oids = dict(self.nvti.get_oids())
408
        for _filename, vt_id in oids.items():
409
            _vt_params = self.nvti.get_nvt_params(vt_id)
410
            _vt_refs = self.nvti.get_nvt_refs(vt_id)
411
            _custom = self.nvti.get_nvt_metadata(vt_id)
412
            _name = _custom.pop('name')
413
            _vt_creation_time = _custom.pop('creation_date')
414
            _vt_modification_time = _custom.pop('last_modification')
415
416
            _summary = None
417
            _impact = None
418
            _affected = None
419
            _insight = None
420
            _solution = None
421
            _solution_t = None
422
            _vuldetect = None
423
            _qod_t = None
424
            _qod_v = None
425
426
            if 'summary' in _custom:
427
                _summary = _custom.pop('summary')
428
            if 'impact' in _custom:
429
                _impact = _custom.pop('impact')
430
            if 'affected' in _custom:
431
                _affected = _custom.pop('affected')
432
            if 'insight' in _custom:
433
                _insight = _custom.pop('insight')
434
            if 'solution' in _custom:
435
                _solution = _custom.pop('solution')
436
                if 'solution_type' in _custom:
437
                    _solution_t = _custom.pop('solution_type')
438
439
            if 'vuldetect' in _custom:
440
                _vuldetect = _custom.pop('vuldetect')
441
            if 'qod_type' in _custom:
442
                _qod_t = _custom.pop('qod_type')
443
            elif 'qod' in _custom:
444
                _qod_v = _custom.pop('qod')
445
446
            _severity = dict()
447
            if 'severity_base_vector' in _custom:
448
                _severity_vector = _custom.pop('severity_base_vector')
449
            else:
450
                _severity_vector = _custom.pop('cvss_base_vector')
451
            _severity['severity_base_vector'] = _severity_vector
452
            if 'severity_type' in _custom:
453
                _severity_type = _custom.pop('severity_type')
454
            else:
455
                _severity_type = 'cvss_base_v2'
456
            _severity['severity_type'] = _severity_type
457
            if 'severity_origin' in _custom:
458
                _severity['severity_origin'] = _custom.pop('severity_origin')
459
460
            _vt_dependencies = list()
461
            if 'dependencies' in _custom:
462
                _deps = _custom.pop('dependencies')
463
                _deps_list = _deps.split(', ')
464
                for dep in _deps_list:
465
                    _vt_dependencies.append(oids.get('filename:' + dep))
466
467
            try:
468
                self.add_vt(
469
                    vt_id,
470
                    name=_name,
471
                    vt_params=_vt_params,
472
                    vt_refs=_vt_refs,
473
                    custom=_custom,
474
                    vt_creation_time=_vt_creation_time,
475
                    vt_modification_time=_vt_modification_time,
476
                    vt_dependencies=_vt_dependencies,
477
                    summary=_summary,
478
                    impact=_impact,
479
                    affected=_affected,
480
                    insight=_insight,
481
                    solution=_solution,
482
                    solution_t=_solution_t,
483
                    detection=_vuldetect,
484
                    qod_t=_qod_t,
485
                    qod_v=_qod_v,
486
                    severities=_severity,
487
                )
488
            except OspdError as e:
489
                logger.info("Error while adding vt. %s", e)
490
491
        _feed_version = self.nvti.get_feed_version()
492
        self.set_vts_version(vts_version=_feed_version)
493
        self.pending_feed = False
494
        logger.debug('Finish loading up vts.')
495
496
    @staticmethod
497
    def get_custom_vt_as_xml_str(vt_id, custom):
498
        """ Return an xml element with custom metadata formatted as string.
499
        Arguments:
500
            vt_id (str): VT OID. Only used for logging in error case.
501
            custom (dict): Dictionary with the custom metadata.
502
        Return:
503
            string: xml element as string.
504
        """
505
506
        _custom = Element('custom')
507
        for key, val in custom.items():
508
            xml_key = SubElement(_custom, key)
509
            xml_key.text = val
510
511
        return tostring(_custom).decode('utf-8')
512
513
    @staticmethod
514
    def get_severities_vt_as_xml_str(vt_id, severities):
515
        """ Return an xml element with severities as string.
516
        Arguments:
517
            vt_id (str): VT OID. Only used for logging in error case.
518
            severities (dict): Dictionary with the severities.
519
        Return:
520
            string: xml element as string.
521
        """
522
        _severities = Element('severities')
523
        _severity = SubElement(_severities, 'severity')
524
        if 'severity_base_vector' in severities:
525
            _severity.text = severities.get('severity_base_vector')
526
        if 'severity_origin' in severities:
527
            _severity.set('origin', severities.get('severity_origin'))
528
        if 'severity_type' in severities:
529
            _severity.set('type', severities.get('severity_type'))
530
531
        return tostring(_severities).decode('utf-8')
532
533
    @staticmethod
534
    def get_params_vt_as_xml_str(vt_id, vt_params):
535
        """ Return an xml element with params formatted as string.
536
        Arguments:
537
            vt_id (str): VT OID. Only used for logging in error case.
538
            vt_params (dict): Dictionary with the VT parameters.
539
        Return:
540
            string: xml element as string.
541
        """
542
        vt_params_xml = Element('params')
543
        for _pref_id, prefs in vt_params.items():
544
            vt_param = Element('param')
545
            vt_param.set('type', prefs['type'])
546
            vt_param.set('id', _pref_id)
547
            xml_name = SubElement(vt_param, 'name')
548
            xml_name.text = prefs['name']
549
            if prefs['default']:
550
                xml_def = SubElement(vt_param, 'default')
551
                xml_def.text = prefs['default']
552
            vt_params_xml.append(vt_param)
553
554
        return tostring(vt_params_xml).decode('utf-8')
555
556
    @staticmethod
557
    def get_refs_vt_as_xml_str(vt_id, vt_refs):
558
        """ Return an xml element with references formatted as string.
559
        Arguments:
560
            vt_id (str): VT OID. Only used for logging in error case.
561
            vt_refs (dict): Dictionary with the VT references.
562
        Return:
563
            string: xml element as string.
564
        """
565
        vt_refs_xml = Element('refs')
566
        for ref_type, ref_values in vt_refs.items():
567
            for value in ref_values:
568
                vt_ref = Element('ref')
569
                if ref_type == "xref" and value:
570
                    for xref in value.split(', '):
571
                        try:
572
                            _type, _id = xref.split(':', 1)
573
                        except ValueError:
574
                            logger.error(
575
                                'Not possible to parse xref %s for vt %s',
576
                                xref,
577
                                vt_id,
578
                            )
579
                            continue
580
                        vt_ref.set('type', _type.lower())
581
                        vt_ref.set('id', _id)
582
                elif value:
583
                    vt_ref.set('type', ref_type.lower())
584
                    vt_ref.set('id', value)
585
                else:
586
                    continue
587
                vt_refs_xml.append(vt_ref)
588
589
        return tostring(vt_refs_xml).decode('utf-8')
590
591
    @staticmethod
592
    def get_dependencies_vt_as_xml_str(
593
        vt_id, dep_list
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
594
    ):  # pylint: disable=arguments-differ
595
        """ Return  an xml element with dependencies as string.
596
        Arguments:
597
            vt_id (str): VT OID. Only used for logging in error case.
598
            dep_list (List): List with the VT dependencies.
599
        Return:
600
            string: xml element as string.
601
        """
602
        vt_deps_xml = Element('dependencies')
603
        for dep in dep_list:
604
            _vt_dep = Element('dependency')
605
            try:
606
                _vt_dep.set('vt_id', dep)
607
            except TypeError:
608
                logger.error(
609
                    'Not possible to add dependency %s for vt %s', dep, vt_id
610
                )
611
                continue
612
            vt_deps_xml.append(_vt_dep)
613
614
        return tostring(vt_deps_xml).decode('utf-8')
615
616
    @staticmethod
617
    def get_creation_time_vt_as_xml_str(
618
        vt_id, creation_time
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
619
    ):  # pylint: disable=arguments-differ
620
        """ Return creation time as string.
621
        Arguments:
622
            vt_id (str): VT OID. Only used for logging in error case.
623
            creation_time (str): String with the VT creation time.
624
        Return:
625
            string: xml element as string.
626
        """
627
        _time = Element('creation_time')
628
        _time.text = creation_time
629
        return tostring(_time).decode('utf-8')
630
631
    @staticmethod
632
    def get_modification_time_vt_as_xml_str(
633
        vt_id, modification_time
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
634
    ):  # pylint: disable=arguments-differ
635
        """ Return modification time as string.
636
        Arguments:
637
            vt_id (str): VT OID. Only used for logging in error case.
638
            modification_time (str): String with the VT modification time.
639
        Return:
640
            string: xml element as string.
641
        """
642
        _time = Element('modification_time')
643
        _time.text = modification_time
644
        return tostring(_time).decode('utf-8')
645
646
    @staticmethod
647
    def get_summary_vt_as_xml_str(vt_id, summary):
648
        """ Return summary as string.
649
        Arguments:
650
            vt_id (str): VT OID. Only used for logging in error case.
651
            summary (str): String with a VT summary.
652
        Return:
653
            string: xml element as string.
654
        """
655
        _summary = Element('summary')
656
        _summary.text = summary
657
        return tostring(_summary).decode('utf-8')
658
659
    @staticmethod
660
    def get_impact_vt_as_xml_str(vt_id, impact):
661
        """ Return impact as string.
662
663
        Arguments:
664
            vt_id (str): VT OID. Only used for logging in error case.
665
            impact (str): String which explain the vulneravility impact.
666
        Return:
667
            string: xml element as string.
668
        """
669
        _impact = Element('impact')
670
        _impact.text = impact
671
        return tostring(_impact).decode('utf-8')
672
673
    @staticmethod
674
    def get_affected_vt_as_xml_str(vt_id, affected):
675
        """ Return affected as string.
676
        Arguments:
677
            vt_id (str): VT OID. Only used for logging in error case.
678
            affected (str): String which explain what is affected.
679
        Return:
680
            string: xml element as string.
681
        """
682
        _affected = Element('affected')
683
        _affected.text = affected
684
        return tostring(_affected).decode('utf-8')
685
686
    @staticmethod
687
    def get_insight_vt_as_xml_str(vt_id, insight):
688
        """ Return insight as string.
689
        Arguments:
690
            vt_id (str): VT OID. Only used for logging in error case.
691
            insight (str): String giving an insight of the vulnerability.
692
        Return:
693
            string: xml element as string.
694
        """
695
        _insight = Element('insight')
696
        _insight.text = insight
697
        return tostring(_insight).decode('utf-8')
698
699
    @staticmethod
700
    def get_solution_vt_as_xml_str(vt_id, solution, solution_type=None):
701
        """ Return solution as string.
702
        Arguments:
703
            vt_id (str): VT OID. Only used for logging in error case.
704
            solution (str): String giving a possible solution.
705
            solution_type (str): A solution type
706
        Return:
707
            string: xml element as string.
708
        """
709
        _solution = Element('solution')
710
        _solution.text = solution
711
        if solution_type:
712
            _solution.set('type', solution_type)
713
        return tostring(_solution).decode('utf-8')
714
715
    @staticmethod
716
    def get_detection_vt_as_xml_str(
717
        vt_id, vuldetect=None, qod_type=None, qod=None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
718
    ):  # pylint: disable=arguments-differ
719
        """ Return detection as string.
720
        Arguments:
721
            vt_id (str): VT OID. Only used for logging in error case.
722
            vuldetect (str, opt): String which explain how the vulnerability
723
                was detected.
724
            qod_type (str, opt): qod type.
725
            qod (str, opt): qod value.
726
        Return:
727
            string: xml element as string.
728
        """
729
        _detection = Element('detection')
730
        if vuldetect:
731
            _detection.text = vuldetect
732
        if qod_type:
733
            _detection.set('qod_type', qod_type)
734
        elif qod:
735
            _detection.set('qod', qod)
736
737
        return tostring(_detection).decode('utf-8')
738
739
    @property
740
    def sudo_available(self):
741
        """ Checks that sudo is available """
742
        if self._sudo_available is not None:
743
            return self._sudo_available
744
        try:
745
            subprocess.check_call(
746
                ['sudo', '-n', 'openvas', '-s'], stdout=subprocess.PIPE
747
            )
748
            self._sudo_available = True
749
        except subprocess.CalledProcessError as e:
750
            logger.debug(
751
                'It was not possible to call openvas with sudo. '
752
                'The scanner will run as non-root user. Reason %s',
753
                e,
754
            )
755
            self._sudo_available = False
756
757
        return self._sudo_available
758
759
    def check(self):
760
        """ Checks that openvas command line tool is found and
761
        is executable. """
762
        try:
763
            result = subprocess.check_output(
764
                ['openvas', '-V'], stderr=subprocess.STDOUT
765
            )
766
            result = result.decode('ascii')
767
        except OSError:
768
            # The command is not available
769
            return False
770
771
        if result is None:
772
            return False
773
774
        version = result.split('\n')
775
        if version[0].find('OpenVAS') < 0:
776
            return False
777
778
        self.parse_param()
779
        self.scanner_info['version'] = version[0]
780
781
        return True
782
783
    def update_progress(self, scan_id, target, current_host, msg):
784
        """ Calculate percentage and update the scan status of a host
785
        for the progress bar.
786
        Arguments:
787
            scan_id (uuid): Scan ID to identify the current scan process.
788
            target (str): Target to be updated with the calculated
789
                          scan progress.
790
            msg (str): String with launched and total plugins.
791
        """
792
        try:
793
            launched, total = msg.split('/')
794
        except ValueError:
795
            return
796
        if float(total) == 0:
797
            return
798
        elif float(total) == -1:
799
            host_prog = 100
800
        else:
801
            host_prog = (float(launched) / float(total)) * 100
802
        self.set_scan_target_progress(scan_id, target, current_host, host_prog)
803
804
    def get_openvas_status(self, scan_id, target, current_host):
805
        """ Get all status entries from redis kb.
806
        Arguments:
807
            scan_id (uuid): Scan ID to identify the current scan.
808
            target (str): Target progress to be updated.
809
        """
810
        res = self.openvas_db.get_status()
811
        while res:
812
            self.update_progress(scan_id, target, current_host, res)
813
            res = self.openvas_db.get_status()
814
815
    def get_severity_score(self, oid):
816
        """ Return the severity score for the given oid.
817
        Arguments:
818
            oid (str): VT OID from which to get the severity vector
819
        Returns:
820
            The calculated cvss base value. None if there is no severity
821
            vector or severity type is not cvss base version 2.
822
        """
823
        severity_type = self.vts[oid]['severities'].get('severity_type')
824
        severity_vector = self.vts[oid]['severities'].get(
825
            'severity_base_vector'
826
        )
827
828
        if severity_type == "cvss_base_v2" and severity_vector:
829
            return CVSS.cvss_base_v2_value(severity_vector)
830
831
        return None
832
833
    def get_openvas_result(self, scan_id, current_host):
834
        """ Get all result entries from redis kb. """
835
        res = self.openvas_db.get_result()
836
        while res:
837
            msg = res.split('|||')
838
            roid = msg[3]
839
            rqod = ''
840
            rname = ''
841
            rhostname = msg[1] if msg[1] else ''
842
            host_is_dead = "Host dead" in msg[4]
843
844
            if not host_is_dead:
845
                if self.vts[roid].get('qod_type'):
846
                    qod_t = self.vts[roid].get('qod_type')
847
                    rqod = self.nvti.QOD_TYPES[qod_t]
848
                elif self.vts[roid].get('qod'):
849
                    rqod = self.vts[roid].get('qod')
850
851
                rname = self.vts[roid].get('name')
852
853
            if msg[0] == 'ERRMSG':
854
                self.add_scan_error(
855
                    scan_id,
856
                    host=current_host,
857
                    hostname=rhostname,
858
                    name=rname,
859
                    value=msg[4],
860
                    port=msg[2],
861
                )
862
863
            if msg[0] == 'LOG':
864
                self.add_scan_log(
865
                    scan_id,
866
                    host=current_host,
867
                    hostname=rhostname,
868
                    name=rname,
869
                    value=msg[4],
870
                    port=msg[2],
871
                    qod=rqod,
872
                    test_id=roid,
873
                )
874
875
            if msg[0] == 'HOST_DETAIL':
876
                self.add_scan_host_detail(
877
                    scan_id,
878
                    host=current_host,
879
                    hostname=rhostname,
880
                    name=rname,
881
                    value=msg[4],
882
                )
883
884
            if msg[0] == 'ALARM':
885
                rseverity = self.get_severity_score(roid)
886
                self.add_scan_alarm(
887
                    scan_id,
888
                    host=current_host,
889
                    hostname=rhostname,
890
                    name=rname,
891
                    value=msg[4],
892
                    port=msg[2],
893
                    test_id=roid,
894
                    severity=rseverity,
895
                    qod=rqod,
896
                )
897
898
            res = self.openvas_db.get_result()
899
900
    def get_openvas_timestamp_scan_host(self, scan_id, target):
901
        """ Get start and end timestamp of a host scan from redis kb. """
902
        timestamp = self.openvas_db.get_host_scan_scan_end_time()
903
        if timestamp:
904
            self.add_scan_log(
905
                scan_id, host=target, name='HOST_END', value=timestamp
906
            )
907
            return
908
        timestamp = self.openvas_db.get_host_scan_scan_start_time()
909
        if timestamp:
910
            self.add_scan_log(
911
                scan_id, host=target, name='HOST_START', value=timestamp
912
            )
913
            return
914
915
    def scan_is_finished(self, scan_id):
916
        """ Check if the scan has finished. """
917
        status = self.openvas_db.get_single_item('internal/%s' % scan_id)
918
        return status == 'finished'
919
920
    def scan_is_stopped(self, scan_id):
921
        """ Check if the parent process has received the stop_scan order.
922
        @in scan_id: ID to identify the scan to be stopped.
923
        @return 1 if yes, None in other case.
924
        """
925
        ctx = self.openvas_db.kb_connect(dbnum=self.main_kbindex)
926
        self.openvas_db.set_redisctx(ctx)
927
        status = self.openvas_db.get_single_item('internal/%s' % scan_id)
928
        return status == 'stop_all'
929
930
    def stop_scan_cleanup(
931
        self, global_scan_id
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
932
    ):  # pylint: disable=arguments-differ
933
        """ Set a key in redis to indicate the wrapper is stopped.
934
        It is done through redis because it is a new multiprocess
935
        instance and it is not possible to reach the variables
936
        of the grandchild process. Send SIGUSR2 to openvas to stop
937
        each running scan."""
938
        ctx = self.openvas_db.kb_connect()
939
        for current_kbi in range(0, self.openvas_db.max_dbindex):
940
            self.openvas_db.select_kb(ctx, str(current_kbi), set_global=True)
941
            scan_id = self.openvas_db.get_single_item(
942
                'internal/%s/globalscanid' % global_scan_id
943
            )
944
            if scan_id:
945
                self.openvas_db.set_single_item(
946
                    'internal/%s' % scan_id, ['stop_all']
947
                )
948
                ovas_pid = self.openvas_db.get_single_item('internal/ovas_pid')
949
                parent = None
950
                try:
951
                    parent = psutil.Process(int(ovas_pid))
952
                except psutil.NoSuchProcess:
953
                    logger.debug(
954
                        'Process with pid %s already stopped', ovas_pid
955
                    )
956
                except TypeError:
957
                    logger.debug(
958
                        'Scan with ID %s never started and stopped '
959
                        'unexpectedly',
960
                        scan_id,
961
                    )
962
963
                if parent:
964
                    cmd = ['openvas', '--scan-stop', scan_id]
965
                    if self.sudo_available:
966
                        cmd = ['sudo', '-n'] + cmd
967
968
                    try:
969
                        subprocess.Popen(cmd, shell=False)
970
                    except OSError as e:
971
                        # the command is not available
972
                        logger.debug(
973
                            'Not possible to Stopping process: %s.' 'Reason %s',
974
                            parent,
975
                            e,
976
                        )
977
                        return False
978
979
                    logger.debug('Stopping process: %s', parent)
980
                self.openvas_db.release_db(current_kbi)
981
982
    def get_vts_in_groups(self, filters):
983
        """ Return a list of vts which match with the given filter.
984
985
        @input filters A list of filters. Each filter has key, operator and
986
                       a value. They are separated by a space.
987
                       Supported keys: family
988
        @return Return a list of vts which match with the given filter.
989
        """
990
        vts_list = list()
991
        families = dict()
992
        for oid in self.vts:
993
            family = self.vts[oid]['custom'].get('family')
994
            if family not in families:
995
                families[family] = list()
996
            families[family].append(oid)
997
998
        for elem in filters:
999
            key, value = elem.split('=')
1000
            if key == 'family' and value in families:
1001
                vts_list.extend(families[value])
1002
        return vts_list
1003
1004
    def get_vt_param_type(self, vtid, vt_param_id):
1005
        """ Return the type of the vt parameter from the vts dictionary. """
1006
1007
        vt_params_list = self.vts[vtid].get("vt_params")
1008
        if vt_params_list.get(vt_param_id):
1009
            return vt_params_list[vt_param_id]["type"]
1010
        return None
1011
1012
    def get_vt_param_name(self, vtid, vt_param_id):
1013
        """ Return the type of the vt parameter from the vts dictionary. """
1014
1015
        vt_params_list = self.vts[vtid].get("vt_params")
1016
        if vt_params_list.get(vt_param_id):
1017
            return vt_params_list[vt_param_id]["name"]
1018
        return None
1019
1020
    @staticmethod
1021
    def check_param_type(vt_param_value, param_type):
1022
        """ Check if the value of a vt parameter matches with
1023
        the type founded.
1024
        """
1025
        if param_type in [
1026
            'entry',
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1027
            'file',
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1028
            'password',
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1029
            'radio',
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1030
            'sshlogin',
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1031
        ] and isinstance(vt_param_value, str):
1032
            return None
1033
        elif param_type == 'checkbox' and (
1034
            vt_param_value == '0' or vt_param_value == '1'
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1035
        ):
1036
            return None
1037
        elif param_type == 'integer':
1038
            try:
1039
                int(vt_param_value)
1040
            except ValueError:
1041
                return 1
1042
            return None
1043
1044
        return 1
1045
1046
    def process_vts(self, vts):
1047
        """ Add single VTs and their parameters. """
1048
        vts_list = []
1049
        vts_params = []
1050
        vtgroups = vts.pop('vt_groups')
1051
1052
        if vtgroups:
1053
            vts_list = self.get_vts_in_groups(vtgroups)
1054
1055
        for vtid, vt_params in vts.items():
1056
            vts_list.append(vtid)
1057
            for vt_param_id, vt_param_value in vt_params.items():
1058
                param_type = self.get_vt_param_type(vtid, vt_param_id)
1059
                param_name = self.get_vt_param_name(vtid, vt_param_id)
1060
                if not param_type or not param_name:
1061
                    logger.debug(
1062
                        'The vt parameter %s for %s could not be loaded.',
1063
                        vt_param_id,
1064
                        vtid,
1065
                    )
1066
                    continue
1067
                if vt_param_id == '0':
1068
                    type_aux = 'integer'
1069
                else:
1070
                    type_aux = param_type
1071
                if self.check_param_type(vt_param_value, type_aux):
1072
                    logger.debug(
1073
                        'Expected %s type for parameter value %s',
1074
                        type_aux,
1075
                        str(vt_param_value),
1076
                    )
1077
                    continue
1078
                if type_aux == 'checkbox':
1079
                    vt_param_value = _from_bool_to_str(int(vt_param_value))
1080
                param = [
1081
                    "{0}:{1}:{2}:{3}".format(
1082
                        vtid, vt_param_id, param_type, param_name
1083
                    ),
1084
                    str(vt_param_value),
1085
                ]
1086
                vts_params.append(param)
1087
        return vts_list, vts_params
1088
1089
    @staticmethod
1090
    def build_credentials_as_prefs(credentials):
1091
        """ Parse the credential dictionary.
1092
        @param credentials: Dictionary with the credentials.
1093
1094
        @return A list with the credentials in string format to be
1095
                added to the redis KB.
1096
        """
1097
        cred_prefs_list = []
1098
        for credential in credentials.items():
1099
            service = credential[0]
1100
            cred_params = credentials.get(service)
1101
            cred_type = cred_params.get('type', '')
1102
            username = cred_params.get('username', '')
1103
            password = cred_params.get('password', '')
1104
1105
            if service == 'ssh':
1106
                port = cred_params.get('port', '')
1107
                cred_prefs_list.append('auth_port_ssh|||' + '{0}'.format(port))
1108
                cred_prefs_list.append(
1109
                    OID_SSH_AUTH
1110
                    + ':1:'
1111
                    + 'entry:SSH login '
1112
                    + 'name:|||{0}'.format(username)
1113
                )
1114
                if cred_type == 'up':
1115
                    cred_prefs_list.append(
1116
                        OID_SSH_AUTH
1117
                        + ':3:'
1118
                        + 'password:SSH password '
1119
                        + '(unsafe!):|||{0}'.format(password)
1120
                    )
1121
                else:
1122
                    private = cred_params.get('private', '')
1123
                    cred_prefs_list.append(
1124
                        OID_SSH_AUTH
1125
                        + ':2:'
1126
                        + 'password:SSH key passphrase:|||'
1127
                        + '{0}'.format(password)
1128
                    )
1129
                    cred_prefs_list.append(
1130
                        OID_SSH_AUTH
1131
                        + ':4:'
1132
                        + 'file:SSH private key:|||'
1133
                        + '{0}'.format(private)
1134
                    )
1135
            if service == 'smb':
1136
                cred_prefs_list.append(
1137
                    OID_SMB_AUTH
1138
                    + ':1:entry'
1139
                    + ':SMB login:|||{0}'.format(username)
1140
                )
1141
                cred_prefs_list.append(
1142
                    OID_SMB_AUTH
1143
                    + ':2:'
1144
                    + 'password:SMB password:|||'
1145
                    + '{0}'.format(password)
1146
                )
1147
            if service == 'esxi':
1148
                cred_prefs_list.append(
1149
                    OID_ESXI_AUTH
1150
                    + ':1:entry:'
1151
                    + 'ESXi login name:|||'
1152
                    + '{0}'.format(username)
1153
                )
1154
                cred_prefs_list.append(
1155
                    OID_ESXI_AUTH
1156
                    + ':2:'
1157
                    + 'password:ESXi login password:|||'
1158
                    + '{0}'.format(password)
1159
                )
1160
1161
            if service == 'snmp':
1162
                community = cred_params.get('community', '')
1163
                auth_algorithm = cred_params.get('auth_algorithm', '')
1164
                privacy_password = cred_params.get('privacy_password', '')
1165
                privacy_algorithm = cred_params.get('privacy_algorithm', '')
1166
1167
                cred_prefs_list.append(
1168
                    OID_SNMP_AUTH
1169
                    + ':1:'
1170
                    + 'password:SNMP Community:'
1171
                    + '{0}'.format(community)
1172
                )
1173
                cred_prefs_list.append(
1174
                    OID_SNMP_AUTH
1175
                    + ':2:'
1176
                    + 'entry:SNMPv3 Username:'
1177
                    + '{0}'.format(username)
1178
                )
1179
                cred_prefs_list.append(
1180
                    OID_SNMP_AUTH + ':3:'
1181
                    'password:SNMPv3 Password:' + '{0}'.format(password)
1182
                )
1183
                cred_prefs_list.append(
1184
                    OID_SNMP_AUTH
1185
                    + ':4:'
1186
                    + 'radio:SNMPv3 Authentication '
1187
                    + 'Algorithm:{0}'.format(auth_algorithm)
1188
                )
1189
                cred_prefs_list.append(
1190
                    OID_SNMP_AUTH
1191
                    + ':5:'
1192
                    + 'password:SNMPv3 Privacy Password:'
1193
                    + '{0}'.format(privacy_password)
1194
                )
1195
                cred_prefs_list.append(
1196
                    OID_SNMP_AUTH
1197
                    + ':6:'
1198
                    + 'radio:SNMPv3 Privacy Algorithm:'
1199
                    + '{0}'.format(privacy_algorithm)
1200
                )
1201
1202
        return cred_prefs_list
1203
1204
    def exec_scan(self, scan_id, target):
1205
        """ Starts the OpenVAS scanner for scan_id scan. """
1206
        if self.pending_feed:
1207
            logger.info(
1208
                '%s: There is a pending feed update. '
1209
                'The scan can not be started.',
1210
                scan_id,
1211
            )
1212
            self.add_scan_error(
1213
                scan_id,
1214
                name='',
1215
                host=target,
1216
                value=(
1217
                    'It was not possible to start the scan,'
1218
                    'because a pending feed update. Please try later'
1219
                ),
1220
            )
1221
            return 2
1222
1223
        ports = self.get_scan_ports(scan_id, target)
1224
        if not ports:
1225
            self.add_scan_error(
1226
                scan_id, name='', host=target, value='No port list defined.'
1227
            )
1228
            return 2
1229
1230
        # Get scan options
1231
        options = self.get_scan_options(scan_id)
1232
        prefs_val = []
1233
        ctx = self.openvas_db.kb_new()
1234
        self.openvas_db.set_redisctx(ctx)
1235
        self.main_kbindex = self.openvas_db.db_index
1236
1237
        # To avoid interference between scan process during a parallel scanning
1238
        # new uuid is used internally for each scan.
1239
        openvas_scan_id = str(uuid.uuid4())
1240
        self.openvas_db.add_single_item(
1241
            'internal/%s' % openvas_scan_id, ['new']
1242
        )
1243
        self.openvas_db.add_single_item(
1244
            'internal/%s/globalscanid' % scan_id, [openvas_scan_id]
1245
        )
1246
1247
        exclude_hosts = self.get_scan_exclude_hosts(scan_id, target)
1248
        if exclude_hosts:
1249
            options['exclude_hosts'] = exclude_hosts
1250
1251
        # Get unfinished hosts, in case it is a resumed scan. And added
1252
        # into exclude_hosts scan preference. Set progress for the finished ones
1253
        # to 100%.
1254
        finished_hosts = self.get_scan_finished_hosts(scan_id)
1255
        if finished_hosts:
1256
            if exclude_hosts:
1257
                finished_hosts_str = ','.join(finished_hosts)
1258
                exclude_hosts = exclude_hosts + ',' + finished_hosts_str
1259
                options['exclude_hosts'] = exclude_hosts
1260
            else:
1261
                options['exclude_hosts'] = ','.join(finished_hosts)
1262
1263
        # Set scan preferences
1264
        for key, value in options.items():
1265
            item_type = ''
1266
            if key in OSPD_PARAMS:
1267
                item_type = OSPD_PARAMS[key].get('type')
1268
            if item_type == 'boolean':
1269
                val = _from_bool_to_str(value)
1270
            else:
1271
                val = str(value)
1272
            prefs_val.append(key + "|||" + val)
1273
        self.openvas_db.add_single_item(
1274
            'internal/%s/scanprefs' % openvas_scan_id, prefs_val
1275
        )
1276
1277
        # Store main_kbindex as global preference
1278
        ov_maindbid = 'ov_maindbid|||%d' % self.main_kbindex
1279
        self.openvas_db.add_single_item(
1280
            'internal/%s/scanprefs' % openvas_scan_id, [ov_maindbid]
1281
        )
1282
1283
        # Set target
1284
        target_aux = 'TARGET|||%s' % target
1285
        self.openvas_db.add_single_item(
1286
            'internal/%s/scanprefs' % openvas_scan_id, [target_aux]
1287
        )
1288
        # Set port range
1289
        port_range = 'port_range|||%s' % ports
1290
        self.openvas_db.add_single_item(
1291
            'internal/%s/scanprefs' % openvas_scan_id, [port_range]
1292
        )
1293
1294
        # Set credentials
1295
        credentials = self.get_scan_credentials(scan_id, target)
1296
        if credentials:
1297
            cred_prefs = self.build_credentials_as_prefs(credentials)
1298
            self.openvas_db.add_single_item(
1299
                'internal/%s/scanprefs' % openvas_scan_id, cred_prefs
1300
            )
1301
1302
        # Set plugins to run
1303
        nvts = self.get_scan_vts(scan_id)
1304
        if nvts != '':
1305
            nvts_list, nvts_params = self.process_vts(nvts)
1306
            # Add nvts list
1307
            separ = ';'
1308
            plugin_list = 'plugin_set|||%s' % separ.join(nvts_list)
1309
            self.openvas_db.add_single_item(
1310
                'internal/%s/scanprefs' % openvas_scan_id, [plugin_list]
1311
            )
1312
            # Add nvts parameters
1313
            for elem in nvts_params:
1314
                item = '%s|||%s' % (elem[0], elem[1])
1315
                self.openvas_db.add_single_item(
1316
                    'internal/%s/scanprefs' % openvas_scan_id, [item]
1317
                )
1318
        else:
1319
            self.openvas_db.release_db(self.main_kbindex)
1320
            self.add_scan_error(
1321
                scan_id, name='', host=target, value='No VTS to run.'
1322
            )
1323
            return 2
1324
1325
        cmd = ['openvas', '--scan-start', openvas_scan_id]
1326
        if self.sudo_available:
1327
            cmd = ['sudo', '-n'] + cmd
1328
1329
        if self._niceness is not None:
1330
            cmd = ['nice', '-n', self._niceness] + cmd
1331
1332
        logger.debug("Running scan with niceness %s", self._niceness)
1333
        try:
1334
            result = subprocess.Popen(cmd, shell=False)
1335
        except OSError:
1336
            # the command is not available
1337
            return False
1338
1339
        ovas_pid = result.pid
1340
        logger.debug('pid = %s', ovas_pid)
1341
        self.openvas_db.add_single_item('internal/ovas_pid', [ovas_pid])
1342
1343
        # Wait until the scanner starts and loads all the preferences.
1344
        while (
1345
            self.openvas_db.get_single_item('internal/' + openvas_scan_id)
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1346
            == 'new'
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
1347
        ):
1348
            res = result.poll()
1349
            if res and res < 0:
1350
                self.stop_scan_cleanup(scan_id)
1351
                msg = (
1352
                    'It was not possible run the task %s, since openvas ended '
1353
                    'unexpectedly with errors during launching.' % scan_id
1354
                )
1355
                logger.error(msg)
1356
                return 1
1357
            time.sleep(1)
1358
1359
        no_id_found = False
1360
        while True:
1361
            time.sleep(3)
1362
            # Check if the client stopped the whole scan
1363
            if self.scan_is_stopped(openvas_scan_id):
1364
                return 1
1365
1366
            ctx = self.openvas_db.kb_connect(self.main_kbindex)
1367
            self.openvas_db.set_redisctx(ctx)
1368
            dbs = self.openvas_db.get_list_item('internal/dbindex')
1369
            for i in list(dbs):
1370
                if i == self.main_kbindex:
1371
                    continue
1372
                self.openvas_db.select_kb(ctx, str(i), set_global=True)
1373
                id_aux = self.openvas_db.get_single_item('internal/scan_id')
1374
                if not id_aux:
1375
                    continue
1376
                if id_aux == openvas_scan_id:
1377
                    no_id_found = False
1378
                    current_host = self.openvas_db.get_host_ip()
1379
                    self.get_openvas_result(scan_id, current_host)
1380
                    self.get_openvas_status(scan_id, target, current_host)
1381
                    self.get_openvas_timestamp_scan_host(scan_id, current_host)
1382
                    if self.scan_is_finished(openvas_scan_id):
1383
                        self.set_scan_host_finished(
1384
                            scan_id, target, current_host
1385
                        )
1386
                        self.get_openvas_status(scan_id, target, current_host)
1387
                        self.get_openvas_timestamp_scan_host(
1388
                            scan_id, current_host
1389
                        )
1390
                        self.openvas_db.select_kb(
1391
                            ctx, str(self.main_kbindex), set_global=False
1392
                        )
1393
                        self.openvas_db.remove_list_item('internal/dbindex', i)
1394
                        self.openvas_db.release_db(i)
1395
1396
            # Scan end. No kb in use for this scan id
1397
            if no_id_found:
1398
                break
1399
            no_id_found = True
1400
1401
        # Delete keys from KB related to this scan task.
1402
        self.openvas_db.release_db(self.main_kbindex)
1403
        return 1
1404
1405
1406
def main():
1407
    """ OSP openvas main function. """
1408
    daemon_main('OSPD - openvas', OSPDopenvas)
1409
1410
1411
if __name__ == '__main__':
1412
    main()
1413