Completed
Push — master ( 5cbc02...597abf )
by Juan José
16s
created

ospd_openvas.wrapper.OSPDopenvas.parse_param()   B

Complexity

Conditions 8

Size

Total Lines 22
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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