Passed
Pull Request — master (#21)
by Juan José
01:24
created

ospd_openvas.wrapper   F

Complexity

Total Complexity 76

Size/Duplication

Total Lines 674
Duplicated Lines 69.29 %

Importance

Changes 0
Metric Value
wmc 76
eloc 488
dl 467
loc 674
rs 2.32
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A OSPDopenvas.get_custom_vt_as_xml_str() 4 4 1
A OSPDopenvas.check() 22 22 4
A OSPDopenvas.redis_nvticache_init() 8 8 2
A OSPDopenvas.__init__() 23 23 4
A OSPDopenvas.get_params_vt_as_xml_str() 4 4 1
A OSPDopenvas.update_progress() 12 12 2
B OSPDopenvas.parse_param() 19 19 6
A OSPDopenvas.get_openvas_status() 6 6 2
A OSPDopenvas.load_vts() 16 16 4
C OSPDopenvas.build_credentials_as_prefs() 73 73 7
A OSPDopenvas.get_vts_in_groups() 18 18 5
A OSPDopenvas.process_vts() 19 19 4
A OSPDopenvas.scan_is_stopped() 9 9 1
A OSPDopenvas.get_openvas_timestamp_scan_host() 12 12 3
F OSPDopenvas.exec_scan() 146 146 19
B OSPDopenvas.get_openvas_result() 29 29 6
A OSPDopenvas.scan_is_finished() 4 4 1
A OSPDopenvas.stop_scan() 21 21 3

1 Function

Rating   Name   Duplication   Size   Complexity  
A main() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ospd_openvas.wrapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
# Description:
3
# Setup for the OSP OpenVAS Server
4
#
5
# Authors:
6
# Juan José Nicola <[email protected]>
7
#
8
# Copyright:
9
# Copyright (C) 2018 Greenbone Networks GmbH
10
#
11
# This program is free software; you can redistribute it and/or
12
# modify it under the terms of the GNU General Public License
13
# as published by the Free Software Foundation; either version 2
14
# of the License, or (at your option) any later version.
15
#
16
# This program is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
# GNU General Public License for more details.
20
#
21
# You should have received a copy of the GNU General Public License
22
# along with this program; if not, write to the Free Software
23
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25
import subprocess
26
import time
27
import signal
28
import psutil
29
import uuid
0 ignored issues
show
introduced by
standard import "import uuid" should be placed before "import psutil"
Loading history...
30
31
from ospd.ospd import OSPDaemon, logger
32
from ospd.misc import main as daemon_main
33
from ospd.misc import target_str_to_list
34
from ospd_openvas import __version__
35
36
import ospd_openvas.nvticache as nvti
37
import ospd_openvas.openvas_db as openvas_db
38
39
OSPD_DESC = """
40
This scanner runs 'OpenVAS Scanner' to scan the target hosts.
41
42
OpenVAS (Open Vulnerability Assessment System) is a powerful scanner
43
for vulnerabilities in IT infrastrucutres. The capabilities include
44
unauthzenticated scanning as well as authneticated scanning for
45
various types of systems and services.
46
47
For more details about OpenVAS see the OpenVAS homepage:
48
http://www.openvas.org/
49
50
The current version of ospd-openvas is a simple frame, which sends
51
the server parameters to the Greenbone Vulnerability Manager (GVM) and checks
52
the existence of OpenVAS Scanner binary. But it can not run scans yet.
53
"""
54
55
MAIN_KBINDEX = None
56
57
OSPD_PARAMS = {
58
    'auto_enable_dependencies': {
59
        'type': 'boolean',
60
        'name': 'auto_enable_dependencies',
61
        'default': 1,
62
        'mandatory': 1,
63
        'description': 'Automatically enable the plugins that are depended on',
64
    },
65
    'cgi_path': {
66
        'type': 'string',
67
        'name': 'cgi_path',
68
        'default': '/cgi-bin:/scripts',
69
        'mandatory': 1,
70
        'description': 'Look for default CGIs in /cgi-bin and /scripts',
71
    },
72
    'checks_read_timeout': {
73
        'type': 'integer',
74
        'name': 'checks_read_timeout',
75
        'default': 5,
76
        'mandatory': 1,
77
        'description': ('Number  of seconds that the security checks will ' +
78
                        'wait for when doing a recv()'),
79
    },
80
    'drop_privileges': {
81
        'type': 'boolean',
82
        'name': 'drop_privileges',
83
        'default': 0,
84
        'mandatory': 1,
85
        'description': '',
86
    },
87
    'network_scan': {
88
        'type': 'boolean',
89
        'name': 'network_scan',
90
        'default': 0,
91
        'mandatory': 1,
92
        'description': '',
93
    },
94
    'non_simult_ports': {
95
        'type': 'string',
96
        'name': 'non_simult_ports',
97
        'default': '139, 445, 3389, Services/irc',
98
        'mandatory': 1,
99
        'description': ('Prevent to make two connections on the same given ' +
100
                        'ports at the same time.'),
101
    },
102
    'open_sock_max_attempts': {
103
        'type': 'integer',
104
        'name': 'open_sock_max_attempts',
105
        'default': 5,
106
        'mandatory': 0,
107
        'description': ('Number of unsuccessful retries to open the socket ' +
108
                        'before to set the port as closed.'),
109
    },
110
    'timeout_retry': {
111
        'type': 'integer',
112
        'name': 'timeout_retry',
113
        'default': 5,
114
        'mandatory': 0,
115
        'description': ('Number of retries when a socket connection attempt ' +
116
                        'timesout.'),
117
    },
118
    'optimize_test': {
119
        'type': 'integer',
120
        'name': 'optimize_test',
121
        'default': 5,
122
        'mandatory': 0,
123
        'description': ('By default, openvassd does not trust the remote ' +
124
                        'host banners.'),
125
    },
126
    'plugins_timeout': {
127
        'type': 'integer',
128
        'name': 'plugins_timeout',
129
        'default': 5,
130
        'mandatory': 0,
131
        'description': 'This is the maximum lifetime, in seconds of a plugin.',
132
    },
133
    'report_host_details': {
134
        'type': 'boolean',
135
        'name': 'report_host_details',
136
        'default': 1,
137
        'mandatory': 1,
138
        'description': '',
139
    },
140
    'safe_checks': {
141
        'type': 'boolean',
142
        'name': 'safe_checks',
143
        'default': 1,
144
        'mandatory': 1,
145
        'description': ('Disable the plugins with potential to crash ' +
146
                        'the remote services'),
147
    },
148
    'scanner_plugins_timeout': {
149
        'type': 'integer',
150
        'name': 'scanner_plugins_timeout',
151
        'default': 36000,
152
        'mandatory': 1,
153
        'description': 'Like plugins_timeout, but for ACT_SCANNER plugins.',
154
    },
155
    'time_between_request': {
156
        'type': 'integer',
157
        'name': 'time_between_request',
158
        'default': 0,
159
        'mandatory': 0,
160
        'description': ('Allow to set a wait time between two actions ' +
161
                        '(open, send, close).'),
162
    },
163
    'unscanned_closed': {
164
        'type': 'boolean',
165
        'name': 'unscanned_closed',
166
        'default': 1,
167
        'mandatory': 1,
168
        'description': '',
169
    },
170
    'unscanned_closed_udp': {
171
        'type': 'boolean',
172
        'name': 'unscanned_closed_udp',
173
        'default': 1,
174
        'mandatory': 1,
175
        'description': '',
176
    },
177
    'use_mac_addr': {
178
        'type': 'boolean',
179
        'name': 'use_mac_addr',
180
        'default': 0,
181
        'mandatory': 0,
182
        'description': 'To test the local network. ' +
183
                       'Hosts will be referred to by their MAC address.',
184
    },
185
    'vhosts': {
186
        'type': 'string',
187
        'name': 'vhosts',
188
        'default': '',
189
        'mandatory': 0,
190
        'description': '',
191
    },
192
    'vhosts_ip': {
193
        'type': 'string',
194
        'name': 'vhosts_ip',
195
        'default': '',
196
        'mandatory': 0,
197
        'description': '',
198
    },
199
}
200
201
202 View Code Duplication
class OSPDopenvas(OSPDaemon):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
203
204
    """ Class for ospd-openvas daemon. """
205
206
    def __init__(self, certfile, keyfile, cafile):
207
        """ Initializes the ospd-openvas daemon's internal data. """
208
209
        super(OSPDopenvas, self).__init__(certfile=certfile, keyfile=keyfile,
210
                                          cafile=cafile)
211
        self.server_version = __version__
212
        self.scanner_info['name'] = 'openvassd'
213
        self.scanner_info['version'] = ''  # achieved during self.check()
214
        self.scanner_info['description'] = OSPD_DESC
215
        for name, param in OSPD_PARAMS.items():
216
            self.add_scanner_param(name, param)
217
218
        if openvas_db.db_init() is False:
219
            logger.error('OpenVAS Redis Error: Not possible '
220
                         'to find db_connection.')
221
            raise Exception
222
223
        ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
224
        if not ctx:
225
            self.redis_nvticache_init()
226
            ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
227
        openvas_db.set_global_redisctx(ctx)
228
        self.load_vts()
229
230
    def parse_param(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
231
        """ Set OSPD_PARAMS with the params taken from the openvas_scanner. """
232
        global OSPD_PARAMS
0 ignored issues
show
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
233
        bool_dict = {'no': 0, 'yes': 1}
234
235
        result = subprocess.check_output(['openvassd', '-s'],
236
                                         stderr=subprocess.STDOUT)
237
        result = result.decode('ascii')
238
        param_list = dict()
239
        for conf in result.split('\n'):
240
            elem = conf.split('=')
241
            if len(elem) == 2:
242
                value = str.strip(elem[1])
243
                if str.strip(elem[1]) in bool_dict:
244
                    value = bool_dict[value]
245
                param_list[str.strip(elem[0])] = value
246
        for elem in OSPD_PARAMS:
247
            if elem in param_list:
248
                OSPD_PARAMS[elem]['default'] = param_list[elem]
249
250
    def redis_nvticache_init(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
251
        """ Loads NVT's metadata into Redis DB. """
252
        try:
253
            logger.debug('Loading NVTs in Redis DB')
254
            subprocess.check_call(['openvassd', '-C'])
255
        except subprocess.CalledProcessError as err:
256
            logger.error('OpenVAS Scanner failed to load NVTs.')
257
            raise err
258
259
    def load_vts(self):
260
        """ Load the NVT's OIDs and their filename into the vts
261
        global  dictionary. """
262
        oids = nvti.get_oids()
263
        str_out = True
264
        for oid in oids:
265
            vt_id = oid[1]
266
            filename = oid[0].split(':')
267
            ret = self.add_vt(vt_id,
268
                              name=filename[1],
269
                              vt_params=nvti.get_nvt_params(vt_id, str_out),
270
                              custom=nvti.get_nvt_metadata(vt_id, str_out))
271
            if ret == -1:
272
                logger.info("Dupplicated VT with OID: {0}".format(vt_id))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
273
            if ret == -2:
274
                logger.info("{0}: Invalid OID.".format(vt_id))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
275
276
    @staticmethod
277
    def get_custom_vt_as_xml_str(custom):
278
        """ Return custom since it is already formated as string. """
279
        return custom
280
281
    @staticmethod
282
    def get_params_vt_as_xml_str(vt_params):
283
        """ Return custom since it is already formated as string. """
284
        return vt_params
285
286
    def check(self):
287
        """ Checks that openvassd command line tool is found and
288
        is executable. """
289
        try:
290
            result = subprocess.check_output(['openvassd', '-V'],
291
                                             stderr=subprocess.STDOUT)
292
            result = result.decode('ascii')
293
        except OSError:
294
            # The command is not available
295
            return False
296
297
        if result is None:
298
            return False
299
300
        version = result.split('\n')
301
        if version[0].find('OpenVAS') < 0:
302
            return False
303
304
        self.parse_param()
305
        self.scanner_info['version'] = version[0]
306
307
        return True
308
309
    def update_progress(self, scan_id, target, msg):
310
        """ Calculate porcentage and update the scan status
311
        for the progress bar. """
312
        host_progress_dict = dict()
313
        prog = str.split(msg, '/')
314
        if float(prog[1]) == 0:
315
            return
316
        host_prog = (float(prog[0]) / float(prog[1])) * 100
317
        host_progress_dict[target] = host_prog
318
        total_host = len(target_str_to_list(target))
319
        self.set_scan_target_progress(scan_id, target,
320
                                      sum(host_progress_dict.values()) / total_host)
321
322
    def get_openvas_status(self, scan_id, target):
323
        """ Get all status entries from redis kb. """
324
        res = openvas_db.get_status()
325
        while res:
326
            self.update_progress(scan_id, target, res)
327
            res = openvas_db.get_status()
328
329
    def get_openvas_result(self, scan_id):
330
        """ Get all result entries from redis kb. """
331
        res = openvas_db.get_result()
332
        ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
333
        while res:
334
            msg = res.split('|||')
335
            host_aux = openvas_db.item_get_single('internal/ip')
336
            roid = msg[3]
337
            tag = nvti.get_nvt_tag(ctx, roid)
338
            rqod = nvti.get_nvt_qod(ctx, tag)
339
            rseverity = nvti.get_nvt_severity(ctx, tag)
340
            rname = nvti.get_nvt_name(ctx, roid)
341
342
            if msg[0] == 'ERRMSG':
343
                self.add_scan_error(scan_id, host=host_aux,
344
                                    name=rname, value=msg[4], port=msg[2])
345
            if msg[0] == 'LOG':
346
                self.add_scan_log(scan_id, host=host_aux, name=rname,
347
                                  value=msg[4], port=msg[2], qod=rqod,
348
                                  test_id=roid)
349
            if msg[0] == 'HOST_DETAIL':
350
                self.add_scan_log(scan_id, host=host_aux, name=rname,
351
                                  value=msg[4])
352
            if msg[0] == 'ALARM':
353
                self.add_scan_alarm(scan_id, host=host_aux, name=rname,
354
                                    value=msg[4], port=msg[2],
355
                                    test_id=roid, severity=rseverity,
356
                                    qod=rqod)
357
            res = openvas_db.get_result()
358
359
    def get_openvas_timestamp_scan_host(self, scan_id, target):
360
        """ Get start and end timestamp of a host scan from redis kb. """
361
        timestamp = openvas_db.get_host_scan_scan_end_time()
362
        if timestamp:
363
            self.add_scan_log(scan_id, host=target, name='HOST_END',
364
                              value=timestamp)
365
            return
366
        timestamp = openvas_db.get_host_scan_scan_start_time()
367
        if timestamp:
368
            self.add_scan_log(scan_id, host=target, name='HOST_START',
369
                              value=timestamp)
370
            return
371
372
    def scan_is_finished(self, scan_id):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
373
        """ Check if the scan has finished. """
374
        status = openvas_db.item_get_single(('internal/%s' % scan_id))
375
        return status == 'finished'
376
377
    def scan_is_stopped(self, scan_id):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
378
        """ Check if the parent process has recieved the stop_scan order.
379
        @in scan_id: ID to identify the scan to be stopped.
380
        @return 1 if yes, None in oder case.
381
        """
382
        ctx = openvas_db.kb_connect(dbnum=MAIN_KBINDEX)
383
        openvas_db.set_global_redisctx(ctx)
384
        status = openvas_db.item_get_single(('internal/%s' % scan_id))
385
        return status == 'stop_all'
386
387
    @staticmethod
388
    def stop_scan(global_scan_id):
0 ignored issues
show
Bug introduced by
Parameters differ from overridden 'stop_scan' method
Loading history...
389
        """ Set a key in redis to indicate the wrapper is stopped.
390
        It is done through redis because it is a new multiprocess
391
        instance and it is not possible to reach the variables
392
        of the grandchild process. Send SIGUSR2 to openvas to stop
393
        each running scan."""
394
        ctx = openvas_db.kb_connect()
395
        for current_kbi in range(0, openvas_db.MAX_DBINDEX):
396
            ctx.execute_command('SELECT '+ str(current_kbi))
397
            openvas_db.set_global_redisctx(ctx)
398
            scan_id = openvas_db.item_get_single(
399
                ('internal/%s/globalscanid' % global_scan_id))
400
            if scan_id:
401
                openvas_db.item_set_single(('internal/%s' % scan_id),
402
                                           ['stop_all', ])
403
                ovas_pid = openvas_db.item_get_single('internal/ovas_pid')
404
                parent = psutil.Process(int(ovas_pid))
405
                openvas_db.release_db(current_kbi)
406
                parent.send_signal(signal.SIGUSR2)
407
                logger.debug('Stopping process: {0}'.format(parent))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
408
409
    @staticmethod
410
    def get_vts_in_groups(ctx, filters):
411
        """ Return a list of vts which match with the given filter.
412
413
        @input filters A list of filters. Each filter has key, operator and
414
                       a value. They are separated by a space.
415
                       Supported keys: family
416
        @return Return a list of vts which match with the given filter.
417
        """
418
        vts_list = list()
419
        oids = nvti.get_oids()
420
421
        for elem in filters:
422
            key, value = elem.split('=')
423
            for oid in oids:
424
                if key == 'family' and value == nvti.get_nvt_family(ctx, oid[1]):
425
                    vts_list.append(oid[1])
426
        return vts_list
427
428
429
    def process_vts(self, vts):
430
        """ Add single VTs and their parameters. """
431
        vts_list = []
432
        vts_params = []
433
        vtgroups = vts.pop('vtgroups')
434
435
        ctx = openvas_db.db_find(nvti.NVTICACHE_STR)
436
        openvas_db.set_global_redisctx(ctx)
437
        if vtgroups:
438
            vts_list = self.get_vts_in_groups(ctx, vtgroups)
439
440
        for memb in vts.items():
441
            vts_list.append(memb[0])
442
            nvt_name = nvti.get_nvt_name(ctx, memb[0])
443
            for i in memb[1].items():
444
                param = ["{0}[{1}]:{2}".format(nvt_name, i[1]['type'], i[0]),
445
                         str(i[1]['value'])]
446
                vts_params.append(param)
447
        return vts_list, vts_params
448
449
    @staticmethod
450
    def build_credentials_as_prefs(credentials):
451
        """ Parse the credential dictionary.
452
        @param credentials: Dictionary with the credentials.
453
454
        @return A list with the credentials in string format to be
455
                added to the redis KB.
456
        """
457
        cred_prefs_list = []
458
        for credential in credentials.items():
459
            service = credential[0]
460
            cred_params = credentials.get(service)
461
            cred_type = cred_params.get('type', '')
462
            username = cred_params.get('username', '')
463
            password = cred_params.get('password', '')
464
465
            if service == 'ssh':
466
                port = cred_params.get('port', '')
467
                cred_prefs_list.append('auth_port_ssh|||' +
468
                                       '{0}'.format(port))
469
                cred_prefs_list.append('SSH Authorization[entry]:SSH login ' +
470
                                       'name:|||{0}'.format(username))
471
                if cred_type == 'up':
472
                    cred_prefs_list.append('SSH Authorization[password]:' +
473
                                           'SSH password (unsafe!):|||' +
474
                                           '{0}'.format(password))
475
                else:
476
                    private = cred_params.get('private', '')
477
                    cred_prefs_list.append('SSH Authorization[password]:' +
478
                                           'SSH key passphrase:|||' +
479
                                           '{0}'.format(password))
480
                    cred_prefs_list.append('SSH Authorization[file]:' +
481
                                           'SSH private key:|||' +
482
                                           '{0}'.format(private))
483
            if service == 'smb':
484
                cred_prefs_list.append('SMB Authorization[entry]:SMB login:' +
485
                                       '|||{0}'.format(username))
486
                cred_prefs_list.append('SMB Authorization[password]:' +
487
                                       'SMB password :|||' +
488
                                       '{0}'.format(password))
489
            if service == 'esxi':
490
                cred_prefs_list.append('ESXi Authorization[entry]:ESXi login ' +
491
                                       'name:|||{0}'.format(username))
492
                cred_prefs_list.append('ESXi Authorization[password]:' +
493
                                       'ESXi login password:|||' +
494
                                       '{0}'.format(password))
495
496
            if service == 'snmp':
497
                community = cred_params.get('community', '')
498
                auth_algorithm = cred_params.get('auth_algorithm', '')
499
                privacy_password = cred_params.get('privacy_password', '')
500
                privacy_algorithm = cred_params.get('privacy_algorithm', '')
501
502
                cred_prefs_list.append('SNMP Authorization[password]:' +
503
                                       'SNMP Community:' +
504
                                       '{0}'.format(community))
505
                cred_prefs_list.append('SNMP Authorization[entry]:' +
506
                                       'SNMPv3 Username:' +
507
                                       '{0}'.format(username))
508
                cred_prefs_list.append('SNMP Authorization[password]:' +
509
                                       'SNMPv3 Password:' +
510
                                       '{0}'.format(password))
511
                cred_prefs_list.append('SNMP Authorization[radio]:' +
512
                                       'SNMPv3 Authentication Algorithm:' +
513
                                       '{0}'.format(auth_algorithm))
514
                cred_prefs_list.append('SNMP Authorization[password]:' +
515
                                       'SNMPv3 Privacy Password:' +
516
                                       '{0}'.format(privacy_password))
517
                cred_prefs_list.append('SNMP Authorization[radio]:' +
518
                                       'SNMPv3 Privacy Algorithm:' +
519
                                       '{0}'.format(privacy_algorithm))
520
521
        return cred_prefs_list
522
523
    def exec_scan(self, scan_id, target):
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (30/15).
Loading history...
524
        """ Starts the OpenVAS scanner for scan_id scan. """
525
        global MAIN_KBINDEX
0 ignored issues
show
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
526
        ports = self.get_scan_ports(scan_id, target)
527
        if not ports:
528
            self.add_scan_error(scan_id, name='', host=target,
529
                                value='No port list defined.')
530
            return 2
531
532
        # Get scan options
533
        options = self.get_scan_options(scan_id)
534
        prefs_val = []
535
        ctx = openvas_db.kb_new()
536
        openvas_db.set_global_redisctx(ctx)
537
        MAIN_KBINDEX = openvas_db.DB_INDEX
538
539
        # To avoid interference between scan process during a parallel scanning
540
        # new uuid is used internaly for each scan.
541
        openvas_scan_id = str(uuid.uuid4())
542
        openvas_db.item_add_single(('internal/%s' % openvas_scan_id), ['new', ])
543
        openvas_db.item_add_single(('internal/%s/globalscanid' % scan_id), [openvas_scan_id, ])
544
545
        # Set scan preferences
546
        for item in options.items():
547
            item_type = ''
548
            if item[0] in OSPD_PARAMS:
549
                item_type = OSPD_PARAMS[item[0]].get('type')
550
            if item_type == 'boolean' and item[1] == 1:
551
                val = 'yes'
552
            else:
553
                val = str(item[1])
554
            prefs_val.append(item[0] + "|||" + val)
555
        openvas_db.item_add_single(str('internal/%s/scanprefs' % (openvas_scan_id)),
556
                                   prefs_val)
557
558
        # Store MAIN_KBINDEX as global preference
559
        ov_maindbid = ('ov_maindbid|||%d' % MAIN_KBINDEX)
560
        openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
561
                                   [ov_maindbid, ])
562
563
        # Set target
564
        target_aux = ('TARGET|||%s' % target)
565
        openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
566
                                   [target_aux, ])
567
        # Set port range
568
        port_range = ('port_range|||%s' % ports)
569
        openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
570
                                   [port_range, ])
571
572
        # Set credentials
573
        credentials = self.get_scan_credentials(scan_id, target)
574
        if credentials:
575
            cred_prefs = self.build_credentials_as_prefs(credentials)
576
            openvas_db.item_add_single(str('internal/%s/scanprefs' % openvas_scan_id),
577
                                       cred_prefs)
578
579
        # Set plugins to run
580
        nvts = self.get_scan_vts(scan_id)
581
        if nvts != '':
582
            nvts_list, nvts_params = self.process_vts(nvts)
583
            # Select the scan KB again.
584
            ctx.execute_command('SELECT '+ str(MAIN_KBINDEX))
585
            openvas_db.set_global_redisctx(ctx)
586
            # Add nvts list
587
            separ = ';'
588
            plugin_list = ('plugin_set|||%s' % separ.join(nvts_list))
589
            openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
590
                                       [plugin_list, ])
591
            # Add nvts parameters
592
            for elem in nvts_params:
593
                item = ('%s|||%s' % (elem[0], elem[1]))
594
                openvas_db.item_add_single(('internal/%s/scanprefs' % openvas_scan_id),
595
                                           [item, ])
596
        else:
597
            openvas_db.release_db(MAIN_KBINDEX)
598
            self.add_scan_error(scan_id, name='', host=target,
599
                                value='No VTS to run.')
600
            return 2
601
602
        # Create a general log entry about executing OpenVAS
603
        # It is important to send at least one result, otherwise
604
        # the host details won't be stored.
605
        self.add_scan_log(scan_id, host=target, name='OpenVAS summary',
606
                          value='An OpenVAS Scanner was started for %s.'
607
                          % target)
608
609
        self.add_scan_log(scan_id, host=target, name='KB location Found',
610
                          value='KB location path was found: %s.'
611
                          % openvas_db.DB_ADDRESS)
612
613
        self.add_scan_log(scan_id, host=target, name='Feed Update',
614
                          value='Feed version: %s.'
615
                          % nvti.get_feed_version())
616
617
        cmd = ['openvassd', '--scan-start', openvas_scan_id]
618
        try:
619
            result = subprocess.Popen(cmd, shell=False)
620
        except OSError:
621
            # the command is not available
622
            return False
623
624
        ovas_pid = result.pid
625
        logger.debug('pid = {0}'.format(ovas_pid))
0 ignored issues
show
introduced by
Use formatting in logging functions and pass the parameters as arguments
Loading history...
626
        openvas_db.item_add_single(('internal/ovas_pid'), [ovas_pid, ])
627
628
        # Wait until the scanner starts and loads all the preferences.
629
        while openvas_db.item_get_single('internal/'+ openvas_scan_id) == 'new':
630
            time.sleep(1)
631
632
        no_id_found = False
633
        while True:
634
            time.sleep(3)
635
636
            # Check if the client stopped the whole scan
637
            if self.scan_is_stopped(openvas_scan_id):
638
                return 1
639
640
            ctx = openvas_db.kb_connect(MAIN_KBINDEX)
641
            openvas_db.set_global_redisctx(ctx)
642
            dbs = openvas_db.item_get_set('internal/dbindex')
643
            for i in list(dbs):
644
                if i == MAIN_KBINDEX:
645
                    continue
646
                ctx.execute_command('SELECT '+ str(i))
647
                openvas_db.set_global_redisctx(ctx)
648
                id_aux = ctx.execute_command('srandmember internal/scan_id')
649
                if not id_aux:
650
                    continue
651
                if id_aux == openvas_scan_id:
652
                    no_id_found = False
653
                    self.get_openvas_timestamp_scan_host(scan_id, target)
654
                    self.get_openvas_result(scan_id)
655
                    self.get_openvas_status(scan_id, target)
656
                    if self.scan_is_finished(openvas_scan_id):
657
                        ctx.execute_command('SELECT '+ str(MAIN_KBINDEX))
658
                        openvas_db.remove_set_member('internal/dbindex', i)
659
                        openvas_db.release_db(i)
660
661
            # Scan end. No kb in use for this scan id
662
            if no_id_found:
663
                break
664
            no_id_found = True
665
666
        # Delete keys from KB related to this scan task.
667
        openvas_db.release_db(MAIN_KBINDEX)
668
        return 1
669
670
671
def main():
672
    """ OSP openvas main function. """
673
    daemon_main('OSPD - openvas wrapper', OSPDopenvas)
674