Passed
Push — master ( 1b5660...71e7de )
by Juan José
01:31 queued 11s
created

ospd_openvas.openvas_db   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 279
Duplicated Lines 33.69 %

Importance

Changes 0
Metric Value
wmc 46
eloc 160
dl 94
loc 279
rs 8.72
c 0
b 0
f 0

22 Functions

Rating   Name   Duplication   Size   Complexity  
A kb_connect() 15 15 3
A item_add_single() 0 6 1
A get_host_scan_scan_end_time() 0 4 1
A get_result() 0 4 1
A kb_new() 0 8 3
A db_init() 0 5 3
A get_status() 0 4 1
A release_db() 0 9 2
A db_find() 0 7 3
A get_kb_context() 14 14 3
A set_global_redisctx() 0 5 1
A max_db_index() 17 17 4
A item_del_single() 0 6 1
B get_db_connection() 25 25 6
A try_database_index() 13 13 4
A get_host_scan_scan_start_time() 0 4 1
A item_set_single() 0 9 1
A get_elem_pattern_by_index() 0 11 2
A item_get_single() 0 6 1
A get_pattern() 10 10 2
A remove_list_item() 0 6 1
A item_get_list() 0 6 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.openvas_db often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

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

1
# -*- coding: utf-8 -*-
2
# Description:
3
# Access management for redis-based OpenVAS Scanner Database
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
""" Functions to retrieve and store data from redis-based OpenVAS Scanner database. """
26
27
# Needed to say that when we import ospd, we mean the package and not the
28
# module in that directory.
29
from __future__ import absolute_import
30
from __future__ import print_function
31
32
import redis
33
import subprocess
34
35
""" Path to the Redis socket. """
36
DB_ADDRESS = ""
37
38
""" Name of the namespace usage bitmap in redis. """
39
DBINDEX_NAME = "GVM.__GlobalDBIndex"
40
MAX_DBINDEX = 0
41
DB_INDEX = 0
42
REDISCONTEXT = None
43
SOCKET_TIMEOUT = 60
44
45
# Possible positions of nvt values in cache list.
46
nvt_meta_fields = [
47
    "NVT_FILENAME_POS",
48
    "NVT_REQUIRED_KEYS_POS",
49
    "NVT_MANDATORY_KEYS_POS",
50
    "NVT_EXCLUDED_KEYS_POS",
51
    "NVT_REQUIRED_UDP_PORTS_POS",
52
    "NVT_REQUIRED_PORTS_POS",
53
    "NVT_DEPENDENCIES_POS",
54
    "NVT_TAGS_POS",
55
    "NVT_CVES_POS",
56
    "NVT_BIDS_POS",
57
    "NVT_XREFS_POS",
58
    "NVT_CATEGORY_POS",
59
    "NVT_TIMEOUT_POS",
60
    "NVT_FAMILY_POS",
61
    "NVT_NAME_POS",]
62
63 View Code Duplication
def get_db_connection():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
64
    """ Retrieve the db address from openvassd config.
65
    """
66
    global DB_ADDRESS
67
    try:
68
        result = subprocess.check_output(['openvassd', '-s'],
69
                                         stderr=subprocess.STDOUT)
70
        result = result.decode('ascii')
71
    except OSError:
72
        # the command is not available
73
        return 2
74
75
    if result is None:
76
        return 2
77
78
    path = None
79
    for conf in result.split('\n'):
80
        if conf.find("db_address") == 0:
81
            path = conf.split('=')
82
            break
83
84
    if path is None:
85
        return 2
86
87
    DB_ADDRESS = str.strip(path[1])
88
89
90 View Code Duplication
def max_db_index():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
91
    """Set the number of databases have been configured into kbr struct.
92
    """
93
    global MAX_DBINDEX
94
    try:
95
        ctx = kb_connect()
96
        resp = ctx.config_get("databases")
97
    except redis.RedisError:
98
        return 2
99
100
    if isinstance(resp, dict) is False:
101
        return 2
102
    if len(resp) == 1:
103
        MAX_DBINDEX = int(resp["databases"])
104
    else:
105
        print("Redis: unexpected reply length %d" % len(resp))
106
        return 2
107
108
def set_global_redisctx(ctx):
109
    """ Set the global set the global REDISCONTEXT.
110
    """
111
    global REDISCONTEXT
112
    REDISCONTEXT = ctx
113
114
def db_init():
115
    """ Set DB_ADDRESS and max_db_index. """
116
    if get_db_connection() or max_db_index():
117
        return False
118
    return True
119
120 View Code Duplication
def try_database_index(ctx, i):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
121
    """ Check if it is already in use. If not set it as in use and return.
122
    """
123
    try:
124
        resp = ctx.hsetnx(DBINDEX_NAME, i, 1)
125
    except:
126
        return 2
127
128
    if isinstance(resp, int) is False:
129
        return 2
130
131
    if resp == 1:
132
        return 1
133
134 View Code Duplication
def kb_connect(dbnum=0):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
135
    """ Connect to redis to the given database or to the default db 0 .
136
    """
137
    global DB_INDEX
138
    if get_db_connection() is 2:
139
        return 2
140
    try:
141
        ctx = redis.Redis(unix_socket_path=DB_ADDRESS,
142
                          db=dbnum,
143
                          socket_timeout=SOCKET_TIMEOUT, charset="latin-1",
144
                          decode_responses=True)
145
    except ConnectionError as e:
146
        return {"error": str(e)}
147
    DB_INDEX = dbnum
148
    return ctx
149
150
def db_find(patt):
151
    """ Search a pattern inside all kbs. When find it return it.
152
    """
153
    for i in range(0, MAX_DBINDEX):
154
        ctx = kb_connect (i)
155
        if ctx.keys(patt):
156
            return ctx
157
158
def kb_new():
159
    """ Return a new kb context to an empty kb.
160
    """
161
    ctx = db_find(DBINDEX_NAME)
162
    for index in range(1, MAX_DBINDEX):
163
            if try_database_index(ctx, index) == 1:
164
                ctx = kb_connect(index)
165
                return ctx
166
167 View Code Duplication
def get_kb_context():
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
168
    """ Get redis context if it is already connected or do a connection.
169
    """
170
    global REDISCONTEXT
171
    if REDISCONTEXT is not None:
172
        return REDISCONTEXT
173
174
    REDISCONTEXT = db_find(DBINDEX_NAME)
175
176
    if REDISCONTEXT is None:
177
        print("Problem retrieving Redis Context")
178
        return 2
179
180
    return REDISCONTEXT
181
182
def item_get_list(name):
183
    """ Get all values under a KB key list.
184
    The right global REDISCONTEXT must be already set.
185
    """
186
    ctx = get_kb_context()
187
    return ctx.lrange(name, 0, -1)
188
189
def remove_list_item(key, value):
190
    """ Remove item from the key list.
191
    The right global REDISCONTEXT must be already set.
192
    """
193
    ctx = get_kb_context()
194
    ctx.lrem(key, 0, value)
195
196
def item_get_single(name):
197
    """ Get a single KB element. The right global REDISCONTEXT must be
198
    already set.
199
    """
200
    ctx = get_kb_context()
201
    return ctx.lindex(name, 0)
202
203
def item_add_single(name, values):
204
    """ Add a single KB element with one or more values.
205
    The right global REDISCONTEXT must be already set.
206
    """
207
    ctx = get_kb_context()
208
    ctx.rpush(name, *set(values))
209
210
def item_set_single(name, value):
211
    """ Set (replace) a new single KB element. The right global
212
    REDISCONTEXT must be already set.
213
    """
214
    ctx = get_kb_context()
215
    pipe = ctx.pipeline()
216
    pipe.delete(name)
217
    pipe.rpush(name, *set(value))
218
    pipe.execute()
219
220
def item_del_single(name):
221
    """ Delete a single KB element. The right global REDISCONTEXT must be
222
    already set.
223
    """
224
    ctx = get_kb_context()
225
    ctx.delete(name)
226
227 View Code Duplication
def get_pattern(pattern):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
228
    """ Get all items stored under a given pattern.
229
    """
230
    ctx = get_kb_context()
231
    items = ctx.keys(pattern)
232
233
    elem_list = []
234
    for item in items:
235
        elem_list.append([item, ctx.lrange(item, 0, -1)])
236
    return elem_list
237
238
def get_elem_pattern_by_index(pattern, index=1):
239
    """ Get all items with index 'index', stored under
240
    a given pattern.
241
    """
242
    ctx = get_kb_context()
243
    items = ctx.keys(pattern)
244
245
    elem_list = []
246
    for item in items:
247
        elem_list.append([item, ctx.lindex(item, index)])
248
    return elem_list
249
250
def release_db(kbindex=0):
251
    """ Connect to redis and select the db by index.
252
    Flush db and delete the index from DBINDEX_NAME list.
253
    """
254
    if kbindex:
255
        ctx = kb_connect(kbindex)
256
        ctx.flushdb()
257
        ctx = kb_connect()
258
        ctx.hdel(DBINDEX_NAME, kbindex)
259
260
def get_result():
261
    """ Get and remove the oldest result from the list. """
262
    ctx = get_kb_context()
263
    return ctx.rpop("internal/results")
264
265
def get_status():
266
    """ Get and remove the oldest host scan status from the list. """
267
    ctx = get_kb_context()
268
    return ctx.rpop("internal/status")
269
270
def get_host_scan_scan_start_time():
271
    """ Get the timestamp of the scan start from redis. """
272
    ctx = get_kb_context()
273
    return ctx.rpop("internal/start_time")
274
275
def get_host_scan_scan_end_time():
276
    """ Get the timestamp of the scan end from redis. """
277
    ctx = get_kb_context()
278
    return ctx.rpop("internal/end_time")
279