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

get_elem_pattern_by_index()   A

Complexity

Conditions 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nop 2
dl 0
loc 11
rs 10
c 0
b 0
f 0
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