Completed
Push — master ( af96e1...147191 )
by Jaspar
23s queued 16s
created

GmpV208Mixin.import_report_format()   A

Complexity

Conditions 3

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nop 2
dl 0
loc 27
rs 9.7
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018-2021 Greenbone Networks GmbH
3
#
4
# SPDX-License-Identifier: GPL-3.0-or-later
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (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, see <http://www.gnu.org/licenses/>.
18
19
# pylint: disable=arguments-differ, redefined-builtin, too-many-lines
20
21
"""
22
Module for communication with gvmd in
23
`Greenbone Management Protocol version 20.08`_
24
25
.. _Greenbone Management Protocol version 20.08:
26
    https://docs.greenbone.net/API/GMP/gmp-20.08.html
27
"""
28
import logging
29
from numbers import Integral
30
31
from typing import Any, List, Optional, Callable
32
33
from gvm.connections import GvmConnection
34
from gvm.errors import InvalidArgument, RequiredArgument
35
from gvm.protocols.base import GvmProtocol
36
37
38
from gvm.utils import (
39
    check_command_status,
40
    to_base64,
41
    to_bool,
42
    to_comma_list,
43
    add_filter,
44
)
45
from gvm.xml import XmlCommand
46
47
PROTOCOL_VERSION = (20, 8)
48
49
50
logger = logging.getLogger(__name__)
51
52
53
class GmpV208Mixin(GvmProtocol):
54
    """Python interface for Greenbone Management Protocol
55
56
    This class implements the `Greenbone Management Protocol version 20.08`_
57
58
    Arguments:
59
        connection: Connection to use to talk with the gvmd daemon. See
60
            :mod:`gvm.connections` for possible connection types.
61
        transform: Optional transform `callable`_ to convert response data.
62
            After each request the callable gets passed the plain response data
63
            which can be used to check the data and/or conversion into different
64
            representations like a xml dom.
65
66
            See :mod:`gvm.transforms` for existing transforms.
67
68
    .. _Greenbone Management Protocol version 20.08:
69
        https://docs.greenbone.net/API/GMP/gmp-20.08.html
70
    .. _callable:
71
        https://docs.python.org/3/library/functions.html#callable
72
    """
73
74
    def __init__(
75
        self,
76
        connection: GvmConnection,
77
        *,
78
        transform: Optional[Callable[[str], Any]] = None,
79
    ):
80
        super().__init__(connection, transform=transform)
81
82
        # Is authenticated on gvmd
83
        self._authenticated = False
84
85
    def is_authenticated(self) -> bool:
86
        """Checks if the user is authenticated
87
88
        If the user is authenticated privileged GMP commands like get_tasks
89
        may be send to gvmd.
90
91
        Returns:
92
            bool: True if an authenticated connection to gvmd has been
93
            established.
94
        """
95
        return self._authenticated
96
97
    def authenticate(self, username: str, password: str) -> Any:
98
        """Authenticate to gvmd.
99
100
        The generated authenticate command will be send to server.
101
        Afterwards the response is read, transformed and returned.
102
103
        Arguments:
104
            username: Username
105
            password: Password
106
107
        Returns:
108
            Transformed response from server.
109
        """
110
        cmd = XmlCommand("authenticate")
111
112
        if not username:
113
            raise RequiredArgument(
114
                function=self.authenticate.__name__, argument='username'
115
            )
116
117
        if not password:
118
            raise RequiredArgument(
119
                function=self.authenticate.__name__, argument='password'
120
            )
121
122
        credentials = cmd.add_element("credentials")
123
        credentials.add_element("username", username)
124
        credentials.add_element("password", password)
125
126
        self._send(cmd.to_string())
127
        response = self._read()
128
129
        if check_command_status(response):
130
            self._authenticated = True
131
132
        return self._transform(response)
133
134
    def get_vulnerabilities(
135
        self, *, filter: Optional[str] = None, filter_id: Optional[str] = None
136
    ) -> Any:
137
        """Request a list of vulnerabilities
138
139
        Arguments:
140
            filter: Filter term to use for the query
141
            filter_id: UUID of an existing filter to use for the query
142
        Returns:
143
            The response. See :py:meth:`send_command` for details.
144
        """
145
        cmd = XmlCommand("get_vulns")
146
147
        add_filter(cmd, filter, filter_id)
148
149
        return self._send_xml_command(cmd)
150
151
    def get_vulnerability(self, vulnerability_id: str) -> Any:
152
        """Request a single vulnerability
153
154
        Arguments:
155
            vulnerability_id: ID of an existing vulnerability
156
157
        Returns:
158
            The response. See :py:meth:`send_command` for details.
159
        """
160
        if not vulnerability_id:
161
            raise RequiredArgument(
162
                function=self.get_vulnerability.__name__,
163
                argument='vulnerability_id',
164
            )
165
166
        cmd = XmlCommand("get_vulns")
167
        cmd.set_attribute("vuln_id", vulnerability_id)
168
        return self._send_xml_command(cmd)
169
170
    def create_group(
171
        self,
172
        name: str,
173
        *,
174
        comment: Optional[str] = None,
175
        special: Optional[bool] = False,
176
        users: Optional[List[str]] = None,
177
    ) -> Any:
178
        """Create a new group
179
180
        Arguments:
181
            name: Name of the new group
182
            comment: Comment for the group
183
            special: Create permission giving members full access to each
184
                other's entities
185
            users: List of user names to be in the group
186
187
        Returns:
188
            The response. See :py:meth:`send_command` for details.
189
        """
190
        if not name:
191
            raise RequiredArgument(
192
                function=self.create_group.__name__, argument='name'
193
            )
194
195
        cmd = XmlCommand("create_group")
196
        cmd.add_element("name", name)
197
198
        if comment:
199
            cmd.add_element("comment", comment)
200
201
        if special:
202
            _xmlspecial = cmd.add_element("specials")
203
            _xmlspecial.add_element("full")
204
205
        if users:
206
            cmd.add_element("users", to_comma_list(users))
207
208
        return self._send_xml_command(cmd)
209
210
    def clone_group(self, group_id: str) -> Any:
211
        """Clone an existing group
212
213
        Arguments:
214
            group_id: UUID of an existing group to clone from
215
216
        Returns:
217
            The response. See :py:meth:`send_command` for details.
218
        """
219
        if not group_id:
220
            raise RequiredArgument(
221
                function=self.clone_group.__name__, argument='group_id'
222
            )
223
224
        cmd = XmlCommand("create_group")
225
        cmd.add_element("copy", group_id)
226
        return self._send_xml_command(cmd)
227
228
    def delete_group(
229
        self, group_id: str, *, ultimate: Optional[bool] = False
230
    ) -> Any:
231
        """Deletes an existing group
232
233
        Arguments:
234
            group_id: UUID of the group to be deleted.
235
            ultimate: Whether to remove entirely, or to the trashcan.
236
        """
237
        if not group_id:
238
            raise RequiredArgument(
239
                function=self.delete_group.__name__, argument='group_id'
240
            )
241
242
        cmd = XmlCommand("delete_group")
243
        cmd.set_attribute("group_id", group_id)
244
        cmd.set_attribute("ultimate", to_bool(ultimate))
245
246
        return self._send_xml_command(cmd)
247
248
    def describe_auth(self) -> Any:
249
        """Describe authentication methods
250
251
        Returns a list of all used authentication methods if such a list is
252
        available.
253
254
        Returns:
255
            The response. See :py:meth:`send_command` for details.
256
        """
257
        return self._send_xml_command(XmlCommand("describe_auth"))
258
259
    def empty_trashcan(self) -> Any:
260
        """Empty the trashcan
261
262
        Remove all entities from the trashcan. **Attention:** this command can
263
        not be reverted
264
265
        Returns:
266
            The response. See :py:meth:`send_command` for details.
267
        """
268
        return self._send_xml_command(XmlCommand("empty_trashcan"))
269
270 View Code Duplication
    def get_groups(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
271
        self,
272
        *,
273
        filter: Optional[str] = None,
274
        filter_id: Optional[str] = None,
275
        trash: Optional[bool] = None,
276
    ) -> Any:
277
        """Request a list of groups
278
279
        Arguments:
280
            filter: Filter term to use for the query
281
            filter_id: UUID of an existing filter to use for the query
282
            trash: Whether to get the trashcan groups instead
283
284
        Returns:
285
            The response. See :py:meth:`send_command` for details.
286
        """
287
        cmd = XmlCommand("get_groups")
288
289
        add_filter(cmd, filter, filter_id)
290
291
        if trash is not None:
292
            cmd.set_attribute("trash", to_bool(trash))
293
294
        return self._send_xml_command(cmd)
295
296
    def get_group(self, group_id: str) -> Any:
297
        """Request a single group
298
299
        Arguments:
300
            group_id: UUID of an existing group
301
302
        Returns:
303
            The response. See :py:meth:`send_command` for details.
304
        """
305
        cmd = XmlCommand("get_groups")
306
307
        if not group_id:
308
            raise RequiredArgument(
309
                function=self.get_group.__name__, argument='group_id'
310
            )
311
312
        cmd.set_attribute("group_id", group_id)
313
        return self._send_xml_command(cmd)
314
315
    def get_preferences(
316
        self, *, nvt_oid: Optional[str] = None, config_id: Optional[str] = None
317
    ) -> Any:
318
        """Request a list of preferences
319
320
        When the command includes a config_id attribute, the preference element
321
        includes the preference name, type and value, and the NVT to which the
322
        preference applies. Otherwise, the preference element includes just the
323
        name and value, with the NVT and type built into the name.
324
325
        Arguments:
326
            nvt_oid: OID of nvt
327
            config_id: UUID of scan config of which to show preference values
328
329
        Returns:
330
            The response. See :py:meth:`send_command` for details.
331
        """
332
        cmd = XmlCommand("get_preferences")
333
334
        if nvt_oid:
335
            cmd.set_attribute("nvt_oid", nvt_oid)
336
337
        if config_id:
338
            cmd.set_attribute("config_id", config_id)
339
340
        return self._send_xml_command(cmd)
341
342
    def get_preference(
343
        self,
344
        name: str,
345
        *,
346
        nvt_oid: Optional[str] = None,
347
        config_id: Optional[str] = None,
348
    ) -> Any:
349
        """Request a nvt preference
350
351
        Arguments:
352
            name: name of a particular preference
353
            nvt_oid: OID of nvt
354
            config_id: UUID of scan config of which to show preference values
355
356
        Returns:
357
            The response. See :py:meth:`send_command` for details.
358
        """
359
        cmd = XmlCommand("get_preferences")
360
361
        if not name:
362
            raise RequiredArgument(
363
                function=self.get_preference.__name__, argument='name'
364
            )
365
366
        cmd.set_attribute("preference", name)
367
368
        if nvt_oid:
369
            cmd.set_attribute("nvt_oid", nvt_oid)
370
371
        if config_id:
372
            cmd.set_attribute("config_id", config_id)
373
374
        return self._send_xml_command(cmd)
375
376
    def get_settings(self, *, filter: Optional[str] = None) -> Any:
377
        """Request a list of user settings
378
379
        Arguments:
380
            filter: Filter term to use for the query
381
382
        Returns:
383
            The response. See :py:meth:`send_command` for details.
384
        """
385
        cmd = XmlCommand("get_settings")
386
387
        if filter:
388
            cmd.set_attribute("filter", filter)
389
390
        return self._send_xml_command(cmd)
391
392
    def get_setting(self, setting_id: str) -> Any:
393
        """Request a single setting
394
395
        Arguments:
396
            setting_id: UUID of an existing setting
397
398
        Returns:
399
            The response. See :py:meth:`send_command` for details.
400
        """
401
        cmd = XmlCommand("get_settings")
402
403
        if not setting_id:
404
            raise RequiredArgument(
405
                function=self.get_setting.__name__, argument='setting_id'
406
            )
407
408
        cmd.set_attribute("setting_id", setting_id)
409
        return self._send_xml_command(cmd)
410
411
    def get_system_reports(
412
        self,
413
        *,
414
        name: Optional[str] = None,
415
        duration: Optional[int] = None,
416
        start_time: Optional[str] = None,
417
        end_time: Optional[str] = None,
418
        brief: Optional[bool] = None,
419
        slave_id: Optional[str] = None,
420
    ) -> Any:
421
        """Request a list of system reports
422
423
        Arguments:
424
            name: A string describing the required system report
425
            duration: The number of seconds into the past that the system report
426
                should include
427
            start_time: The start of the time interval the system report should
428
                include in ISO time format
429
            end_time: The end of the time interval the system report should
430
                include in ISO time format
431
            brief: Whether to include the actual system reports
432
            slave_id: UUID of GMP scanner from which to get the system reports
433
434
        Returns:
435
            The response. See :py:meth:`send_command` for details.
436
        """
437
        cmd = XmlCommand("get_system_reports")
438
439
        if name:
440
            cmd.set_attribute("name", name)
441
442
        if duration is not None:
443
            if not isinstance(duration, Integral):
444
                raise InvalidArgument("duration needs to be an integer number")
445
446
            cmd.set_attribute("duration", str(duration))
447
448
        if start_time:
449
            cmd.set_attribute("start_time", str(start_time))
450
451
        if end_time:
452
            cmd.set_attribute("end_time", str(end_time))
453
454
        if brief is not None:
455
            cmd.set_attribute("brief", to_bool(brief))
456
457
        if slave_id:
458
            cmd.set_attribute("slave_id", slave_id)
459
460
        return self._send_xml_command(cmd)
461
462
    def get_version(self) -> Any:
463
        """Get the Greenbone Manager Protocol version used by the remote gvmd
464
        Returns:
465
            The response. See :py:meth:`send_command` for details.
466
        """
467
        return self._send_xml_command(XmlCommand("get_version"))
468
469
    def help(
470
        self, *, format: Optional[str] = None, help_type: Optional[str] = None
471
    ) -> Any:
472
        """Get the help text
473
474
        Arguments:
475
            format: One of "html", "rnc", "text" or "xml
476
            help_type: One of "brief" or "". Default ""
477
478
        Returns:
479
            The response. See :py:meth:`send_command` for details.
480
        """
481
        cmd = XmlCommand("help")
482
483
        if not help_type:
484
            help_type = ""
485
486
        if help_type not in ("", "brief"):
487
            raise InvalidArgument(
488
                'help_type argument must be an empty string or "brief"'
489
            )
490
491
        cmd.set_attribute("type", help_type)
492
493
        if format:
494
            if not format.lower() in ("html", "rnc", "text", "xml"):
495
                raise InvalidArgument(
496
                    "help format Argument must be one of html, rnc, text or "
497
                    "xml"
498
                )
499
500
            cmd.set_attribute("format", format)
501
502
        return self._send_xml_command(cmd)
503
504
    def modify_auth(self, group_name: str, auth_conf_settings: dict) -> Any:
505
        """Modifies an existing auth.
506
507
        Arguments:
508
            group_name: Name of the group to be modified.
509
            auth_conf_settings: The new auth config.
510
511
        Returns:
512
            The response. See :py:meth:`send_command` for details.
513
        """
514
        if not group_name:
515
            raise RequiredArgument(
516
                function=self.modify_auth.__name__, argument='group_name'
517
            )
518
        if not auth_conf_settings:
519
            raise RequiredArgument(
520
                function=self.modify_auth.__name__,
521
                argument='auth_conf_settings',
522
            )
523
        cmd = XmlCommand("modify_auth")
524
        _xmlgroup = cmd.add_element("group", attrs={"name": str(group_name)})
525
526
        for key, value in auth_conf_settings.items():
527
            _xmlauthconf = _xmlgroup.add_element("auth_conf_setting")
528
            _xmlauthconf.add_element("key", key)
529
            _xmlauthconf.add_element("value", value)
530
531
        return self._send_xml_command(cmd)
532
533 View Code Duplication
    def modify_group(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
534
        self,
535
        group_id: str,
536
        *,
537
        comment: Optional[str] = None,
538
        name: Optional[str] = None,
539
        users: Optional[List[str]] = None,
540
    ) -> Any:
541
        """Modifies an existing group.
542
543
        Arguments:
544
            group_id: UUID of group to modify.
545
            comment: Comment on group.
546
            name: Name of group.
547
            users: List of user names to be in the group
548
549
        Returns:
550
            The response. See :py:meth:`send_command` for details.
551
        """
552
        if not group_id:
553
            raise RequiredArgument(
554
                function=self.modify_group.__name__, argument='group_id'
555
            )
556
557
        cmd = XmlCommand("modify_group")
558
        cmd.set_attribute("group_id", group_id)
559
560
        if comment:
561
            cmd.add_element("comment", comment)
562
563
        if name:
564
            cmd.add_element("name", name)
565
566
        if users:
567
            cmd.add_element("users", to_comma_list(users))
568
569
        return self._send_xml_command(cmd)
570
571
    def modify_setting(
572
        self,
573
        setting_id: Optional[str] = None,
574
        name: Optional[str] = None,
575
        value: Optional[str] = None,
576
    ) -> Any:
577
        """Modifies an existing setting.
578
579
        Arguments:
580
            setting_id: UUID of the setting to be changed.
581
            name: The name of the setting. Either setting_id or name must be
582
                passed.
583
            value: The value of the setting.
584
585
        Returns:
586
            The response. See :py:meth:`send_command` for details.
587
        """
588
        if not setting_id and not name:
589
            raise RequiredArgument(
590
                function=self.modify_setting.__name__,
591
                argument='setting_id or name argument',
592
            )
593
594
        if value is None:
595
            raise RequiredArgument(
596
                function=self.modify_setting.__name__, argument='value argument'
597
            )
598
599
        cmd = XmlCommand("modify_setting")
600
601
        if setting_id:
602
            cmd.set_attribute("setting_id", setting_id)
603
        else:
604
            cmd.add_element("name", name)
605
606
        cmd.add_element("value", to_base64(value))
607
608
        return self._send_xml_command(cmd)
609
610
    def restore(self, entity_id: str) -> Any:
611
        """Restore an entity from the trashcan
612
613
        Arguments:
614
            entity_id: ID of the entity to be restored from the trashcan
615
616
        Returns:
617
            The response. See :py:meth:`send_command` for details.
618
        """
619
        if not entity_id:
620
            raise RequiredArgument(
621
                function=self.restore.__name__, argument='entity_id'
622
            )
623
624
        cmd = XmlCommand("restore")
625
        cmd.set_attribute("id", entity_id)
626
627
        return self._send_xml_command(cmd)
628
629
    def sync_cert(self) -> Any:
630
        """Request a synchronization with the CERT feed service
631
632
        Returns:
633
            The response. See :py:meth:`send_command` for details.
634
        """
635
        return self._send_xml_command(XmlCommand("sync_cert"))
636
637
    def sync_scap(self) -> Any:
638
        """Request a synchronization with the SCAP feed service
639
640
        Returns:
641
            The response. See :py:meth:`send_command` for details.
642
        """
643
        return self._send_xml_command(XmlCommand("sync_scap"))
644