pax_global_header00006660000000000000000000000064140020177350014511gustar00rootroot0000000000000052 comment=a9f38d2e615b05c04561a9cc2d829c4e93b32ac9 gvm-tools-21.1.0/000077500000000000000000000000001400201773500135215ustar00rootroot00000000000000gvm-tools-21.1.0/.bandit000066400000000000000000000002341400201773500147620ustar00rootroot00000000000000# B410, B320: Use of defusedxml is recommended for any server code that parses untrusted XML data. We don't have server code here. skips: ['B410', 'B320'] gvm-tools-21.1.0/.circleci/000077500000000000000000000000001400201773500153545ustar00rootroot00000000000000gvm-tools-21.1.0/.circleci/config.yml000066400000000000000000000111341400201773500173440ustar00rootroot00000000000000version: 2.1 executors: python-37: docker: - image: circleci/python:3.7 working_directory: ~/repo python-38: docker: - image: circleci/python:3.8 working_directory: ~/repo python-39: docker: - image: circleci/python:3.9 working_directory: ~/repo commands: build: description: "Download and build" steps: - checkout - run: name: Install dependencies command: poetry install --no-dev build-docs: description: "Download and build the documentation" steps: - checkout - run: name: Install dependencies command: poetry install - run: name: Build docs command: cd docs && poetry run make html test: description: "Download and run tests" steps: - checkout - run: name: Install dependencies command: poetry install --no-dev - run: name: Run unit tests command: poetry run python -m unittest test-with-codecov: description: "Download and run tests with code coverage" steps: - checkout - run: name: Install dependencies command: poetry install - run: name: Install codecov command: poetry run pip install codecov - run: name: Run unit tests command: poetry run coverage run -m unittest - run: name: Upload coverage to Codecov command: poetry run codecov lint: description: "Lint python files" steps: - checkout - run: name: Install dependencies command: poetry install - run: name: Check with black command: poetry run black --check gvmtools - run: name: Run pylint command: poetry run pylint --score=n --disable=R gvmtools - run: name: Check version information command: poetry run python -m pontos.version verify current lint-scripts: description: "Lint GVM scripts" steps: - checkout - run: name: Install dependencies command: poetry install - run: name: Install additional script dependencies command: poetry run pip install -r scripts/requirements.txt - run: name: Check with black command: poetry run black --check scripts/*.gmp.py - run: name: Run pylint command: | poetry run pylint --rcfile=scripts/.pylintrc --disable=R --ignore=requirements.txt scripts/*.py deploy: description: "Upload package to PyPI" steps: - checkout - run: name: Install dependencies command: poetry install - run: name: Verify tag version command: poetry run python -m pontos.version verify ${CIRCLE_TAG} - run: name: Install twine command: poetry run pip install twine - run: name: Initialize .pypirc command: | echo -e "[distutils]" > ~/.pypirc echo -e "index-servers = pypi" >> ~/.pypirc echo -e "[pypi]" >> ~/.pypirc echo -e "username = __token__" >> ~/.pypirc echo -e "password = $PYPI_TOKEN" >> ~/.pypirc - run: name: Create and upload distribution to pypi command: | rm -rf dist build gvm_tools.egg-info poetry build poetry run twine upload dist/* jobs: lint-python-files: executor: python-38 steps: - lint lint-gvm-scripts: executor: python-38 steps: - lint-scripts build-documentation: executor: python-38 steps: - build-docs build-37: executor: python-37 steps: - build test-37: executor: python-37 steps: - test-with-codecov deploy-37: executor: python-37 steps: - deploy build-38: executor: python-38 steps: - build test-38: executor: python-38 steps: - test build-39: executor: python-39 steps: - build test-39: executor: python-39 steps: - test workflows: version: 2 build_and_test: jobs: - lint-python-files - lint-gvm-scripts - build-documentation - build-37 - test-37 - build-38 - test-38 - build-39 - test-39 build_and_deploy: jobs: - build-37: filters: tags: only: /.*/ branches: ignore: /.*/ - deploy-37: requires: - build-37 filters: tags: only: /.*/ branches: ignore: /.*/ gvm-tools-21.1.0/.coveragerc000066400000000000000000000001331400201773500156370ustar00rootroot00000000000000# Configuration for coverage.py [run] omit = tests/* source = gvmtools scripts gvm-tools-21.1.0/.github/000077500000000000000000000000001400201773500150615ustar00rootroot00000000000000gvm-tools-21.1.0/.github/CODEOWNERS000066400000000000000000000001111400201773500164450ustar00rootroot00000000000000# default reviewers * @greenbone/python-gvm-maintainers gvm-tools-21.1.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000016711400201773500175730ustar00rootroot00000000000000 ### Expected behavior ### Current behavior ### Steps to reproduce 1. 2. 3. ### GVM versions **gsa:** (gsad --version) **gvm:** (gvmd --version) **openvas-scanner:** (openvassd --version) **gvm-libs:** **gvm-tools:** (gvm-cli --version) ### Environment **Operating system:** **Installation method / source:** (packages, source installation) ### Logfiles ``` ```gvm-tools-21.1.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000015151400201773500206640ustar00rootroot00000000000000**What**: **Why**: **How**: **Checklist**: - [ ] Tests - [ ] [CHANGELOG](https://github.com/greenbone/gvm-tools/blob/master/CHANGELOG.md) Entry - [ ] Documentation gvm-tools-21.1.0/.github/dependabot.yml000066400000000000000000000003231400201773500177070ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: pip directory: "/" schedule: interval: weekly time: "04:00" open-pull-requests-limit: 10 allow: - dependency-type: direct - dependency-type: indirect gvm-tools-21.1.0/.gitignore000066400000000000000000000001211400201773500155030ustar00rootroot00000000000000__pycache__ *.pyc *.log .egg *.egg-info dist build .idea .vscode .coverage .venv gvm-tools-21.1.0/.pylintrc000066400000000000000000000347131400201773500153760ustar00rootroot00000000000000[MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist=lxml # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns=docs,.*?.gmp.py,.*?osp.py # Pickle collected data for later comparisons. persistent=yes # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # bad-continuation is disabled because of a bug in pylint. # See https://github.com/ambv/black/issues/48 and https://github.com/PyCQA/pylint/issues/289 disable=len-as-condition, attribute-defined-outside-init, missing-docstring, bad-continuation, R #disable=print-statement, # parameter-unpacking, # unpacking-in-except, # old-raise-syntax, # backtick, # long-suffix, # old-ne-operator, # old-octal-literal, # import-star-module-level, # non-ascii-bytes-literal, # raw-checker-failed, # bad-inline-option, # locally-disabled, # locally-enabled, # file-ignored, # suppressed-message, # useless-suppression, # deprecated-pragma, # apply-builtin, # basestring-builtin, # buffer-builtin, # cmp-builtin, # coerce-builtin, # execfile-builtin, # file-builtin, # long-builtin, # raw_input-builtin, # reduce-builtin, # standarderror-builtin, # unicode-builtin, # xrange-builtin, # coerce-method, # delslice-method, # getslice-method, # setslice-method, # no-absolute-import, # old-division, # dict-iter-method, # dict-view-method, # next-method-called, # metaclass-assignment, # indexing-exception, # raising-string, # reload-builtin, # oct-method, # hex-method, # nonzero-method, # cmp-method, # input-builtin, # round-builtin, # intern-builtin, # unichr-builtin, # map-builtin-not-iterating, # zip-builtin-not-iterating, # range-builtin-not-iterating, # filter-builtin-not-iterating, # using-cmp-argument, # eq-without-hash, # div-method, # idiv-method, # rdiv-method, # exception-message-attribute, # invalid-str-codec, # sys-max-int, # bad-python3-import, # deprecated-string-function, # deprecated-str-translate-call, # deprecated-itertools-function, # deprecated-types-field, # next-method-defined, # dict-items-not-iterating, # dict-keys-not-iterating, # dict-values-not-iterating # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio).You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Tells whether to display a full report or only the messages reports=no # Deactivate the evaluation score. score=no [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=optparse.Values,sys.exit [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO [BASIC] # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{1,40}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{1,40}$ # Bad variable names which should always be refused, separated by a comma bad-names=foo, bar, baz, toto, tutu, tata # Regular expression matching correct class attribute names. class-attribute-rgx=([a-z_][a-z0-9_]{1,40})|([A-Z_][A-Z0-9_]{1,30})$ # Naming style matching correct class names class-naming-style=PascalCase # Naming style matching correct constant names const-naming-style=UPPER_CASE # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=3 # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]+$ # Good variable names which should always be accepted, separated by a comma good-names=e, f, i, j, k, ex, Run, logger, _ # Include a hint for the correct naming format with invalid-name include-naming-hint=yes # Regular expression matching correct inline iteration names. inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]+$ # Regular expression which should only match correct module names module-rgx=([a-z]+)|(test_*)$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. property-classes=abc.abstractproperty # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]+$ [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format=LF # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=80 # Maximum number of lines in a module max-module-lines=1000 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma, dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [IMPORTS] # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant [DESIGN] # Maximum number of arguments for function / method max-args=15 # Maximum number of attributes for a class (see R0902). max-attributes=20 # Maximum number of boolean expressions in a if statement max-bool-expr=5 # Maximum number of branch for function / method body max-branches=12 # Maximum number of locals for function / method body max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=30 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of statements in function / method body max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=0 [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception gvm-tools-21.1.0/CHANGELOG.md000066400000000000000000000371161400201773500153420ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). For detailed code changes, please visit https://github.com/greenbone/gvm-tools/commits/master or get the entire source code repository and view log history: ```sh $ git clone https://github.com/greenbone/gvm-tools.git $ cd gvm-tools && git log ``` ## [21.1.0] - 2021-01-20 ### Added * Added `pretty_print` to `pyshell` by default, so it does not need to be manually imported [#305](https://github.com/greenbone/gvm-tools/pull/305) * Added tests for `helper` module [#310](https://github.com/greenbone/gvm-tools/pull/310) * Added tests for `parser` module [#311](https://github.com/greenbone/gvm-tools/pull/311) * Added tests for `scripts/send-target.gmp.py` [#314](https://github.com/greenbone/gvm-tools/pull/314/) * Added tests for `scripts/send-tasks.gmp.py` [#317](https://github.com/greenbone/gvm-tools/pull/317) * Added tests for `scripts/send-schedules.gmp.py` [#344](https://github.com/greenbone/gvm-tools/pull/344) * Added tests for `script/start-alert-scan.gmp.py` [#344](https://github.com/greenbone/gvm-tools/pull/344) * Adding useful script helper functions to the `helper.py` [#317](https://github.com/greenbone/gvm-tools/pull/317) * CI tests Python 3.9 now. [#353](https://github.com/greenbone/gvm-tools/pull/353) * Added tests for `script/combine-reports.gmp.py` [#366](https://github.com/greenbone/gvm-tools/pull/366) ### Changed * The `script/start-alert-scan.gmp.py` has been reworked with argparser [#344](https://github.com/greenbone/gvm-tools/pull/344) * Moved generic functions to generate random ids and ips from scripts to the `helper` module. [#365](https://github.com/greenbone/gvm-tools/pull/365) ### Deprecated * Dropped Python 3.5 and Python 3.6 support. Python 3.7+ is required now. [#353](https://github.com/greenbone/gvm-tools/pull/353) ### Fixed * Fixed the `send-targets.gmp.py` script. [#313](https://github.com/greenbone/gvm-tools/pull/313) * Fixed the `pdf-report.gmp.py` script when an empty report is downloaded [#328](https://github.com/greenbone/gvm-tools/pull/328) * Fixed the `combine-reports.gmp.py` script, the `import_report()` command changed since v9.0. [#366](https://github.com/greenbone/gvm-tools/pull/366) [21.1.0]: https://github.com/greenbone/gvm-tools/compare/v20.10.1...v21.1.0 ## [20.10.1] - 2020-10-06 ### Fixed - Reverted changes in the dependency that causes CI failures. [20.10.1]: https://github.com/greenbone/gvm-tools/compare/v20.10.0...HEAD ## [20.10.0] - 2020-10-05 ### Changed - Fixed `send-schedule.gmp.py` script, because has been [removed](https://github.com/greenbone/gvmd/commit/d4a0fa2287b425199330b7e5671b61cdbd836fe4) from Schedules, using instead. [#299](https://github.com/greenbone/gvm-tools/pull/299) - Fixed `send-targets.gmp.py` script, because alive_test needs to be from `AliveTest` enum in `create_target` function. [#297](https://github.com/greenbone/gvm-tools/pull/297) - Added gmpv20.08 support to the `scan-new-system.gmp.py` script, as `create_target` requires an argument `port_range` or `port_list_id` now. [#295](https://github.com/greenbone/gvm-tools/pull/295) - Using the `--log` argument is not casesensitive anymore. Use the lower-case or upper-case loglevel as the argument now.[PR 276](https://github.com/greenbone/gvm-tools/pull/276) ### Fixed - Fixed the `check-gmp.gmp.py` script, as it was not compatible to Python 3.5 anymore. [PR 280](https://github.com/greenbone/gvm-tools/pull/280) - Fixed the `check-gmp.gmp.py` script: results have not been loaded with `-F host -T task --status` and probably some other cases. Added `details=True` to the command that requests the report. [PR 280](https://github.com/greenbone/gvm-tools/pull/280) - Fixed the `pdf-report.gmp.py` script. Joining the Content of the tag was not the correct way here ... we needed the tail of the `` tag ... [PR 301](https://github.com/greenbone/gvm-tools/pull/301) ### Removed * Removed `gvm.version` module in favor of using `pontos.version` [#254](https://github.com/greenbone/gvm-tools/pull/254) [20.10.0]: https://github.com/greenbone/gvm-tools/compare/v2.1.0...v20.10.0 ## [2.1.0] - 2020-04-03 ### Added - Allow to specify hostname for SSH and TLS connections in the config file [#239](https://github.com/greenbone/gvm-tools/pull/239) ### Changed - The script `random-report-gen.gmp` is able to add `host`, `host details`, `os` and `application` data now, so the created reports are more realistic [PR 218](https://github.com/greenbone/gvm-tools/pull/218), [PR 220](https://github.com/greenbone/gvm-tools/pull/220) [PR 225](https://github.com/greenbone/gvm-tools/pull/225) - The script `random-report-gen.gmp` now uses argparser, to improve its usage [PR 223](https://github.com/greenbone/gvm-tools/pull/223) - Use .py ending for all gmp scripts to support auto highlighting [PR 244](https://github.com/greenbone/gvm-tools/pull/244) - Updated glossary in the documentation to reflect changes in GVM 11 [PR 245](https://github.com/greenbone/gvm-tools/pull/245) - Replaced `pipenv` with `poetry` for dependency management. `poetry install` works a bit different then `pipenv install`. It installs dev packages by default and also gvmtools in editable mode. This means after running `poetry install` all gvm-tools scripts are available in the created virtual environment. [PR 246](https://github.com/greenbone/gvm-tools/pull/246) - Fixed version handling after switching to poetry [#249](https://github.com/greenbone/gvm-tools/pull/249) ### Fixed - Exit with an error, if the `check_gmp.gmp` script is used with an temporary path, that has not the correct permissions. - Fixed `update-task-target.gmp` to create unique target names to support Gmpv8 - Fixed an error, where the `--sockpath` argument didn't worked as expected [PR 216](https://github.com/greenbone/gvm-tools/pull/216) - Catch exception from gvm lib [PR 222](https://github.com/greenbone/gvm-tools/pull/222) [PR 224](https://github.com/greenbone/gvm-tools/pull/224) - Fixed `send-targets.gmp` throwing an exception due to an improper check [PR 248](https://github.com/greenbone/gvm-tools/pull/248) - Fixed `send-targets.gmp` : `hosts` and `exclude_hosts` expecting lists [PR 248](https://github.com/greenbone/gvm-tools/pull/248) [2.1.0]: https://github.com/greenbone/gvm-tools/compare/v2.0.0...v2.1.0 ## [2.0.0] - 2019-09-19 ### Added - Added --duration switch to gvm-cli for command execution measurement [PR 206](https://github.com/greenbone/gvm-tools/pull/206) - Added --ssh-password switch for ssh connection [PR 140](https://github.com/greenbone/gvm-tools/pull/140) - Added a new console line interface `gvm-script` for only running GMP and OSP scripts without opening a python shell [PR 152](https://github.com/greenbone/gvm-tools/pull/152) - Forbid to run any gvm-tools cli as root user [PR 183](https://github.com/greenbone/gvm-tools/pull/183) - Added error message if invalid XML is passed to `gvm-cli` [PR 198](https://github.com/greenbone/gvm-tools/pull/198) - Added argument `--pretty` to `gvm-cli` to pretty format xml output [PR 203](https://github.com/greenbone/gvm-tools/pull/203) ### Changed - Improved error messages if unix socket could not be found [PR 78](https://github.com/greenbone/python-gvm/pull/78) - The structure for the config file (default is ~/.config/gvm-tools.conf) has changed. It's possible to set defaults for nearly all command line arguments [PR 140](https://github.com/greenbone/gvm-tools/pull/140) - The command line help for `gvm-cli` and `gvm-pyshell` has been updated and made more consistent [PR 138](https://github.com/greenbone/gvm-tools/pull/138) - Renamed --ssh-user switch to --ssh-username [PR 140](https://github.com/greenbone/gvm-tools/pull/140) - Update `gvmtools.get_version` to return a fully compliant [PEP 440](https://www.python.org/dev/peps/pep-0440/) version string [PR 150](https://github.com/greenbone/gvm-tools/pull/150) - Refresh the dependencies specified via the `Pipfile.lock` file to their latest versions [PR 186](https://github.com/greenbone/gvm-tools/pull/186), [PR 193](https://github.com/greenbone/gvm-tools/pull/193) - Dropped global command line arguments from sub commands e.g. it must be `gvm-cli --config foo.conf socket ...` instead of `gvm-cli socket --config foo.conf` now. The latter didn't work actually but was listed in the `--help` output [#194](https://github.com/greenbone/gvm-tools/pull/194) - Improved error message if a global argument is passed after the connection type to `gvm-cli` [#196](https://github.com/greenbone/gvm-tools/pull/196) - Renamed `clean-slave.gmp` to `clean-sensor.gmp` [PR 202](https://github.com/greenbone/gvm-tools/pull/202) ### Deprecated - Only running scripts with gvm-pyshell is deprecated [PR 152](https://github.com/greenbone/gvm-tools/pull/152) - \[Auth\] section in config file is deprecated and will be ignored in future releases [PR 160](https://github.com/greenbone/gvm-tools/pull/160) ### Fixed - Fix a bug which caused `gvm-pyshell` to immediately re-enter interactive mode upon exiting it for the first time [PR 139](https://github.com/greenbone/gvm-tools/pull/139) - Support \[Auth\] section in config file for backwards compatibility [PR 160](https://github.com/greenbone/gvm-tools/pull/160) - Fix using correct API to get single task and targets in update-task-target.gmp script [PR 188](https://github.com/greenbone/gvm-tools/pull/188) [2.0.0]: https://github.com/greenbone/gvm-tools/compare/v2.0.0.beta1...v2.0.0 ## [2.0.0.beta1] - 2018-11-13 gvm-tools got split into the command line interfaces (*gvm-cli* and *gvm-pyshell*) including the [gmp (example) scripts](https://github.com/greenbone/gvm-tools/tree/master/scripts) and the Python API. The Python API can now be found at [python-gvm](https://github.com/greenbone/python-gvm). During this split the python package name for the API got changed from **gmp** to **gvm**. The API has also been refactored and stabilized. For details please take a look at [python-gvm](https://github.com/greenbone/python-gvm) [PR 126](https://github.com/greenbone/gvm-tools/pull/126). ### Added - It's now possible to write OSP scripts. Using the `--protocol=OSP` switch `gvm-pyshell` adds a global **osp** object instead of the **gmp** one. - Added new client helper module. - It's possible to get the current versions of gvm-tools via `__version__` and python-gvm via `__api_version__` [PR 127](https://github.com/greenbone/gvm-tools/pull/127) - Use pipenv for development. ### Changed - The `__name__` variable is set to `__gmp__` for GMP scripts and to `__osp__` for OSP scripts *(Remember: for normal Python scripts `__name__` is set to [`__main__`](https://docs.python.org/3/library/__main__.html))*. - Scripts are only getting two global variables now: **gmp** (or **osp**) and **args**. **gmp** and **osp** are the global objects to communicate with the remote *gvmd* or *ospd* daemon. **args** contains the parsed arguments for the script. - The global **args** object only contains script related parameters now. These username and password from the `--gmp-username` and `--gmp-password` switches and the additional scripts parameters as `args.argv`. - **GMPError** got renamed to **GvmError** and must be imported from `gvm.errors` module. ```python from gvm.errors import GvmError as GMPError ``` - pretty function isn't available as a global function in the scripts anymore. It must be imported separately like ```python from gvmtools.helper import pretty_print as pretty ``` - The included [gmp scripts](https://github.com/greenbone/gvm-tools/tree/master/scripts) have been cleaned up and adjusted for the new API. ### Removed - Removed experimental `gvm-dialog` application. ## [1.4.1] - 2018-08-10 This is the first maintenance release of the gvm-tools module 1.4 for the Greenbone Vulnerability Management (GVM) framework. This release covers bug fixes in 'create' and 'modify' methods. Many thanks to everyone who has contributed to this release: Raphael Grewe, Juan Jose Nicola and Jan-Oliver Wagner Main changes compared to gvm-tools-1.4.0: - Fix bugs for create and modify command methods. - Improve unit tests. - Improve documentation. ## [1.4.0] - 2018-08-09 This is the first release of the gvm-tools module 1.4 for the Greenbone Vulnerability Management (GVM) framework. This release covers bug fixes, robustness improvements and an extended GMP scripts collection. Many thanks to everyone who has contributed to this release: Raphael Grewe, Mirko Hansen, Henning Häcker, David Kleuker, Juan Jose Nicola, Timo Pollmeier, Bjoern Ricks, Joshua Schwartz, Jan-Oliver Wagner and Michael Wiegand. Main changes compared to gvm-tools-1.3.1: - Correct XML encoding for commands - Fix bug for long GMP commands through SSHConnection - Add new GMP scripts: create\_targets\_from\_host\_list.gmp, gen-random-targets.gmp, send-schedules.gmp, send-targets.gmp, send-tasks.gmp, send\_delta\_emails.gmp, startAlertScan.gmp, update-task-target.gmp. - Improve and extend 'create' and 'modify' command methods - Add support for accessing the raw response - Improve unit tests - Allow anonymous connections - Require lxml and defusedxml python modules - Improve documentation - Several code improvements ## [1.3.1] - 2017-12-14 - Improved stability with ssh connections again ## [1.3.0] - 2017-12-12 - Improved stability with ssh connections - Fixed bugs for create\_target command - Fixed some typos - Added correct license file - Improved setup (Only Python3 is allowed) ## [1.2.0] - 2017-08-04 - Improved feature to read from config file for gvm-cli - Added feature to read from config file for gvm-pyshell - Added feature to disable timeout on sockets for all clients - Added new script to delete overrides by filter - Removed requirement for username in gvm-cli - Minor code improvement ## [1.1.0] - 2017-06-28 - Fixed hgignore file (Ignored important file) - Fixed choice decision for the connectiontype - Fixed quote bug in gvm\_connection.py - Changed quit function to sys.exit of non interactively used python files (f.e. scripts) - Changed path of unixsocket from openvasmd.sock to gvmd.sock - Added timeout functionality to all connection types - Added GPL v3 licenses in all relevant files - Added function create\_report - Added new script to sync tasks between to gsm - Added new script to sync assets from a csv list - Added experimental client gvm-dialog again ## [1.0.3] - 2017-06-01 - Fixed wrong library path ## [1.0.2] - 2017-06-01 - Changed directory structure and names, because of the generic names for python modules - Directory libs is named gmp - Directory clients is copied into gmp ## [1.0.1] - 2017-06-01 - Changed name to gvm-tools - Bugfixes at the scripts - Added new script to create dummy data for gsm ## [1.0] - 2017-05-31 - First stable release of gvm-tools [2.0.0.beta1]: https://github.com/greenbone/gvm-tools/compare/v1.4.1...v2.0.0.beta1 [1.4.1]: https://github.com/greenbone/gvm-tools/compare/v1.4.0...v1.4.1 [1.4.0]: https://github.com/greenbone/gvm-tools/compare/1.3.1...v1.4.0 [1.3.1]: https://github.com/greenbone/gvm-tools/compare/1.3.0...1.3.1 [1.3.0]: https://github.com/greenbone/gvm-tools/compare/1.2.0...1.3.0 [1.2.0]: https://github.com/greenbone/gvm-tools/compare/1.1.0...1.2.0 [1.1.0]: https://github.com/greenbone/gvm-tools/compare/1.0.3...1.1.0 [1.0.3]: https://github.com/greenbone/gvm-tools/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/greenbone/gvm-tools/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/greenbone/gvm-tools/compare/1.0...1.0.1 [1.0]: https://github.com/greenbone/gvm-tools/releases/tag/1.0 gvm-tools-21.1.0/LICENSE000066400000000000000000001045051400201773500145330ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . gvm-tools-21.1.0/MANIFEST.in000066400000000000000000000000711400201773500152550ustar00rootroot00000000000000include scripts/* include README.md include CHANGELOG.md gvm-tools-21.1.0/README.md000066400000000000000000000147631400201773500150130ustar00rootroot00000000000000![Greenbone Logo](https://www.greenbone.net/wp-content/uploads/gb_logo_resilience_horizontal.png) # Greenbone Vulnerability Management Tools [![GitHub releases](https://img.shields.io/github/release-pre/greenbone/gvm-tools.svg)](https://github.com/greenbone/gvm-tools/releases) [![PyPI release](https://img.shields.io/pypi/v/gvm-tools.svg)](https://pypi.org/project/gvm-tools/) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/greenbone/gvm-tools/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/greenbone/gvm-tools/?branch=master) [![code test coverage](https://codecov.io/gh/greenbone/gvm-tools/branch/master/graph/badge.svg)](https://codecov.io/gh/greenbone/gvm-tools) [![CircleCI](https://circleci.com/gh/greenbone/gvm-tools/tree/master.svg?style=svg)](https://circleci.com/gh/greenbone/gvm-tools/tree/master) The Greenbone Vulnerability Management Tools `gvm-tools` are a collection of tools that help with remote controlling a Greenbone Security Manager (GSM) appliance and its underlying Greenbone Vulnerability Manager (GVM). The tools aid in accessing the communication protocols GMP (Greenbone Management Protocol) and OSP (Open Scanner Protocol). This module is comprised of interactive and non-interactive clients. The programming language Python is supported directly for interactive scripting. But it is also possible to issue remote GMP/OSP commands without programming in Python. ## Table of Contents - [Documentation](#documentation) - [Installation](#installation) - [Requirements](#requirements) - [Install using pip](#install-using-pip) - [Usage](#usage) - [gvm-cli](#gvm-cli) - [Example program use](#example-program-use) - [gvm-script](#gvm-script) - [Example script](#example-script) - [More example scripts](#more-example-scripts) - [gvm-pyshell](#gvm-pyshell) - [Example program use](#example-program-use-1) - [Support](#support) - [Maintainer](#maintainer) - [Contributing](#contributing) - [License](#license) ## Documentation The documentation for `gvm-tools` can be found at [https://gvm-tools.readthedocs.io/](https://gvm-tools.readthedocs.io/). Please refer to the documentation for more details as this README just gives a short overview. ## Installation See the [documentation](https://gvm-tools.readthedocs.io/en/latest/install.html) for all supported installation options. ### Version Please consider to always use the **newest** version of `gvm-tools` and `python-gvm`. We freqently update this projects to add features and keep them free from bugs. This is why installing `gvm-tools` using pip is recommended. The current release of `gvm-tools` can be used with all supported GOS versions. ### Requirements Python 3.7 and later is supported. ### Install using pip You can install the latest stable release of gvm-tools from the Python Package Index using [pip](https://pip.pypa.io/): pip install --user gvm-tools ## Usage There are several clients to communicate via GMP/OSP. All clients have the ability to build a connection in various ways: * Unix Socket * TLS Connection * SSH Connection ### gvm-cli This tool sends plain GMP/OSP commands and prints the result to the standard output. #### Examples Return the current protocol version used by the server: ``` gvm-cli socket --xml "" ``` Return all tasks visible to the GMP user with the provided credentials: ``` gvm-cli --gmp-username foo --gmp-password bar socket --xml "" ``` Read a file with GMP commands and return the result: ``` gvm-cli --gmp-username foo --gmp-password bar socket < myfile.xml ``` Note that `gvm-cli` will by default print an error message and exit with a non-zero exit code when a command is rejected by the server. If this kind of error handling is not desired, the unparsed XML response can be requested using the `--raw` parameter: ``` gvm-cli socket --raw --xml "" ``` ### gvm-script This tool has a lot more features than the simple `gvm-cli` client. You have the possibility to create your own custom gmp or osp scripts with commands from the [python-gvm library](https://github.com/greenbone/python-gvm) and from Python 3 itself. #### Example script ``` # Retrieve current GMP version version = gmp.get_version() # Prints the XML in beautiful form from gvmtools.helper import pretty_print pretty_print(version) # Retrieve all tasks tasks = gmp.get_tasks() # Get names of tasks task_names = tasks.xpath('task/name/text()') pretty_print(task_names) ``` #### More example scripts There is a growing collection of gmp-scripts in the ["scripts/"](scripts/) folder. Some of them might be exactly what you need and all of them help writing your own gmp scripts. ### gvm-pyshell This tool is for running gmp or osp scripts interactively. It provides the same API as [gvm-script](#gvm-script) using the [python-gvm library](https://github.com/greenbone/python-gvm). #### Example program use Connect with given credentials via a unix domain socket and open an interactive shell: ``` gvm-pyshell --gmp-username user --gmp-password pass socket ``` Connect through SSH connection and open the interactive shell: ``` gvm-pyshell --hostname 127.0.0.1 ssh ``` ## Support For any question on the usage of `gvm-tools` or gmp scripts please use the [Greenbone Community Portal](https://community.greenbone.net/c/gmp). If you found a problem with the software, please [create an issue](https://github.com/greenbone/gvm-tools/issues) on GitHub. ## Maintainer This project is maintained by [Greenbone Networks GmbH](https://www.greenbone.net/). ## Contributing Your contributions are highly appreciated. Please [create a pull request](https://github.com/greenbone/gvm-tools/pulls) on GitHub. For bigger changes, please discuss it first in the [issues](https://github.com/greenbone/gvm-tools/issues). For development you should use [poetry](https://python-poetry.org/) to keep you python packages separated in different environments. First install poetry via pip pip install --user poetry Afterwards run poetry install in the checkout directory of `gvm-tools` (the directory containing the `pyproject.toml` file) to install all dependencies including the packages only required for development. Afterwards active the git hooks for auto-formatting and linting via [autohooks](https://github.com/greenbone/autohooks). poetry run autohooks activate --force ## License Copyright (C) 2017-2021 [Greenbone Networks GmbH](https://www.greenbone.net/) Licensed under the [GNU General Public License v3.0 or later](LICENSE). gvm-tools-21.1.0/RELEASE.md000066400000000000000000000106201400201773500151220ustar00rootroot00000000000000# Release instructions Before creating a new release please do a careful consideration about the version number for the new release. We are following [Semantic Versioning](https://semver.org/) and [PEP440](https://www.python.org/dev/peps/pep-0440/). ## Preparing the Required Python Packages * Install twine for pypi package uploads and update poetry ```sh python3 -m pip install --user --upgrade twine poetry ``` ## Configuring the Access to the Python Package Index (PyPI) *Note:* This is only necessary for users performing the release process for the first time. * Create an account at [Test PyPI](https://packaging.python.org/guides/using-testpypi/). * Create an account at [PyPI](https://pypi.org/). * Create a pypi configuration file `~/.pypirc` with the following content (Note: `` must be replaced): ```ini [distutils] index-servers = pypi testpypi [pypi] username = [testpypi] repository = https://test.pypi.org/legacy/ username = ## Prepare testing the Release * Fetch upstream changes and create release branch ```sh git fetch upstream git checkout -b create-new-release upstream/master ``` * Get the current version number ```sh poetry run python -m pontos.version show ``` * Update the version number to some alpha version e.g. ```sh poetry run python -m pontos.version update 1.2.3a1 ``` ## Uploading to the PyPI Test Instance * Create a source and wheel distribution: ```sh rm -rf dist build gvm_tools.egg-info poetry build ``` * Upload the archives in `dist` to [Test PyPI](https://test.pypi.org/): ```sh twine upload -r testpypi dist/* ``` * Check if the package is available at . ## Testing the Uploaded Package * Create a test directory: ```sh mkdir gvm-tools-install-test cd gvm-tools-install-test python3 -m venv test-env source test-env/bin/activate pip install -U pip # ensure the environment uses a recent version of pip pip install --pre -I --extra-index-url https://test.pypi.org/simple/ gvm-tools ``` * Check install version with a Python script: ```sh python3 -c "from gvmtools.__version__ import __version__; print(__version__)" ``` * Remove test environment: ```sh deactivate cd .. rm -rf gvm-tools-install-test ``` ## Prepare the Release * Determine new release version number If the output is something like `1.2.3.dev1` or `1.2.3a1`, the new version should be `1.2.3`. * Update to new version number (`` must be replaced by the version from the last step) ```sh cd path/to/git/clone/of/gvm-tools poetry run python -m pontos.version update ``` * Update the `CHANGELOG.md` file: * Change `[unreleased]` to new release version. * Add a release date. * Update reference to Github diff. * Remove empty sub sections like *Deprecated*. * Create a git commit ```sh git add . git commit -m "Prepare release " ``` ## Performing the Release on GitHub * Create a pull request (PR) for the earlier commit: ```sh git push origin ``` Open GitHub and create a PR against . * Ask another developer/maintainer to review and merge the PR. * Once the PR is merged, update the local `master` branch: ```sh git fetch upstream git rebase upstream/master master ``` * Create a git tag: ```sh git tag v ``` Or even a tag signed with a personal GPG key: ```sh git tag --sign --message "Tagging the release" v ``` * Push changes and tag to Github: ```sh git push --tags upstream ``` ## Uploading to the 'real' PyPI * Uploading to PyPI is done automatically by pushing a git tag via CircleCI * Check if new version is available at . ## Bumping `master` Branch to the Next Version * Update to a Development Version The next version should contain an incremented minor version and a dev suffix e.g. `2.3.0.dev1`. For example, if the released version was `1.2.3`, it should be changed to `1.3.0.dev1`. ```sh poetry run python -m pontos.version update ``` * Create a commit for the version bump: ```sh git add . git commit -m "Update version after release" git push upstream ``` ## Announcing the Release * Create a Github release: See https://help.github.com/articles/creating-releases/ gvm-tools-21.1.0/docs/000077500000000000000000000000001400201773500144515ustar00rootroot00000000000000gvm-tools-21.1.0/docs/Makefile000066400000000000000000000011041400201773500161050ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SOURCEDIR = . BUILDDIR = build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) gvm-tools-21.1.0/docs/_static/000077500000000000000000000000001400201773500160775ustar00rootroot00000000000000gvm-tools-21.1.0/docs/_static/custom.css000066400000000000000000000000761400201773500201260ustar00rootroot00000000000000div.sphinxsidebarwrapper p.description { font-size: 12px; } gvm-tools-21.1.0/docs/_static/greenbone.png000066400000000000000000000243261400201773500205600ustar00rootroot00000000000000PNG  IHDRG7KiTXtXML:com.adobe.xmp I: IDATxwx- HB$!4APr$VTDxQ,UQ (( @P )$ef?ffIvMgdgΜ~y{,Puǟc\={oE™,2//4dGH=W׫~d@nݤGޑCoL_UC^  AqN8s3=8ºd߾="~; )lty*:?U #Mq%cǏ:ӀFjv`={<'҇OY=+0Bs5ch8㧶4㷣eWa#xgk|ӱd4m11A*{7d;'4TS;LO;@D!'V#o(i`#Ǧ']N~i @@Cݏ?5P+- 0ԈNAs@aϾ^u3@TV\,QfS]qN^}9S_i{(`$UHU/d HHIOKxӉt52=%=m~GLvhY{M4k@( Ϧx;=xuq/ 8&q4kz?^Mnvncfm :Wa7aMJos@ "NM8y݈A2kEO`fdD@'Q/ŪPZv2`BQ 4Dcwߙrl%l oI n 3萙ug*` q8MìX2֝|@!x-F&ߚ3[6@tx!e3m";ܷCxhҼ:@Nd-ٷIҳ>?s 딌b ?XL,|9xܔ/ٳ:AD@ҝ34qŗ͚9չ9ZMF ^h(&]wQ~7Wc e4z\Ge /[$6 S̚7Nt:]^VgotD6Z_H F@ͯFF*;e8>9%=mq.HJzPM8e ӹ>%=-ZY1QʯZՁmdb~%jy>4{#/+:zyPt`}\68"ю(*h72`ԉƙS4nҙcpۣݑɪwH}euTȉ("WFsN0|U8ҡVQOwTV0/:"r~JztLU<\cJBtD$w N2p'L&f>U]eVݨ]拷3g^ Xj3%-kѲI,J<L"D_ƾq#gvØPDyTvWsF͇㣀mjt/,GtDdy2`xB J=q̕NU a{jXY KAq6Bڹf#51^ttcajeEBЀDtN\MKvgw&}}},\>.\g/ڗ~aϧxڐ<9ս-:僯ˬ^Ə6 9sڟ9"s 8Ur\&AFmg;F2%PuA^嗔P`+&xU/DGDN+^%S6 :W `:9%=MPmW_5_銚qTS(vlpWSdU[oO5|u.vWm)elrlE`\.ENrTG'CHdd}Kʮkw7Ck,je闒^y:J(OIOlLT&u?= F4ŵ`˟b7霒6]~nhPk_AM5ZC}OM܀៾ޜξ3!'Åe Uxv1@]b. 2>oScq72t_șs%U GPrTW1scuwQ#P56u>qߝ7zۉ;Ͼ2FA$P'"b 28ȶi$٦M#hI#\~ '{~ӡWovxO¦2zcD%MvYJFtvo' n,R* DppCKe(9S҈Ōy|#/^J?ъfAϿneUa#Kh6,.@4'9}'~;i`!߮'߮Wa"BQG$r Xd,pbW7{e_ӽZ~|tDdTm'm5p h_ǷԸ"nO{DuiktIאkՓ^\BFz^~8gOB~ #"< @IV~bI*AC# K /6?*+fxɾ.5}rraET K9weN[mgB R"!lGH/  Kdt2%DU{-D$o5{#uĝzYy M*suOSYC־CEYQ~M}߷KʮXI魔fGqGj@mX5]G3Yɛ7\ GBI8 2`phVYs KVnp _5>xǬkZ눻D*Og\vP_y1\ɸ9WEʳ[$lΞΎO^ KWTiE'8kbnf.lvӵ{Y὏Oǖer- ~\!X/ 1.sK0O" 1ޅ㩧%^]E[NwNT'M;yJUB~^Lh6wy5Wxj+l Bd"M}e dfeԠGl,Vxcy]z".c\k5$r攎%BIdz]{tbcH֩ܽ`+yPמּ~X9ze>UO+Yq=U=ph/ȪɃy(&E}YM϶'Uߏ"QO.6 *Qu&%=mjvRӺO(}_W:MRUim6W#mW9=O_N.u Nv;y쿖 6sڗe&Ȳg딶n{kS9^ҎJ Xdz<1x)'(N udG\*-]3lTgҪxZt+i@DM "!_[wkE5AhCum{ț>(uAkCOqrmdq7X_K ;e2MB^@Xn& T)R?kS5'4R*_K%IǨZآf2K۳!@dB'(/-|haxԍ#~cld[sm)4Eyiٵ' f}7Dr[ڌn=D EŢޅ dmE͂h8[JAv-Ή?~'Mt^,EP(&q.O1RN%B;Ǐ5oI3f=ts`Vd VD] Mp&KGL$J$zǶVIH9fB[/_{bYG+%U+bQ\[Gc%_Vzo֮r*=ǏGFU)l.F5m|EȰtɩLvP3 2F vnWKuH@sHjHZW]CpFE!(adej8灗뽧Ǐ3%`4=Fg-IEdZrлXSrmzDvFTMO2crtϏ$n zB\/yؿhe|e- 7ǾCH%tU|9$oltssbѡm0tB ?2ݻvvS;a_oy/be(_'_G]Of6 v47ٱʂGDѾw)Mt]priZ+FdGh̓ 42FdN% 9E*19~:};:.HYyDܰ;diJ,\V䜅><;!@" ri/w a hϝDJPZp86eI3Ÿ0. tyvF{wU_G7?~.ੰ3!t\XЈ2d "'3,63J`0nl= gJT9L~+R*Xedxnwv&e|C݃rf7;̿}3(df}& !z 'mzOƊk fՖ"C8&$=WC!L .+!D&E|4GY{͹ |< &? !O=͸`ZN Iڔ$ P'Xd>~GJii>Lʮ{0~ٹMLE邰Ws$^P 773Nf}ʡoQlvl3oP!|2N}LϥHt]^P@QdKD;8nBە# l$؛Д"Q L/qp `IBywk7a3%9F4x yv[8s9ZM&H@+zܶ}1ǜPVs,LO>v zR.?}ӻտ4x/>gOJti)]~<#zYpt/H>篔HΔ(C3ȑdۖ(;;Aeߙ>ݯEed9i`ű"V / _o~<¸kl3 ġ`q8}QE=F/e5(F{Py]P@ߘ>{eZ :tH.ddtyA>ТPDFa,K:H1F[e(C#rkgopa&o-@M$@!zї5}<<\ 96eh]+9))qTCŭ:u(^3XvM*9viIIuכͱQʦⶖy(;MOJJɮ] |aKo7tUxRI$d]h߫W Je [s7x9/_~;xw$ewD,(.(+vLzE]93ji/`6Fp~jHHJJ͖1T󟄻263c;'%%zć߾ _~ըb29]j#H'c;6 BLa G$Ѧ`DNGsp+O؋d?'f1~Q9>Okۏةя"q.1y{b#N M"'SP'#L¾>D;/G푸^yN({z;5׿} .R" z.<Ÿ㉠fdB"IGZ-KSfG˧Wo@=я)?*[ cń3ˣʍ(R 0CexgZi#9QI(ov9_uTk jk5Wo96\N}yK3X 6::Bvtf d;wlny3'GcæO)3}ls,Z92oE,{ lnZDr^ PL1՚fpd;1))Q]e&%%ƫ pefs2Pfsv֍p~RRz5cII{mazMC<`TRRb{SZ!\Uf5#p9簫…mv7d5U7'Uz +ka*pb:Tw:Svg\خWfsl*J}Vm] S|}}f kWfXpYܶh¤CA3y :Et`æPM(Lq7jV<>E:PhHjF5|մ0dxln2"ac]Dp>tk6Ǯ3c'j_ZEw~_k·97<ʎހcd*3c=9l$廊?N6N* +22!1l|hTӼVFrag˜|񖖴ʆJ:~tP.s?LJ鯄N2RŖlN=KGѥU?6| %%dGYr!͚7ۆ LS+G9m@HVi*|L:6&;x{L"u'mNZQ~GQȝ1k&'%% jӓmӓ;kTͩ󻔷Yxrp80W׾l΂3дB8;Wa$;ה2;SuUT-]@?xVfs] &RUOOT?ZMwWKt5MiE{ЯBWpS]+ax򙉛p˟EM)r:$~O3JyLL~ػ޽ ݿٖL΋"azf&ďزd 7ƎOA vV q(ZD(zgǧ;_j0n0l* 1j8P3pjIIyfsleU|S^:ǧ6Zd*GMsuVhR> ^?9煻 +w~yE?2Y^Ũ鯄![σbnܴ;y|]m{=)|\>ݯߠ;曀OsXTI6,Œ(C;AU336:IDATn1aG-%ӝTRPPM=Fk_8pKU*T}64W5SVѧQ=Ěf?Q(]IN C;HY(v\j~:7եw?|cVop^KZu6a.y+,$E:bIGvTձHJJLp$5_~]XOMT4zs"gaT3;O^g'hG:3ߓ9FΚ2lŮ0QqP>ڱ6պG@20tΝ5g_xy1f~ىpDͽPf~/0Or6+>\'7rancm v7Cce\~ȱqn((j5Kt2_,ٻ pㄻ[Qe40jspWĨ#1(Rw=^uL}ĨT+u^B܆jq^5MT]jJPִm4Fƭ) (&lsJPksVZ|QT*hR!mq"\4A^&vXGWVM6^;X={33_?xwM\,H(q,{Eu%=/U}2wa׎ |njx>Wlp?vO4r$?c%vp(rP͇r!@yTוFùaj~NTCVq&VyI{#&8U w*tnhT:5XŮEMb4O.2Sjʧ*]\M+i(yVM-Zm[5(QNii K4743#Rʴ/{JAӻ뵪iu1 2&IPF瑸T~.OWvN#^WTNF Qg(Wi`Y! -߮g=nQHsz_t py"~~)|D ] &( d$~p-,Kk p#ELz ou*R%;:e6pA6-6XE+4b6ߩ j|nNNn#\yzCo/z'[z8M*hS,7{ osbe}IPkn}ANQpm[Cu?~ԜZ [ڵ}ࣇEXJ\5{Gk"'Bm\w3c-_4h&X| 6c&z6ӴP.zsʤ~ǏRkaSSNپ}/PXi SG1b2-"NJE첌QPij-6'(K鞍1MrI?~z6r]c~1{f6F bY @iilJ:+}\}^1}z=r~)*lxC_t .haE`Hɳ:6~w5Wo|{JzIs]!ѣмeȅ\G~:-;>_Wv|Q=Ǐ 5;Ft*hҨQQ rS=4v|AŽ=ŝ?/+IENDB`gvm-tools-21.1.0/docs/_templates/000077500000000000000000000000001400201773500166065ustar00rootroot00000000000000gvm-tools-21.1.0/docs/_templates/sidebarlogo.html000066400000000000000000000005041400201773500217650ustar00rootroot00000000000000

{{ project }}

Remote Control of Your Greenbone Vulnerability Manager (GVM)

gvm-tools-21.1.0/docs/conf.py000066400000000000000000000131761400201773500157600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # pylint: disable=invalid-name,redefined-builtin,wrong-import-position import os import sys sys.path.insert(0, os.path.abspath('..')) import gvmtools # -- Project information ----------------------------------------------------- project = 'gvm-tools' copyright = '2018-2020, Greenbone Networks GmbH' author = 'Greenbone Networks GmbH' version = gvmtools.get_version() release = version # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.githubpages', 'sphinx.ext.napoleon', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['build'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' html_favicon = 'favicon.gif' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = { 'github_user': 'greenbone', 'github_repo': 'gvm-tools', 'github_banner': True, 'show_powered_by': False, } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} html_sidebars = { '**': [ 'sidebarlogo.html', 'localtoc.html', 'relations.html', 'searchbox.html', ] } html_show_sourcelink = False # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'gvm-toolsdoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ( master_doc, 'gvm-tools.tex', 'gvm-tools Documentation', 'Greenbone Networks GmbH', 'manual', ) ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [(master_doc, 'gvm-tools', 'gvm-tools Documentation', [author], 1)] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( master_doc, 'gvm-tools', 'gvm-tools Documentation', author, 'gvm-tools', 'One line description of project.', 'Miscellaneous', ) ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- gvm-tools-21.1.0/docs/config.rst000066400000000000000000000077421400201773500164620ustar00rootroot00000000000000.. _config: Configuration ============= .. versionchanged:: 2.0 By default, :program:`gvm-tools` :ref:`programs ` are evaluating the :file:`~/.config/gvm-tools.conf` `ini style `_ config file since version 2.0. The name of the used config file can be set using the :command:`-c/--config` command line switch. Settings -------- The configuration file consists of sections, each led by a :code:`[section]` header, followed by key/value entries separated by a :code:`=` character. Whitespaces between key and value are ignored, i.e., :code:`key = value` is the same as :code:`key=value`. Currently five sections are evaluated: * :ref:`Main section ` * :ref:`GMP section ` * :ref:`Socket section ` * :ref:`TLS section ` * :ref:`SSH section ` .. _main_section: .. rubric:: Main Section The main section allows changing the default connection timeout besides defining variables for :ref:`interpolation`. .. code-block:: ini [main] timeout = 60 .. _gmp_section: .. rubric:: GMP Section The GMP section allows setting the default user name and password for `Greenbone Management Protocol (GMP) `_ based communication. .. code-block:: ini [gmp] username=gmpuser password=gmppassword .. _socket_config_section: .. rubric:: Socket Section This section is only relevant if the :ref:`socket connection type ` is used. The socket section allows setting the default path to the Unix Domain socket of :term:`gvmd` or :term:`openvasmd` respectively. It must not be confused with the socket path to the redis server used by :term:`openvassd`. .. code-block:: ini [unixsocket] socketpath=/var/run/gvmd.sock .. _tls_config_section: .. rubric:: TLS Section This section is only relevant if the :ref:`TLS connection type ` is used (default for accessing :term:`openvasmd` on :term:`GOS` 3.1). The TLS section allows setting the default port, TLS certificate file, TLS key file and TLS certificate authority file. .. code-block:: ini [tls] port=1234 certfile=/path/to/tls.cert keyfile=/path/to/tls.key cafile=/path/to/tls.ca .. _ssh_config_section: .. rubric:: SSH Section This section is only relevant if the :ref:`SSH connection type ` is used (default for accessing :term:`openvasmd` on :term:`GOS` 4 and beyond). The SSH section allows setting the default SSH port, SSH user name and SSH password. .. code-block:: ini [ssh] username=sshuser password=sshpassword port=2222 .. rubric:: Comments Configuration files may also contain comments by using the special character :code:`#`. A comment should be placed on a separate line above or below the setting. .. code-block:: ini [main] # connection timeout of 120 seconds timeout=120 .. _interpolation: .. rubric:: Interpolation The configuration file also supports the `interpolation of values `_. It is possible to define values in the :code:`[main]` section and reference them via a :code:`%()s` syntax. Additionally, values of the same section can be referenced. .. code-block:: ini [main] my_first_name=John [gmp] my_last_name=Smith username=%(my_first_name)s%(my_last_name)s Using this syntax will set the gmp user name setting to `JohnSmith`. Example ------- Full example configuration: .. code-block:: ini [main] # increased timeout to 5 minutes timeout = 300 tls_path=/data/tls default_user=johnsmith [gmp] username=%(default_user)s password=choo4Gahdi2e [unixsocket] socketpath=/var/run/gvmd.sock [tls] port=1234 certfile=%(tls_path)s/tls.cert keyfile=%(tls_path)s/tls.key cafile=%(tls_path)s/tls.ca [ssh] username=%(default_user)s password=Poa8Ies1iJee gvm-tools-21.1.0/docs/connectiontypes.rst000066400000000000000000000057231400201773500204360ustar00rootroot00000000000000.. _connection_types: Connection Types ================ Before being able to talk to a remote :term:`GMP` or :term:`OSP` server using one of the :ref:`provided command line clients `, the user has to choose a connection type for establishing a communication channel. Currently three different connection types are supported for being used as transport protocol: * :ref:`TLS – tls ` * :ref:`SSH – ssh ` * :ref:`Unix Domain Socket – socket ` For the most common use case (querying :term:`openvasmd`/:term:`gvmd` via :term:`GMP` on the same host) the :ref:`socket connection ` should be chosen. The other connection types require some setup and possible adjustments at the server side, if no :term:`Greenbone OS ` based system is used. .. _socket_connection_type: Using a Unix Domain Socket -------------------------- The Unix Domain Socket is the default connection type of :term:`gvmd` in the :term:`Greenbone Source Edition `. It is only usable when running the client tool on the same host as the daemon. The location and name of the Unix Domain Socket provided by :term:`gvmd`/:term:`openvasmd` highly depends on the environment and :term:`GVM` installation. Additionally, its name changed from :file:`openvasmd.sock` in :term:`GVM 9 ` to :file:`gvmd.sock` in :term:`GVM 10 `. For :term:`GOS 4 ` the path is either :file:`/run/openvas/openvasmd.sock` or :file:`/usr/share/openvas/gsa/classic/openvasmd.sock` and for :term:`GOS 5 ` the path is either :file:`/run/gvm/gvmd.sock` or :file:`/usr/share/gvm/gsad/web/gvmd.sock`. :term:`OSPd based scanners ` may be accessed via Unix Domain Sockets as well. The location and name of these sockets is configurable and depends on the used OSPd scanner implementation. .. _don_t_use_sudo: .. warning:: Accessing a Unix Domain Socket requires sufficient Unix file permissions for the user running the :ref:`command line interface tool `. Please do not start a tool as **root** user via :command:`sudo` or :command:`su` only to be able to access the socket path. Instead, adjust the socket file permissions, e.g. by setting the :command:`--listen-owner`, :command:`--listen-group` or :command:`--listen-mode` arguments of :term:`gvmd`. .. _tls_connection_type: Using TLS --------- The TLS connection type was the default connection type for remote and local communication in :term:`GOS 3.1 ` and before. It is used to secure the transport protocol connection of :term:`GMP` or :term:`OSP`. It requires to provide a TLS certificate file, TLS key file and TLS certificate authority file. .. _ssh_connection_type: Using SSH --------- Since :term:`GOS 4 `, SSH is the default connection type for secure remote communication with the manager daemon via :term:`GMP`. The :term:`Greenbone Management Protocol ` is tunneled through SSH and forwarded to :term:`gvmd`/:term:`openvasmd`. gvm-tools-21.1.0/docs/favicon.gif000066400000000000000000000011151400201773500165630ustar00rootroot00000000000000GIF89ah#26D$8F'8K$OUGM\8Ef(Lj"Qc>Lu&Pw%Vu*Wu+Rv4Z}&hnb\~.\)[#ZV#lpea6^;m|_kC_+e1f4h!k/|ssFk"vi$f2hwUil{j|Z~k6ns!zAoo ~dqn l|or s;pu5r0qqqrSrv#sv XpYyu v;w~;y0sct| ~!2Z^*JƥӋ% % % % % % % % % % % % % % % % % % % % % % % % !Created with The GIMP! ,cg*=" ZaJ$XNI?AAHF4]>VA9 L[e0D 5f\A26`G(_AM&^:/8'-BQ!@A3E1YO%.+` and later. Abbreviation for **G**\reenbone **V**\ulnerability **M**\anager **D**\aemon. openvasmd Management daemon shipped with :term:`GVM 9 ` and before. Abbreviation for **OpenVAS** **M**\anager **D**\aemon. openvassd Scanner daemon used by :term:`GVM 10 ` and before. It listens for incoming connections via :term:`OTP` and starts scan processes to run the actual vulnerability tests. It collects the results and reports them to the management daemon. With :term:`GVM 11 ` it has been converted into the :term:`openvas` application by removing the daemon and OTP parts. Abbreviation for **OpenVAS** **S**\canner **D**\aemon. openvas Scanner application executable to run vulnerability tests against targets and to store scan results into a redis database. Used in :term:`GVM 11 ` and later. It has originated from the :term:`openvassd` daemon. OSPd A `framework `_ for several scanner daemons speaking the :term:`Open Scanner Protocol (OSP) `. ospd-openvas A :term:`OSP ` scanner daemon managing the :term:`openvas ` executable for reporting scan results to the management daemon :term:`gvmd`. Used in :term:`GVM 11 ` and later. GOS Greenbone Operating System, the operating system of the :term:`GSM appliances `. It provides the commercial version of the :term:`GVM framework ` with enterprise support and features. GSM The commercial product line `Greenbone Security Manager `_ available as appliances or virtual machines. GMP The `Greenbone Management Protocol `_. An XML-based communication protocol provided by :term:`openvasmd` and :term:`gvmd`. In the past it was also known as OMP. OSP The `Open Scanner Protocol `_. An XML-based communication protocol provided by `OSPd `_ based scanners. OTP The OpenVAS Transfer Protocol was inherited from pre-:term:`OpenVAS ` times. It is used by :term:`openvassd` to communicate with the manager daemon and got replaced by :term:`OSP` in :term:`GVM 11 `. See the `announcement `_ for some background. GVM The `Greenbone Vulnerability Management (GVM) `_ is a framework of several services. It is developed as part of the commercial product line :term:`Greenbone Security Manager `. Formerly known as OpenVAS. GVM9 `Version 9 `_ of the :term:`GVM` framework. Also known as **OpenVAS 9**. Used in the :term:`GOS 4 ` series. GVM10 `Version 10 `_ of the :term:`GVM` framework. Used in :term:`GOS 5 `. GVM11 `Version 11 `_ of the :term:`GVM` framework. Used in :term:`GOS 6 `. GSE The `Greenbone Source Edition (GSE) `_ covers the actual source codes of the Greenbone application stack for vulnerability scanning and vulnerability management :term:`GVM`. The source edition is adopted by external third parties, e.g., if the :term:`GVM` stack is provided by a Linux distribution, it is build from the Greenbone Source Edition. gvm-tools-21.1.0/docs/index.rst000066400000000000000000000016051400201773500163140ustar00rootroot00000000000000gvm-tools: Remote Control of Your Greenbone Vulnerability Manager (GVM) ======================================================================= The Greenbone Vulnerability Management Tools, or :program:`gvm-tools` in short, are a collection of tools that help with controlling a `Greenbone Security Manager (GSM) appliance `_ and its underlying :term:`Greenbone Vulnerability Manager (GVM) ` remotely. Essentially, the tools aid accessing the communication protocols :term:`Greenbone Management Protocol (GMP) ` and :term:`Open Scanner Protocol (OSP) `. .. note:: :program:`gvm-tools` requires at least Python 3.5. Python 2 is not supported. .. toctree:: install connectiontypes tools config scripting glossary :maxdepth: 2 Indices and Tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` gvm-tools-21.1.0/docs/install.rst000066400000000000000000000046021400201773500166530ustar00rootroot00000000000000.. _installation: Installation of gvm-tools ========================= The current universally applicable installation process for Python is using the `pip`_ installer tool in conjunction with the `pypi`_ package repository. Installing the Latest Stable Release of gvm-tools ------------------------------------------------- For installing the latest stable release of :program:`gvm-tools` from the `Python Package Index `_, `pip`_ or `poetry`_ can be used. Using pip ^^^^^^^^^ The following command installs :program:`gvm-tools` system wide: .. code-block:: shell python3 -m pip install gvm-tools A system wide installation usually requires admin permissions. Therefore, :program:`gvm-tools` may only be installed for the `current user `_ via: .. code-block:: shell python3 -m pip install --user gvm-tools For further details and additional installation options, please take a look at the documentation of `pip`_. Using poetry ^^^^^^^^^^^^ To avoid polluting the system and user namespaces with Python packages and to allow installing different versions of the same package at the same time, `python virtual environments `_ have been introduced. `poetry`_ is a tool combining the use of virtual environments and handling dependencies elegantly. Please follow the `poetry documentation `_ to install the tool. To install :program:`gvm-tools` into a virtual environment, the following commands need to be executed: .. code-block:: shell mkdir path/to/venv/dir cd path/to/venv/dir poetry install gvm-tools Afterwards, the environment containing the installed :program:`gvm-tools` can be activated by running: .. code-block:: shell cd path/to/venv/dir poetry shell Getting the Source ------------------ The source code of **python-gvm** can be found at `GitHub `_. To clone the public repository run:: git clone git://github.com/greenbone/gvm-tools Once there is a copy of the source, it can be installed into the current Python `environment `_: .. code-block:: shell python3 -m pip install -e /path/to/gvm-tools .. _pip: https://pip.pypa.io/en/stable/ .. _poetry: https://python-poetry.org/ .. _pypi: https://pypi.org/ gvm-tools-21.1.0/docs/requirements.txt000066400000000000000000000000071400201773500177320ustar00rootroot00000000000000sphinx gvm-tools-21.1.0/docs/scripting.rst000066400000000000000000000244461400201773500172170ustar00rootroot00000000000000.. _scripting: Scripting ========= .. _xml_scripting: XML Scripting ------------- .. note:: XML scripting via :program:`gvm-cli` should only be considered for simpler use cases. :ref:`Greenbone Management Protocol (GMP) or Open Scanner Protocol (OSP) scripts ` are often more powerful and easier to write. Scripting via :program:`gvm-cli` is directly based on `GMP `_ and `OSP `_. Both protocols make use of XML command requests and corresponding responses. A typical example for using GMP is the automatic scan of a new system. In the example below, it is assumed that an Intrusion Detection System (IDS) that monitors the systems in the Demilitarized Zone (DMZ) and immediately discovers new systems and unusual, new TCP ports is in use. If such an event is being discovered, the IDS should automatically initiate a scan of the new system. This can be done with the help of a script. 1. Starting point is the IP address of the new suspected system. For this IP address, a target needs to be created on the :term:`GSM`. If the IP address is saved in the environment variable :envvar:`IPADDRESS` by the IDS, the respective target can be created: .. code-block:: shell > gvm-cli socket --xml "Suspect Host"$IPADDRESS"" See :command:`create_target` command for all `details `__. 2. Create a task using the default *Full and Fast* scan configuration with UUID :token:`daba56c8-73ec-11df-a475-002264764cea` and the previously generated target: .. code-block:: shell > gvm-cli socket --xml "Scan Suspect Host" See :command:`create_task` command for all `details `__. 3. Start the task using the UUID return from the last response: .. code-block:: shell > gvm-cli socket --xml "" 0f9ea6ca-abf5-4139-a772-cb68937cdfbb See :command:`start_task` command for all `details `__. → The task is running. The response returns the UUID of the report which will contain the results of the scan. 4. Display the current status of the task: .. code-block:: shell > gvm-cli socket --xml "" ... Running98 ... ... See :command:`get_tasks` command for all `details `__. → As soon as the scan is completed, the full report is available and can be displayed. 5. Display the full report: .. code-block:: shell > gvm-cli socket --xml "" ... See :command:`get_reports` command for all `details `__. 6. Additionally, the report can be downloaded in a specific report format instead of plain XML. List all report formats: .. code-block:: shell > gvm-cli socket --xml "" ... See :command:`get_report_formats` command for all `details `__. 7. Download the report in the desired format. Example: download the report as a PDF file: .. code-block:: shell > gvm-cli socket --xml "" .. note:: Please be aware that the PDF is returned as `base64 encoded `_ content of the ** element in the XML response. .. _gvm_scripting: GVM Scripts ----------- .. versionchanged:: 2.0 Scripting of :term:`Greenbone Management Protocol (GMP) ` and :term:`Open Scanner Protocol (OSP) ` via :program:`gvm-script` or interactively via :program:`gvm-pyshell` is based on the `python-gvm`_ library. Please take a look at `python-gvm`_ for further details about the API. .. note:: By convention, scripts using :term:`GMP` are called *GMP scripts* and are files with the ending :file:`.gmp.py`. Accordingly, *OSP scripts* with the ending :file:`.osp.py` are using :term:`OSP`. Technically both protocols could be used in one single script file. The following sections are using the same example as it was used in :ref:`XML Scripting ` where it was assumed that an Intrusion Detection System (IDS) that monitors the systems in the Demilitarized Zone (DMZ) and immediately discovers new systems and unusual, new TCP ports is in use. The IDS will provide the IP address of a new system to the GMP script. 1. Define the function that should be called when the script is started by adding the following code to a file named :file:`scan-new-system.gmp.py`: .. code-block:: python3 if __name__ == '__gmp__': main(gmp, args) → The script is only called when being run as a GMP script. The :dfn:`gmp` and :dfn:`args` variables are provided by :program:`gvm-cli` or :program:`gvm-pyshell`. :dfn:`args` contains arguments for the script, e.g., the user name and password for the GMP connection. The most important aspect about the example script is that it contains the :dfn:`argv` property with the list of additional script specific arguments. The :dfn:`gmp` variable contains a connected and authenticated instance of a `Greenbone Management Protocol class `_. 2. The main function begins with the following code lines: .. code-block:: python3 def main(gmp, args): # check if IP address is provided to the script # argv[0] contains the script name if len(args.argv) <= 1: print('Missing IP address argument') return 1 ipaddress = args.argv[1] → The main function stores the first argument passed to the script as the :envvar:`ipaddress` variable. 3. Add the logic to create a target, create a new scan task for the target, start the task and print the corresponding report ID: .. code-block:: python3 ipaddress = args.argv[1] target_id = create_target(gmp, ipaddress) full_and_fast_scan_config_id = 'daba56c8-73ec-11df-a475-002264764cea' openvas_scanner_id = '08b69003-5fc2-4037-a479-93b440211c73' task_id = create_task( gmp, ipaddress, target_id, full_and_fast_scan_config_id, openvas_scanner_id, ) report_id = start_task(gmp, task_id) print( "Started scan of host {}. Corresponding report ID is {}".format( ipaddress, report_id ) ) For creating the target from an IP address (DNS name is also possible), the following is used. Since target names must be unique, the current date and time in ISO 8601 format (YYYY-MM-DDTHH:MM:SS.mmmmmm) is added: .. code-block:: python3 def create_target(gmp, ipaddress): import datetime # create a unique name by adding the current datetime name = "Suspect Host {} {}".format(ipaddress, str(datetime.datetime.now())) response = gmp.create_target(name=name, hosts=[ipaddress]) return response.get('id') The function for creating the task is defined as: .. code-block:: python3 def create_task(gmp, ipaddress, target_id, scan_config_id, scanner_id): name = "Scan Suspect Host {}".format(ipaddress) response = gmp.create_task( name=name, config_id=scan_config_id, target_id=target_id, scanner_id=scanner_id, ) return response.get('id') Finally, the function to start the task and get the report ID: .. code-block:: python3 def start_task(gmp, task_id): response = gmp.start_task(task_id) # the response is # id return response[0].text For getting a PDF document of the report, a second script :file:`pdf-report.gmp.py` can be used: .. code-block:: python3 from base64 import b64decode from pathlib import Path def main(gmp, args): # check if report id and PDF filename are provided to the script # argv[0] contains the script name if len(args.argv) <= 2: print('Please provide report ID and PDF file name as script arguments') return 1 report_id = args.argv[1] pdf_filename = args.argv[2] pdf_report_format_id = "c402cc3e-b531-11e1-9163-406186ea4fc5" response = gmp.get_report( report_id=report_id, report_format_id=pdf_report_format_id ) report_element = response[0] # get the full content of the report element content = "".join(report_element.itertext()) # convert content to 8-bit ASCII bytes binary_base64_encoded_pdf = content.encode('ascii') # decode base64 binary_pdf = b64decode(binary_base64_encoded_pdf) # write to file and support ~ in filename path pdf_path = Path(pdf_filename).expanduser() pdf_path.write_bytes(binary_pdf) print('Done.') if __name__ == '__gmp__': main(gmp, args) .. _python-gvm: https://python-gvm.readthedocs.io/en/latest/ Example Scripts --------------- All example scripts can be found at `GitHub `_. gvm-tools-21.1.0/docs/tools.rst000066400000000000000000000153561400201773500163550ustar00rootroot00000000000000.. _tools: Provided Tools ============== Currently, :program:`gvm-tools` comes with three command line interface programs: * :ref:`gvm-cli ` * :ref:`gvm-script ` * :ref:`gvm-pyshell ` All of these programs are clients communicating either via :term:`Greenbone Management Protocol (GMP) ` or :term:`Open Scanner Protocol (OSP) `. The :ref:`connection ` is established using a :ref:`TLS `, :ref:`SSH ` or :ref:`Unix Domain Socket ` communication channel. All tools take several arguments and parameters. :program:`gvm-tools` allows setting defaults for most of these in a configuration file. See :doc:`config` for details about the possible settings and capabilities. .. _gvm_cli: gvm-cli ------- :program:`gvm-cli` is a low level tool which offers sending and receiving commands and responses for the XML-based :term:`GMP ` and :term:`OSP ` directly via the command line. It is intended for :ref:`simple scripting ` via shell. .. code-block:: shell > gvm-cli --help usage: gvm-cli [-h] [-c [CONFIG]] [--log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}]] [--timeout TIMEOUT] [--gmp-username GMP_USERNAME] [--gmp-password GMP_PASSWORD] [-V] CONNECTION_TYPE ... optional arguments: -h, --help show this help message and exit -c [CONFIG], --config [CONFIG] Configuration file path (default: ~/.config/gvm- tools.conf) --log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}] Activate logging (default level: None) --timeout TIMEOUT Response timeout in seconds, or -1 to wait indefinitely (default: 60) --gmp-username GMP_USERNAME Username for GMP service (default: '') --gmp-password GMP_PASSWORD Password for GMP service (default: '') -V, --version Show version information and exit connections: valid connection types CONNECTION_TYPE Connection type to use ssh Use SSH to connect to service tls Use TLS secured connection to connect to service socket Use UNIX Domain socket to connect to service Examples: .. code-block:: shell > gvm-cli socket --xml "" 7.0 > gvm-cli socket --xml "" ... > gvm-cli socket < commands.xml .. _gvm_script: gvm-script ---------- .. versionadded:: 2.0 :program:`gvm-script` allows running :ref:`gvm scripts ` which are Python based scripts calling the `Python based GVM API `_. Depending on the :command:`--protocol` argument a global gmp or osp object is passed to the script. .. note:: :program:`gvm-script` is only available with :program:`gvm-tools` version 2.0 and beyond. .. code-block:: shell usage: gvm-script [-h] [-c [CONFIG]] [--log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}]] [--timeout TIMEOUT] [--gmp-username GMP_USERNAME] [--gmp-password GMP_PASSWORD] [-V] [--protocol {GMP,OSP}] CONNECTION_TYPE ... optional arguments: -h, --help show this help message and exit -c [CONFIG], --config [CONFIG] Configuration file path (default: ~/.config/gvm- tools.conf) --log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}] Activate logging (default level: None) --timeout TIMEOUT Response timeout in seconds, or -1 to wait indefinitely (default: 60) --gmp-username GMP_USERNAME Username for GMP service (default: '') --gmp-password GMP_PASSWORD Password for GMP service (default: '') -V, --version Show version information and exit --protocol {GMP,OSP} Service protocol to use (default: GMP) connections: valid connection types CONNECTION_TYPE Connection type to use ssh Use SSH to connect to service tls Use TLS secured connection to connect to service socket Use UNIX Domain socket to connect to service .. _gvm_pyshell: gvm-pyshell ----------- :program:`gvm-pyshell` is a tool to use the `Python GVM API `_ interactively. Running the tool will open a Python interpreter in the `interactive mode `_ providing a global gmp or osp object depending on the :command:`--protocol` argument. The interactive shell can be exited with: * :kbd:`Ctrl + D` on Linux or * :kbd:`Ctrl + Z` on Windows .. code-block:: shell > gvm-pyshell --help usage: gvm-pyshell [-h] [-c [CONFIG]] [--log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}]] [--timeout TIMEOUT] [--gmp-username GMP_USERNAME] [--gmp-password GMP_PASSWORD] [-V] [--protocol {GMP,OSP}] CONNECTION_TYPE ... optional arguments: -h, --help show this help message and exit -c [CONFIG], --config [CONFIG] Configuration file path (default: ~/.config/gvm- tools.conf) --log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}] Activate logging (default level: None) --timeout TIMEOUT Response timeout in seconds, or -1 to wait indefinitely (default: 60) --gmp-username GMP_USERNAME Username for GMP service (default: '') --gmp-password GMP_PASSWORD Password for GMP service (default: '') -V, --version Show version information and exit --protocol {GMP,OSP} Service protocol to use (default: GMP) connections: valid connection types CONNECTION_TYPE Connection type to use ssh Use SSH to connect to service tls Use TLS secured connection to connect to service socket Use UNIX Domain socket to connect to service Example: .. code-block:: python > gvm-pyshell socket GVM Interactive Console 2.0.0 API 1.0.0. Type "help" to get information about functionality. >>> gmp.get_protocol_version() '7' >>> gmp.get_version().get('status') '200' >>> gmp.get_version()[0].text '7.0' >>> [t.find('name').text for t in tasks.xpath('task')] ['Scan Task', 'Simple Scan', 'Host Discovery'] gvm-tools-21.1.0/gvmtools/000077500000000000000000000000001400201773500153735ustar00rootroot00000000000000gvm-tools-21.1.0/gvmtools/__init__.py000066400000000000000000000021641400201773500175070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Main module of gvm-tools. """ def get_version() -> str: """Returns the version of gvm-tools as a string in `PEP440`_ compliant format. Returns: str: Current version of gvm-tools .. _PEP440: https://www.python.org/dev/peps/pep-0440 """ # pylint: disable=import-outside-toplevel from .__version__ import __version__ return __version__ gvm-tools-21.1.0/gvmtools/__version__.py000066400000000000000000000001471400201773500202300ustar00rootroot00000000000000# pylint: disable=invalid-name # THIS IS AN AUTOGENERATED FILE. DO NOT TOUCH! __version__ = "21.1.0" gvm-tools-21.1.0/gvmtools/cli.py000066400000000000000000000107721400201773500165230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import getpass import logging import sys import time from gvm.errors import GvmError from gvm.protocols.latest import Osp from gvm.protocols.gmp import Gmp from gvm.transforms import CheckCommandTransform from gvm.xml import validate_xml_string, pretty_print from gvmtools.helper import do_not_run_as_root from gvmtools.parser import ( create_parser, create_connection, PROTOCOL_OSP, PROTOCOL_GMP, ) logger = logging.getLogger(__name__) HELP_TEXT = """ Command line tool to access services via GMP (Greenbone Management Protocol) and OSP (Open Scanner Protocol) Examples: gvm-cli socket --help gvm-cli tls --help gvm-cli ssh --help gvm-cli socket --xml "" gvm-cli socket --xml "myusermypass" gvm-cli socket --gmp-username foo --gmp-password foo < myfile.xml The protocol specifications for GMP and OSP are available at: https://docs.greenbone.net/index.html#api_documentation""" def _load_infile(filename=None): if not filename: return None with open(filename) as f: return f.read() def main(): do_not_run_as_root() parser = create_parser(description=HELP_TEXT, logfilename='gvm-cli.log') parser.add_protocol_argument() parser.add_argument('-X', '--xml', help='XML request to send') parser.add_argument( '-r', '--raw', help='Return raw XML', action='store_true', default=False ) parser.add_argument( '--pretty', help='Pretty format the returned xml', action='store_true', default=False, ) parser.add_argument( '--duration', action='store_true', help='Measure command execution time' ) parser.add_argument( 'infile', nargs='?', help='File to read XML commands from.' ) args = parser.parse_args() # If timeout value is -1, then the socket has no timeout for this session if args.timeout == -1: args.timeout = None if args.xml is not None: xml = args.xml else: try: xml = _load_infile(args.infile) except IOError as e: print(e, file=sys.stderr) sys.exit(1) # If no command was given, program asks for one if len(xml) == 0: xml = input() try: validate_xml_string(xml) except GvmError as e: print(e, file=sys.stderr) sys.exit(1) connection = create_connection(**vars(args)) if args.raw: transform = None else: transform = CheckCommandTransform() if args.protocol == PROTOCOL_OSP: protocol_class = Osp else: protocol_class = Gmp try: with protocol_class(connection, transform=transform) as protocol: if args.protocol == PROTOCOL_GMP: # Ask for password if none are given if args.gmp_username and not args.gmp_password: args.gmp_password = getpass.getpass( 'Enter password for ' + args.gmp_username + ': ' ) if args.gmp_username: protocol.authenticate(args.gmp_username, args.gmp_password) if args.duration: starttime = time.time() result = protocol.send_command(xml) if args.duration: duration = time.time() - starttime print('Elapsed time: {} seconds'.format(duration)) elif args.pretty: pretty_print(result) else: print(result) except Exception as e: # pylint: disable=broad-except print(e, file=sys.stderr) sys.exit(1) sys.exit(0) if __name__ == '__main__': main() gvm-tools-21.1.0/gvmtools/config.py000066400000000000000000000053621400201773500172200ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Module to store gvm-tools configuration settings """ import configparser import logging from gvm.connections import ( DEFAULT_UNIX_SOCKET_PATH, DEFAULT_GVM_PORT, DEFAULT_SSH_PORT, DEFAULT_HOSTNAME, ) logger = logging.getLogger(__name__) class Config: def __init__(self): self._config = configparser.ConfigParser(default_section='main') self._config = {} self._config['gmp'] = dict(username='', password='') self._config['ssh'] = dict( username='gmp', password='gmp', port=DEFAULT_SSH_PORT, hostname=DEFAULT_HOSTNAME, ) self._config['unixsocket'] = dict(socketpath=DEFAULT_UNIX_SOCKET_PATH) self._config['tls'] = dict( port=DEFAULT_GVM_PORT, hostname=DEFAULT_HOSTNAME ) self._defaults = dict() def load(self, filepath): path = filepath.expanduser() config = configparser.ConfigParser(default_section='main') with path.open() as f: config.read_file(f) if 'Auth' in config: logger.warning( "Warning: Loaded config file %s contains deprecated 'Auth' " "section. This section will be ignored in future.", str(filepath), ) gmp_username = config.get('Auth', 'gmp_username', fallback='') gmp_password = config.get('Auth', 'gmp_password', fallback='') self._config['gmp']['username'] = gmp_username self._config['gmp']['password'] = gmp_password self._defaults.update(config.defaults()) for section in config.sections(): if section == 'Auth': continue for key, value in config.items(section): self._config.setdefault(section, dict())[key] = value def defaults(self): return self._defaults def get(self, section, name): if not section in self._config: return None return self._config[section].get(name) gvm-tools-21.1.0/gvmtools/helper.py000066400000000000000000000143631400201773500172330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import getpass import os import sys import uuid import string from random import choice, randrange from lxml import etree from gvm.errors import GvmError from gvm.xml import pretty_print __all__ = ['authenticate', 'pretty_print', 'run_script'] class Table: def __init__(self, heading=None, rows=None, divider=' | '): self.heading = heading or [] self.rows = rows or [] self.divider = divider def _calculate_dimensions(self): column_sizes = [] for column in self.heading: column_sizes.append(len(column)) for row in self.rows: for i, column in enumerate(row): dim = column_sizes[i] column_size = len(column) if dim < column_size: column_sizes[i] = column_size return column_sizes def _create_column(self, column, size): return '{}{}'.format(column, ' ' * (size - len(column))) def _create_row(self, columns): return self.divider.join(columns) def __str__(self): column_sizes = self._calculate_dimensions() row_strings = [] heading_columns = [] heading_divider_columns = [] for i, column in enumerate(self.heading): column_size = column_sizes[i] heading_columns.append(self._create_column(column, column_size)) heading_divider_columns.append( self._create_column('-' * column_size, column_size) ) row_strings.append(self._create_row(heading_columns)) row_strings.append(self._create_row(heading_divider_columns)) for row in self.rows: row_columns = [] for i, column in enumerate(row): column_size = column_sizes[i] row_columns.append(self._create_column(column, column_size)) row_strings.append(self._create_row(row_columns)) return "\n".join(row_strings) def yes_or_no(question): """Asks the user to proceed or not in a gvmtools script Arguments: question (str): The condition the user should answer """ reply = str(input(question + ' (y/n): ')).lower().strip() if reply[0] == ('y'): return True if reply[0] == ('n'): return False else: return yes_or_no("Please enter 'y' or 'n'") def error_and_exit(msg): """Prints an error message and quits the gvmtools script Arguments: msg (str): The error message, that will be printed """ print("\nError: {}\n".format(msg), file=sys.stderr) sys.exit(1) def generate_random_ips(count: int): """Generate count random IPv4s""" exclude_127 = [i for i in range(1, 256)] exclude_127.remove(127) return [ '{}.{}.{}.{}'.format( choice(exclude_127), randrange(0, 256), randrange(0, 256), randrange(1, 255), ) for i in range(count) ] def generate_id( size: int = 12, chars: str = string.ascii_uppercase + string.digits ): """Generate a random ID""" return ''.join(choice(chars) for _ in range(size)) def generate_uuid(): """Generate a random new uuid""" return str(uuid.uuid4()) def create_xml_tree(xml_doc): """Creates an XML tree that can be read by an gvmtools script Arguments: xml_doc (str): Path to the xml document """ try: xml_tree = etree.parse(xml_doc) xml_tree = xml_tree.getroot() except IOError as err: error_and_exit("Failed to read xml_file: {} (exit)".format(str(err))) except etree.Error as err: error_and_exit("Failed to parse xml_file: {} (exit)".format(str(err))) if len(xml_tree) == 0: error_and_exit("XML file is empty (exit)") return xml_tree def do_not_run_as_root(): if hasattr(os, 'geteuid') and os.geteuid() == 0: raise RuntimeError('This tool MUST NOT be run as root user.') def authenticate(gmp, username=None, password=None): """Authentication helper Tries to get authentication username and password from arguments and if not present asks the username and/or password from the terminal. Arguments: gmp: A protocol instance username (:obj:`str`, optional): Username to authenticate with. If None, username will be read from terminal. password (:obj:`str`, optional): Password to authenticate with. If None, password will be read from the terminal. Returns: tuple: (username, password) tuple Raises: GmpError: Raises GmpError if authentication fails. """ if gmp.is_authenticated(): return # Ask for login credentials if none are given. if not username: while username is None or len(username) == 0: username = input('Enter username: ') if not password: password = getpass.getpass('Enter password for {0}: '.format(username)) try: gmp.authenticate(username, password) return (username, password) except GvmError as e: print('Could not authenticate. Please check your credentials.') raise e def run_script(path, global_vars): """Loads and executes a file as a python script Arguments: path (str): Path to the script file vars (dict): Variables passed as globals to the script """ try: file = open(path, 'r', newline='').read() except FileNotFoundError: print('Script {path} does not exist'.format(path=path), file=sys.stderr) sys.exit(2) exec(file, global_vars) # pylint: disable=exec-used gvm-tools-21.1.0/gvmtools/parser.py000066400000000000000000000250311400201773500172420ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 - 2019 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """Command Line Interface Parser """ import argparse import logging from pathlib import Path from gvm import get_version as get_gvm_version from gvm.connections import ( DEFAULT_TIMEOUT, SSHConnection, TLSConnection, UnixSocketConnection, ) from gvmtools import get_version from gvmtools.config import Config logger = logging.getLogger(__name__) __version__ = get_version() __api_version__ = get_gvm_version() DEFAULT_CONFIG_PATH = '~/.config/gvm-tools.conf' PROTOCOL_OSP = 'OSP' PROTOCOL_GMP = 'GMP' DEFAULT_PROTOCOL = PROTOCOL_GMP class CliParser: def __init__( self, description, logfilename, *, prog=None, ignore_config=False ): bootstrap_parser = argparse.ArgumentParser( prog=prog, description=description, formatter_class=argparse.RawTextHelpFormatter, # don't parse help initially. the args from parser wouldn't be shown add_help=False, ) bootstrap_parser.add_argument( '-c', '--config', nargs='?', default=DEFAULT_CONFIG_PATH, help='Configuration file path (default: %(default)s)', ) choices = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] bootstrap_parser.add_argument( '--log', nargs='?', dest='loglevel', const='INFO', type=lambda arg: {x.upper(): x for x in choices}[arg.upper()], choices=choices, help='Activate logging (default level: %(default)s)', ) parser = argparse.ArgumentParser(prog=prog, parents=[bootstrap_parser]) parser.add_argument( '--timeout', required=False, default=DEFAULT_TIMEOUT, type=int, help='Response timeout in seconds, or -1 to wait ' 'indefinitely (default: %(default)s)', ) parser.add_argument( '--gmp-username', help='Username for GMP service (default: %(default)r)', ) parser.add_argument( '--gmp-password', help='Password for GMP service (default: %(default)r)', ) parser.add_argument( '-V', '--version', action='version', version='%(prog)s {version} (API version {apiversion})'.format( version=__version__, apiversion=__api_version__ ), help='Show version information and exit', ) subparsers = parser.add_subparsers( metavar='CONNECTION_TYPE', title='connections', description='valid connection types', help="Connection type to use", ) subparsers.required = True subparsers.dest = 'connection_type' self._subparsers = subparsers self._parser = parser self._bootstrap_parser = bootstrap_parser self._logfilename = logfilename self._ignore_config = ignore_config self._add_subparsers() def parse_args(self, args=None): args, unkown_args = self.parse_known_args(args) if unkown_args: self._parser.error( 'unrecognized arguments {}'.format(' '.join(unkown_args)) ) return args def parse_known_args(self, args=None): args_before, _ = self._bootstrap_parser.parse_known_args(args) if args_before.loglevel is not None: level = logging.getLevelName(args_before.loglevel) logging.basicConfig(filename=self._logfilename, level=level) self._set_defaults(None if self._ignore_config else args_before.config) args, unknown_args = self._parser.parse_known_args(args) # If timeout value is -1, then the socket should have no timeout if args.timeout == -1: args.timeout = None logging.debug('Parsed arguments %r', args) return args, unknown_args def add_argument(self, *args, **kwargs): self._parser_socket.add_argument(*args, **kwargs) self._parser_ssh.add_argument(*args, **kwargs) self._parser_tls.add_argument(*args, **kwargs) def add_protocol_argument(self): self._parser.add_argument( '--protocol', required=False, default=DEFAULT_PROTOCOL, choices=[PROTOCOL_GMP, PROTOCOL_OSP], help='Service protocol to use (default: %(default)s)', ) def _load_config(self, configfile): config = Config() if not configfile: return config configpath = Path(configfile) try: if not configpath.expanduser().resolve().exists(): logger.debug('Ignoring non existing config file %s', configfile) return config except FileNotFoundError: # we are on python 3.5 and Path.resolve raised a FileNotFoundError logger.debug('Ignoring non existing config file %s', configfile) return config try: config.load(configpath) logger.debug('Loaded config %s', configfile) except Exception as e: # pylint: disable=broad-except raise RuntimeError( 'Error while parsing config file {config}. Error was ' '{message}'.format(config=configfile, message=e) ) from None return config def _add_subparsers(self): parser_ssh = self._subparsers.add_parser( 'ssh', help='Use SSH to connect to service' ) parser_ssh.add_argument( '--hostname', help='Hostname or IP address (default: %(default)s)' ) parser_ssh.add_argument( '--port', required=False, help='SSH port (default: %(default)s)', type=int, ) parser_ssh.add_argument( '--ssh-username', help='SSH username (default: %(default)r)' ) parser_ssh.add_argument( '--ssh-password', help='SSH password (default: %(default)r)' ) parser_tls = self._subparsers.add_parser( 'tls', help='Use TLS secured connection to connect to service' ) parser_tls.add_argument( '--hostname', help='Hostname or IP address (default: %(default)s)' ) parser_tls.add_argument( '--port', required=False, help='GMP/OSP port (default: %(default)s)', type=int, ) parser_tls.add_argument( '--certfile', required=False, help='Path to the certificate file for client authentication. ' '(default: %(default)s)', ) parser_tls.add_argument( '--keyfile', required=False, help='Path to key file for client authentication. ' '(default: %(default)s)', ) parser_tls.add_argument( '--cafile', required=False, help='Path to CA certificate for server authentication. ' '(default: %(default)s)', ) parser_tls.add_argument( '--no-credentials', required=False, default=False, action='store_true', help='Use only certificates for authentication', ) parser_socket = self._subparsers.add_parser( 'socket', help='Use UNIX Domain socket to connect to service' ) socketpath_group = parser_socket.add_mutually_exclusive_group() socketpath_group.add_argument( '--sockpath', nargs='?', default=None, dest='socketpath', help='Deprecated, use --socketpath instead', ) socketpath_group.add_argument( '--socketpath', nargs='?', help='Path to UNIX Domain socket (default: %(default)s)', ) self._parser_ssh = parser_ssh self._parser_socket = parser_socket self._parser_tls = parser_tls def _set_defaults(self, configfilename=None): self._config = self._load_config(configfilename) self._parser.set_defaults( gmp_username=self._config.get('gmp', 'username'), gmp_password=self._config.get('gmp', 'password'), **self._config.defaults(), ) self._parser_ssh.set_defaults( port=int(self._config.get('ssh', 'port')), ssh_username=self._config.get('ssh', 'username'), ssh_password=self._config.get('ssh', 'password'), hostname=self._config.get('ssh', 'hostname'), ) self._parser_tls.set_defaults( port=int(self._config.get('tls', 'port')), certfile=self._config.get('tls', 'certfile'), keyfile=self._config.get('tls', 'keyfile'), cafile=self._config.get('tls', 'cafile'), hostname=self._config.get('tls', 'hostname'), ) self._parser_socket.set_defaults( socketpath=self._config.get('unixsocket', 'socketpath') ) def create_parser(description, logfilename): return CliParser(description, logfilename) def create_connection( connection_type, socketpath=None, timeout=None, hostname=None, port=None, certfile=None, keyfile=None, cafile=None, ssh_username=None, ssh_password=None, **kwargs # pylint: disable=unused-argument ): if 'socket' in connection_type: return UnixSocketConnection(timeout=timeout, path=socketpath) if 'tls' in connection_type: return TLSConnection( timeout=timeout, hostname=hostname, port=port, certfile=certfile, keyfile=keyfile, cafile=cafile, ) return SSHConnection( timeout=timeout, hostname=hostname, port=port, username=ssh_username, password=ssh_password, ) gvm-tools-21.1.0/gvmtools/pyshell.py000066400000000000000000000123471400201773500174340ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import code import logging import os import sys from argparse import Namespace from gvm import get_version as get_gvm_version from gvm.xml import pretty_print from gvm.protocols.gmp import Gmp from gvm.protocols.latest import Osp from gvm.transforms import EtreeCheckCommandTransform from gvmtools import get_version from gvmtools.helper import authenticate, run_script, do_not_run_as_root from gvmtools.parser import ( create_parser, create_connection, PROTOCOL_OSP, PROTOCOL_GMP, ) __version__ = get_version() __api_version__ = get_gvm_version() logger = logging.getLogger(__name__) HELP_TEXT = """ Command line tool to access services via GMP (Greenbone Management Protocol) and OSP (Open Scanner Protocol) gvm-pyshell provides an interactive shell for GMP and OSP services. Example: >>> tasks = gmp.get_tasks() >>> task_names = tasks.xpath('task/name/text()') >>> print(task_names) ['Scan Task'] >>> pretty_print('') The interactive shell can be exited with: Ctrl + D on Linux or Ctrl + Z on Windows The protocol specifications for GMP and OSP are available at: https://docs.greenbone.net/index.html#api_documentation""" class Help(object): """Help class to overwrite the help function from python itself.""" def __call__(self): return print(HELP_TEXT) def __repr__(self): # do pwd command return HELP_TEXT def main(): do_not_run_as_root() parser = create_parser(description=HELP_TEXT, logfilename='gvm-pyshell.log') parser.add_protocol_argument() parser.add_argument( '-i', '--interactive', action='store_true', default=False, help='Start an interactive Python shell', ) parser.add_argument( 'scriptname', nargs='?', metavar="SCRIPT", help='Path to script to be preloaded (example: myscript.gmp.py)', ) parser.add_argument( 'scriptargs', nargs='*', metavar="ARG", help='Arguments for preloaded script', ) args = parser.parse_args() connection = create_connection(**vars(args)) transform = EtreeCheckCommandTransform() global_vars = { 'help': Help(), 'pretty_print': pretty_print, '__version__': __version__, '__api_version__': __api_version__, } username = None password = None if args.protocol == PROTOCOL_OSP: protocol_class = Osp name = 'osp' else: protocol_class = Gmp name = 'gmp' with protocol_class(connection, transform=transform) as protocol: global_vars[name] = protocol global_vars['__name__'] = '__{}__'.format(name) if args.protocol == PROTOCOL_GMP: if args.gmp_username: (username, password) = authenticate( protocol, username=args.gmp_username, password=args.gmp_password, ) shell_args = Namespace(username=username, password=password) global_vars['args'] = shell_args with_script = args.scriptname and len(args.scriptname) > 0 if with_script: argv = [os.path.abspath(args.scriptname), *args.scriptargs] shell_args.argv = argv # for backwards compatibility we add script here shell_args.script = argv no_script_no_interactive = not args.interactive and not with_script script_and_interactive = args.interactive and with_script only_interactive = not with_script and args.interactive only_script = not args.interactive and with_script if only_interactive or no_script_no_interactive: enter_interactive_mode(global_vars) if script_and_interactive or only_script: if only_script: print( 'Using gvm-pyshell for running scripts only is deprecated. ' 'Please use gvm-script instead', file=sys.stderr, ) script_name = args.scriptname run_script(script_name, global_vars) if not only_script: enter_interactive_mode(global_vars) def enter_interactive_mode(global_vars): code.interact( banner='GVM Interactive Console {} API {}. Type "help" to get ' 'information about functionality.'.format(__version__, __api_version__), local=dict(global_vars), ) if __name__ == '__main__': main() gvm-tools-21.1.0/gvmtools/script.py000066400000000000000000000067671400201773500172710ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import sys from argparse import Namespace from gvm import get_version as get_gvm_version from gvm.protocols.gmp import Gmp from gvm.protocols.latest import Osp from gvm.transforms import EtreeCheckCommandTransform from gvmtools import get_version from gvmtools.helper import authenticate, run_script, do_not_run_as_root from gvmtools.parser import ( create_parser, create_connection, PROTOCOL_OSP, PROTOCOL_GMP, ) HELP_TEXT = """ Command line tool to execute custom GMP (Greenbone Management Protocol) and OSP (Open Scanner Protocol) scripts. The protocol specifications for GMP and OSP are available at: https://docs.greenbone.net/index.html#api_documentation """ __version__ = get_version() __api_version__ = get_gvm_version() def main(): do_not_run_as_root() parser = create_parser(description=HELP_TEXT, logfilename='gvm-script.log') parser.add_protocol_argument() parser.add_argument( 'scriptname', metavar="SCRIPT", help='Path to script to be executed (example: myscript.gmp.py)', ) parser.add_argument( 'scriptargs', nargs='*', metavar="ARG", help='Arguments for the script' ) args, script_args = parser.parse_known_args() connection = create_connection(**vars(args)) transform = EtreeCheckCommandTransform() global_vars = { '__version__': __version__, '__api_version__': __api_version__, } username = None password = None if args.protocol == PROTOCOL_OSP: protocol_class = Osp name = 'osp' else: protocol_class = Gmp name = 'gmp' try: with protocol_class(connection, transform=transform) as protocol: global_vars[name] = protocol global_vars['__name__'] = '__{}__'.format(name) if args.protocol == PROTOCOL_GMP: if args.gmp_username: (username, password) = authenticate( protocol, username=args.gmp_username, password=args.gmp_password, ) argv = [os.path.abspath(args.scriptname), *args.scriptargs] shell_args = Namespace( username=username, password=password, argv=argv, # for backwards compatibility we add script here script=argv, # the unknown args, which are owned by the script. script_args=script_args, ) global_vars['args'] = shell_args run_script(args.scriptname, global_vars) except Exception as e: # pylint: disable=broad-except print(e, file=sys.stderr) sys.exit(1) sys.exit(0) if __name__ == '__main__': main() gvm-tools-21.1.0/poetry.lock000066400000000000000000002073141400201773500157240ustar00rootroot00000000000000[[package]] name = "alabaster" version = "0.7.12" description = "A configurable sidebar-enabled Sphinx theme" category = "dev" optional = false python-versions = "*" [[package]] name = "appdirs" version = "1.4.4" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = "*" [[package]] name = "astroid" version = "2.4.2" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.5" [package.dependencies] lazy-object-proxy = ">=1.4.0,<1.5.0" six = ">=1.12,<2.0" typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} wrapt = ">=1.11,<2.0" [[package]] name = "autohooks" version = "2.2.0" description = "Library for managing git hooks" category = "dev" optional = false python-versions = ">=3.5,<4.0" [package.dependencies] colorful = ">=0.5.4,<0.6.0" packaging = ">=20.3,<21.0" tomlkit = ">=0.5.11,<0.6.0" [[package]] name = "autohooks-plugin-black" version = "1.2.0" description = "Autohooks plugin for code formatting via black" category = "dev" optional = false python-versions = ">=3.5" [package.dependencies] autohooks = ">=1.1" black = "*" [[package]] name = "autohooks-plugin-pylint" version = "1.2.0" description = "Autohooks plugin for code linting via pylint" category = "dev" optional = false python-versions = ">=3.5" [package.dependencies] autohooks = ">=1.1" pylint = "*" [[package]] name = "babel" version = "2.9.0" description = "Internationalization utilities" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pytz = ">=2015.7" [[package]] name = "bcrypt" version = "3.2.0" description = "Modern password hashing for your software and your servers" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] cffi = ">=1.1" six = ">=1.4.1" [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] typecheck = ["mypy"] [[package]] name = "black" version = "20.8b1" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] appdirs = "*" click = ">=7.1.2" mypy-extensions = ">=0.4.3" pathspec = ">=0.6,<1" regex = ">=2020.1.8" toml = ">=0.10.1" typed-ast = ">=1.4.0" typing-extensions = ">=3.7.4" [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "certifi" version = "2020.12.5" description = "Python package for providing Mozilla's CA Bundle." category = "dev" optional = false python-versions = "*" [[package]] name = "cffi" version = "1.14.4" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false python-versions = "*" [package.dependencies] pycparser = "*" [[package]] name = "chardet" version = "4.0.0" description = "Universal encoding detector for Python 2 and 3" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "click" version = "7.1.2" description = "Composable command line interface toolkit" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "colorful" version = "0.5.4" description = "Terminal string styling done right, in Python." category = "dev" optional = false python-versions = "*" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "coverage" version = "5.3.1" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] toml = ["toml"] [[package]] name = "cryptography" version = "3.3.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" [package.dependencies] cffi = ">=1.12" six = ">=1.4.1" [package.extras] docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] ssh = ["bcrypt (>=3.1.5)"] test = ["pytest (>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] [[package]] name = "defusedxml" version = "0.6.0" description = "XML bomb protection for Python stdlib modules" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "docutils" version = "0.16" description = "Docutils -- Python Documentation Utilities" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "idna" version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "imagesize" version = "1.2.0" description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "isort" version = "5.7.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.6,<4.0" [package.extras] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] [[package]] name = "jinja2" version = "2.11.2" description = "A very fast and expressive template engine." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] MarkupSafe = ">=0.23" [package.extras] i18n = ["Babel (>=0.8)"] [[package]] name = "lazy-object-proxy" version = "1.4.3" description = "A fast and thorough lazy object proxy." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "lxml" version = "4.6.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["beautifulsoup4"] source = ["Cython (>=0.29.7)"] [[package]] name = "markupsafe" version = "1.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" [[package]] name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" category = "dev" optional = false python-versions = "*" [[package]] name = "mypy-extensions" version = "0.4.3" description = "Experimental type system extensions for programs checked with the mypy typechecker." category = "dev" optional = false python-versions = "*" [[package]] name = "packaging" version = "20.8" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = ">=2.0.2" [[package]] name = "paramiko" version = "2.7.2" description = "SSH2 protocol library" category = "main" optional = false python-versions = "*" [package.dependencies] bcrypt = ">=3.1.3" cryptography = ">=2.5" pynacl = ">=1.0.1" [package.extras] all = ["pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "bcrypt (>=3.1.3)", "invoke (>=1.3)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] ed25519 = ["pynacl (>=1.0.1)", "bcrypt (>=3.1.3)"] gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] invoke = ["invoke (>=1.3)"] [[package]] name = "pathspec" version = "0.8.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pontos" version = "0.3.1" description = "Common utilities and tools maintained by Greenbone Networks" category = "dev" optional = false python-versions = ">=3.7,<4.0" [package.dependencies] packaging = ">=20.3,<21.0" requests = ">=2.24.0,<3.0.0" tomlkit = ">=0.5.11,<0.6.0" [[package]] name = "pycparser" version = "2.20" description = "C parser in Python" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" version = "2.7.4" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false python-versions = ">=3.5" [[package]] name = "pylint" version = "2.6.0" description = "python code static checker" category = "dev" optional = false python-versions = ">=3.5.*" [package.dependencies] astroid = ">=2.4.0,<=2.5" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" toml = ">=0.7.1" [[package]] name = "pynacl" version = "1.4.0" description = "Python binding to the Networking and Cryptography (NaCl) library" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] cffi = ">=1.4.1" six = "*" [package.extras] docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"] [[package]] name = "pyparsing" version = "2.4.7" description = "Python parsing module" category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "python-gvm" version = "21.1.1" description = "Library to communicate with remote servers over GMP or OSP" category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" [package.dependencies] defusedxml = ">=0.6.0,<0.7.0" lxml = ">=4.5.0,<5.0.0" paramiko = ">=2.7.1,<3.0.0" [[package]] name = "pytz" version = "2020.5" description = "World timezone definitions, modern and historical" category = "dev" optional = false python-versions = "*" [[package]] name = "regex" version = "2020.11.13" description = "Alternative regular expression module, to replace re." category = "dev" optional = false python-versions = "*" [[package]] name = "requests" version = "2.25.1" description = "Python HTTP for Humans." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<5" idna = ">=2.5,<3" urllib3 = ">=1.21.1,<1.27" [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] name = "rope" version = "0.18.0" description = "a python refactoring library..." category = "dev" optional = false python-versions = "*" [package.extras] dev = ["pytest"] [[package]] name = "six" version = "1.15.0" description = "Python 2 and 3 compatibility utilities" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "snowballstemmer" version = "2.0.0" description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." category = "dev" optional = false python-versions = "*" [[package]] name = "sphinx" version = "3.4.3" description = "Python documentation generator" category = "dev" optional = false python-versions = ">=3.5" [package.dependencies] alabaster = ">=0.7,<0.8" babel = ">=1.3" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} docutils = ">=0.12" imagesize = "*" Jinja2 = ">=2.3" packaging = "*" Pygments = ">=2.0" requests = ">=2.5.0" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = "*" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.790)", "docutils-stubs"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] name = "sphinxcontrib-applehelp" version = "1.0.2" description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" category = "dev" optional = false python-versions = ">=3.5" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" version = "1.0.2" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." category = "dev" optional = false python-versions = ">=3.5" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" version = "1.0.3" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" category = "dev" optional = false python-versions = ">=3.5" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest", "html5lib"] [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" category = "dev" optional = false python-versions = ">=3.5" [package.extras] test = ["pytest", "flake8", "mypy"] [[package]] name = "sphinxcontrib-qthelp" version = "1.0.3" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." category = "dev" optional = false python-versions = ">=3.5" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" version = "1.1.4" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." category = "dev" optional = false python-versions = ">=3.5" [package.extras] lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] [[package]] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomlkit" version = "0.5.11" description = "Style preserving TOML library" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "typed-ast" version = "1.4.2" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false python-versions = "*" [[package]] name = "typing-extensions" version = "3.7.4.3" description = "Backported and Experimental Type Hints for Python 3.5+" category = "dev" optional = false python-versions = "*" [[package]] name = "urllib3" version = "1.26.2" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "wrapt" version = "1.12.1" description = "Module for decorators, wrappers and monkey patching." category = "dev" optional = false python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.7.0" content-hash = "adfb1affac870bf8600ef3255ca76a92e82f86eb2077c932ffc3a07187494a0b" [metadata.files] alabaster = [ {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] astroid = [ {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, ] autohooks = [ {file = "autohooks-2.2.0-py3-none-any.whl", hash = "sha256:9c7b1117ebace5f7edb3352ea7951dc09cfab8a1f8331ae4157da11cdf66f280"}, {file = "autohooks-2.2.0.tar.gz", hash = "sha256:44bc4675ae6eae0f0803e1f23f31405317ffc679b6a1873ee192999466e05cdd"}, ] autohooks-plugin-black = [ {file = "autohooks-plugin-black-1.2.0.tar.gz", hash = "sha256:e69a18209f3fd584da903e87faf0e3685caa4d51a9e870ddb3c2b1aef93387b8"}, {file = "autohooks_plugin_black-1.2.0-py3-none-any.whl", hash = "sha256:5099f620e01d3fcfd70195e63f101d003528b40475e921829a9ebde000f2c5ee"}, ] autohooks-plugin-pylint = [ {file = "autohooks-plugin-pylint-1.2.0.tar.gz", hash = "sha256:b1acc77b7845622d969ea2bfe5d8a95ae16a80c2282ca43888f522c9be479d10"}, {file = "autohooks_plugin_pylint-1.2.0-py3-none-any.whl", hash = "sha256:f08cef7ce4374661a2087e621e8fda411f3b2c19ebb7c92c7ac47b57892f7a3d"}, ] babel = [ {file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"}, {file = "Babel-2.9.0.tar.gz", hash = "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"}, ] bcrypt = [ {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, ] black = [ {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, ] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, ] cffi = [ {file = "cffi-1.14.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775"}, {file = "cffi-1.14.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06"}, {file = "cffi-1.14.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26"}, {file = "cffi-1.14.4-cp27-cp27m-win32.whl", hash = "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c"}, {file = "cffi-1.14.4-cp27-cp27m-win_amd64.whl", hash = "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b"}, {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d"}, {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca"}, {file = "cffi-1.14.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698"}, {file = "cffi-1.14.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b"}, {file = "cffi-1.14.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293"}, {file = "cffi-1.14.4-cp35-cp35m-win32.whl", hash = "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2"}, {file = "cffi-1.14.4-cp35-cp35m-win_amd64.whl", hash = "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7"}, {file = "cffi-1.14.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"}, {file = "cffi-1.14.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362"}, {file = "cffi-1.14.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec"}, {file = "cffi-1.14.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b"}, {file = "cffi-1.14.4-cp36-cp36m-win32.whl", hash = "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668"}, {file = "cffi-1.14.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009"}, {file = "cffi-1.14.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb"}, {file = "cffi-1.14.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d"}, {file = "cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03"}, {file = "cffi-1.14.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01"}, {file = "cffi-1.14.4-cp37-cp37m-win32.whl", hash = "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e"}, {file = "cffi-1.14.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35"}, {file = "cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d"}, {file = "cffi-1.14.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b"}, {file = "cffi-1.14.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53"}, {file = "cffi-1.14.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e"}, {file = "cffi-1.14.4-cp38-cp38-win32.whl", hash = "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d"}, {file = "cffi-1.14.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375"}, {file = "cffi-1.14.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909"}, {file = "cffi-1.14.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd"}, {file = "cffi-1.14.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a"}, {file = "cffi-1.14.4-cp39-cp39-win32.whl", hash = "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3"}, {file = "cffi-1.14.4-cp39-cp39-win_amd64.whl", hash = "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b"}, {file = "cffi-1.14.4.tar.gz", hash = "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c"}, ] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] colorful = [ {file = "colorful-0.5.4-py2.py3-none-any.whl", hash = "sha256:8d264b52a39aae4c0ba3e2a46afbaec81b0559a99be0d2cfe2aba4cf94531348"}, {file = "colorful-0.5.4.tar.gz", hash = "sha256:86848ad4e2eda60cd2519d8698945d22f6f6551e23e95f3f14dfbb60997807ea"}, ] coverage = [ {file = "coverage-5.3.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fabeeb121735d47d8eab8671b6b031ce08514c86b7ad8f7d5490a7b6dcd6267d"}, {file = "coverage-5.3.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:7e4d159021c2029b958b2363abec4a11db0ce8cd43abb0d9ce44284cb97217e7"}, {file = "coverage-5.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:378ac77af41350a8c6b8801a66021b52da8a05fd77e578b7380e876c0ce4f528"}, {file = "coverage-5.3.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e448f56cfeae7b1b3b5bcd99bb377cde7c4eb1970a525c770720a352bc4c8044"}, {file = "coverage-5.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:cc44e3545d908ecf3e5773266c487ad1877be718d9dc65fc7eb6e7d14960985b"}, {file = "coverage-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:08b3ba72bd981531fd557f67beee376d6700fba183b167857038997ba30dd297"}, {file = "coverage-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:8dacc4073c359f40fcf73aede8428c35f84639baad7e1b46fce5ab7a8a7be4bb"}, {file = "coverage-5.3.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ee2f1d1c223c3d2c24e3afbb2dd38be3f03b1a8d6a83ee3d9eb8c36a52bee899"}, {file = "coverage-5.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9a9d4ff06804920388aab69c5ea8a77525cf165356db70131616acd269e19b36"}, {file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:782a5c7df9f91979a7a21792e09b34a658058896628217ae6362088b123c8500"}, {file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:fda29412a66099af6d6de0baa6bd7c52674de177ec2ad2630ca264142d69c6c7"}, {file = "coverage-5.3.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:f2c6888eada180814b8583c3e793f3f343a692fc802546eed45f40a001b1169f"}, {file = "coverage-5.3.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8f33d1156241c43755137288dea619105477961cfa7e47f48dbf96bc2c30720b"}, {file = "coverage-5.3.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b239711e774c8eb910e9b1ac719f02f5ae4bf35fa0420f438cdc3a7e4e7dd6ec"}, {file = "coverage-5.3.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:f54de00baf200b4539a5a092a759f000b5f45fd226d6d25a76b0dff71177a714"}, {file = "coverage-5.3.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:be0416074d7f253865bb67630cf7210cbc14eb05f4099cc0f82430135aaa7a3b"}, {file = "coverage-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:c46643970dff9f5c976c6512fd35768c4a3819f01f61169d8cdac3f9290903b7"}, {file = "coverage-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9a4f66259bdd6964d8cf26142733c81fb562252db74ea367d9beb4f815478e72"}, {file = "coverage-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c6e5174f8ca585755988bc278c8bb5d02d9dc2e971591ef4a1baabdf2d99589b"}, {file = "coverage-5.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3911c2ef96e5ddc748a3c8b4702c61986628bb719b8378bf1e4a6184bbd48fe4"}, {file = "coverage-5.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c5ec71fd4a43b6d84ddb88c1df94572479d9a26ef3f150cef3dacefecf888105"}, {file = "coverage-5.3.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f51dbba78d68a44e99d484ca8c8f604f17e957c1ca09c3ebc2c7e3bbd9ba0448"}, {file = "coverage-5.3.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a2070c5affdb3a5e751f24208c5c4f3d5f008fa04d28731416e023c93b275277"}, {file = "coverage-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:535dc1e6e68fad5355f9984d5637c33badbdc987b0c0d303ee95a6c979c9516f"}, {file = "coverage-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a4857f7e2bc6921dbd487c5c88b84f5633de3e7d416c4dc0bb70256775551a6c"}, {file = "coverage-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fac3c432851038b3e6afe086f777732bcf7f6ebbfd90951fa04ee53db6d0bcdd"}, {file = "coverage-5.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cd556c79ad665faeae28020a0ab3bda6cd47d94bec48e36970719b0b86e4dcf4"}, {file = "coverage-5.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a66ca3bdf21c653e47f726ca57f46ba7fc1f260ad99ba783acc3e58e3ebdb9ff"}, {file = "coverage-5.3.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ab110c48bc3d97b4d19af41865e14531f300b482da21783fdaacd159251890e8"}, {file = "coverage-5.3.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e52d3d95df81c8f6b2a1685aabffadf2d2d9ad97203a40f8d61e51b70f191e4e"}, {file = "coverage-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:fa10fee7e32213f5c7b0d6428ea92e3a3fdd6d725590238a3f92c0de1c78b9d2"}, {file = "coverage-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ce6f3a147b4b1a8b09aae48517ae91139b1b010c5f36423fa2b866a8b23df879"}, {file = "coverage-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:93a280c9eb736a0dcca19296f3c30c720cb41a71b1f9e617f341f0a8e791a69b"}, {file = "coverage-5.3.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3102bb2c206700a7d28181dbe04d66b30780cde1d1c02c5f3c165cf3d2489497"}, {file = "coverage-5.3.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8ffd4b204d7de77b5dd558cdff986a8274796a1e57813ed005b33fd97e29f059"}, {file = "coverage-5.3.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a607ae05b6c96057ba86c811d9c43423f35e03874ffb03fbdcd45e0637e8b631"}, {file = "coverage-5.3.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:3a3c3f8863255f3c31db3889f8055989527173ef6192a283eb6f4db3c579d830"}, {file = "coverage-5.3.1-cp38-cp38-win32.whl", hash = "sha256:ff1330e8bc996570221b450e2d539134baa9465f5cb98aff0e0f73f34172e0ae"}, {file = "coverage-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:3498b27d8236057def41de3585f317abae235dd3a11d33e01736ffedb2ef8606"}, {file = "coverage-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ceb499d2b3d1d7b7ba23abe8bf26df5f06ba8c71127f188333dddcf356b4b63f"}, {file = "coverage-5.3.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3b14b1da110ea50c8bcbadc3b82c3933974dbeea1832e814aab93ca1163cd4c1"}, {file = "coverage-5.3.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:76b2775dda7e78680d688daabcb485dc87cf5e3184a0b3e012e1d40e38527cc8"}, {file = "coverage-5.3.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:cef06fb382557f66d81d804230c11ab292d94b840b3cb7bf4450778377b592f4"}, {file = "coverage-5.3.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f61319e33222591f885c598e3e24f6a4be3533c1d70c19e0dc59e83a71ce27d"}, {file = "coverage-5.3.1-cp39-cp39-win32.whl", hash = "sha256:cc6f8246e74dd210d7e2b56c76ceaba1cc52b025cd75dbe96eb48791e0250e98"}, {file = "coverage-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:2757fa64e11ec12220968f65d086b7a29b6583d16e9a544c889b22ba98555ef1"}, {file = "coverage-5.3.1-pp36-none-any.whl", hash = "sha256:723d22d324e7997a651478e9c5a3120a0ecbc9a7e94071f7e1954562a8806cf3"}, {file = "coverage-5.3.1-pp37-none-any.whl", hash = "sha256:c89b558f8a9a5a6f2cfc923c304d49f0ce629c3bd85cb442ca258ec20366394c"}, {file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"}, ] cryptography = [ {file = "cryptography-3.3.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030"}, {file = "cryptography-3.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0"}, {file = "cryptography-3.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812"}, {file = "cryptography-3.3.1-cp27-cp27m-win32.whl", hash = "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e"}, {file = "cryptography-3.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901"}, {file = "cryptography-3.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d"}, {file = "cryptography-3.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5"}, {file = "cryptography-3.3.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302"}, {file = "cryptography-3.3.1-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244"}, {file = "cryptography-3.3.1-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c"}, {file = "cryptography-3.3.1-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c"}, {file = "cryptography-3.3.1-cp36-abi3-win32.whl", hash = "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a"}, {file = "cryptography-3.3.1-cp36-abi3-win_amd64.whl", hash = "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7"}, {file = "cryptography-3.3.1.tar.gz", hash = "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6"}, ] defusedxml = [ {file = "defusedxml-0.6.0-py2.py3-none-any.whl", hash = "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93"}, {file = "defusedxml-0.6.0.tar.gz", hash = "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"}, ] docutils = [ {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] isort = [ {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, ] jinja2 = [ {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, ] lazy-object-proxy = [ {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"}, {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"}, {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"}, {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"}, {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"}, {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"}, {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"}, {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"}, {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"}, {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"}, {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"}, {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"}, {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"}, {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"}, {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"}, {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"}, {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"}, {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"}, {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"}, {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, ] lxml = [ {file = "lxml-4.6.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f"}, {file = "lxml-4.6.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d"}, {file = "lxml-4.6.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2"}, {file = "lxml-4.6.2-cp27-cp27m-win32.whl", hash = "sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e"}, {file = "lxml-4.6.2-cp27-cp27m-win_amd64.whl", hash = "sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e"}, {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2"}, {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe"}, {file = "lxml-4.6.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388"}, {file = "lxml-4.6.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80"}, {file = "lxml-4.6.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b"}, {file = "lxml-4.6.2-cp35-cp35m-win32.whl", hash = "sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8"}, {file = "lxml-4.6.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780"}, {file = "lxml-4.6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af"}, {file = "lxml-4.6.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37"}, {file = "lxml-4.6.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98"}, {file = "lxml-4.6.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d"}, {file = "lxml-4.6.2-cp36-cp36m-win32.whl", hash = "sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf"}, {file = "lxml-4.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939"}, {file = "lxml-4.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e"}, {file = "lxml-4.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711"}, {file = "lxml-4.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089"}, {file = "lxml-4.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01"}, {file = "lxml-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2"}, {file = "lxml-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc"}, {file = "lxml-4.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d"}, {file = "lxml-4.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3"}, {file = "lxml-4.6.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644"}, {file = "lxml-4.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308"}, {file = "lxml-4.6.2-cp38-cp38-win32.whl", hash = "sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505"}, {file = "lxml-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a"}, {file = "lxml-4.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931"}, {file = "lxml-4.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03"}, {file = "lxml-4.6.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5"}, {file = "lxml-4.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a"}, {file = "lxml-4.6.2-cp39-cp39-win32.whl", hash = "sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75"}, {file = "lxml-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf"}, {file = "lxml-4.6.2.tar.gz", hash = "sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc"}, ] markupsafe = [ {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ {file = "packaging-20.8-py2.py3-none-any.whl", hash = "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858"}, {file = "packaging-20.8.tar.gz", hash = "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"}, ] paramiko = [ {file = "paramiko-2.7.2-py2.py3-none-any.whl", hash = "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898"}, {file = "paramiko-2.7.2.tar.gz", hash = "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035"}, ] pathspec = [ {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, ] pontos = [ {file = "pontos-0.3.1-py3-none-any.whl", hash = "sha256:b210fbada72003326537f0e7ebd105614b6a9c5d3cc0aee0d3f2e8b4da00322f"}, {file = "pontos-0.3.1.tar.gz", hash = "sha256:7a9e0f5abbc0de0ee973e9b23c70385dd6b9833a74a4c16193141ebeae76e198"}, ] pycparser = [ {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, ] pygments = [ {file = "Pygments-2.7.4-py3-none-any.whl", hash = "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435"}, {file = "Pygments-2.7.4.tar.gz", hash = "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"}, ] pylint = [ {file = "pylint-2.6.0-py3-none-any.whl", hash = "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"}, {file = "pylint-2.6.0.tar.gz", hash = "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210"}, ] pynacl = [ {file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"}, {file = "PyNaCl-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514"}, {file = "PyNaCl-1.4.0-cp27-cp27m-win32.whl", hash = "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574"}, {file = "PyNaCl-1.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80"}, {file = "PyNaCl-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7"}, {file = "PyNaCl-1.4.0-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122"}, {file = "PyNaCl-1.4.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d"}, {file = "PyNaCl-1.4.0-cp35-abi3-win32.whl", hash = "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634"}, {file = "PyNaCl-1.4.0-cp35-abi3-win_amd64.whl", hash = "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6"}, {file = "PyNaCl-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4"}, {file = "PyNaCl-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25"}, {file = "PyNaCl-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4"}, {file = "PyNaCl-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6"}, {file = "PyNaCl-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f"}, {file = "PyNaCl-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f"}, {file = "PyNaCl-1.4.0-cp38-cp38-win32.whl", hash = "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96"}, {file = "PyNaCl-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420"}, {file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] python-gvm = [ {file = "python-gvm-21.1.1.tar.gz", hash = "sha256:36bd41d3534e7d378c4e0c38509ebd27ae8f40354cf6baa494bb95bc35d27191"}, {file = "python_gvm-21.1.1-py3-none-any.whl", hash = "sha256:7bbc4da6d112c147cb7c102d2eb487440b21b1cb8eab563064807ab204547bf0"}, ] pytz = [ {file = "pytz-2020.5-py2.py3-none-any.whl", hash = "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4"}, {file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"}, ] regex = [ {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, ] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] rope = [ {file = "rope-0.18.0.tar.gz", hash = "sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04"}, ] six = [ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] snowballstemmer = [ {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] sphinx = [ {file = "Sphinx-3.4.3-py3-none-any.whl", hash = "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8"}, {file = "Sphinx-3.4.3.tar.gz", hash = "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c"}, ] sphinxcontrib-applehelp = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, ] sphinxcontrib-devhelp = [ {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] sphinxcontrib-htmlhelp = [ {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"}, {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"}, ] sphinxcontrib-jsmath = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] sphinxcontrib-qthelp = [ {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, ] sphinxcontrib-serializinghtml = [ {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomlkit = [ {file = "tomlkit-0.5.11-py2.py3-none-any.whl", hash = "sha256:4e1bd6c9197d984528f9ff0cc9db667c317d8881288db50db20eeeb0f6b0380b"}, {file = "tomlkit-0.5.11.tar.gz", hash = "sha256:f044eda25647882e5ef22b43a1688fb6ab12af2fc50e8456cdfc751c873101cf"}, ] typed-ast = [ {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, ] typing-extensions = [ {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] urllib3 = [ {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, ] wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] gvm-tools-21.1.0/poetry.toml000066400000000000000000000000401400201773500157320ustar00rootroot00000000000000[virtualenvs] in-project = true gvm-tools-21.1.0/pyproject.toml000066400000000000000000000040331400201773500164350ustar00rootroot00000000000000[build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" [tool.poetry] name = "gvm-tools" version = "21.1.0" authors = ["Greenbone Networks GmbH "] description = "Tools to control a GSM/GVM over GMP or OSP" license = "GPL-3.0-or-later" readme = "README.md" homepage = "https://github.com/greenbone/gvm-tools/" repository = "https://github.com/greenbone/gvm-tools/" documentation = "https://gvm-tools.readthedocs.io/" classifiers=[ # Full list: https://pypi.org/pypi?%3Aaction=list_classifiers 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Operating System :: OS Independent', 'Topic :: Software Development :: Libraries :: Python Modules', ] packages = [ { include = "gvmtools" }, { include = "tests", format = "sdist" }, { include = "scripts", format = "sdist" }, ] [tool.poetry.scripts] gvm-pyshell = "gvmtools.pyshell:main" gvm-cli = "gvmtools.cli:main" gvm-script = "gvmtools.script:main" [tool.poetry.dependencies] python = "^3.7.0" python-gvm = ">=1.4,<22.0" [tool.poetry.dev-dependencies] autohooks = "^2.2.0" autohooks-plugin-pylint = "^1.2.0" sphinx = "^3.4.3" pylint = "^2.5.3" coverage = "^5.3" autohooks-plugin-black = {version = "^1.2.0", python = "^3.6"} black = {version = "20.8b1", python = "^3.6"} rope = "^0.18.0" pontos = "^0.3.1" [tool.black] line-length = 80 target-version = ['py35', 'py36', 'py37', 'py38'] skip-string-normalization = true exclude = ''' /( \.git | \.hg | \.venv | \.circleci | \.github | \.vscode | _build | build | dist | docs )/ ''' [tool.autohooks] mode = "poetry" pre-commit = ['autohooks.plugins.black', 'autohooks.plugins.pylint'] [tool.pontos.version] version-module-file = "gvmtools/__version__.py" gvm-tools-21.1.0/scripts/000077500000000000000000000000001400201773500152105ustar00rootroot00000000000000gvm-tools-21.1.0/scripts/.pylintrc000066400000000000000000000346521400201773500170670ustar00rootroot00000000000000[MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist=lxml # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns=docs # Pickle collected data for later comparisons. persistent=yes # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # # bad-continuation is disabled because of a bug in pylint. # See https://github.com/ambv/black/issues/48 and https://github.com/PyCQA/pylint/issues/289 disable=len-as-condition, attribute-defined-outside-init, missing-docstring, bad-continuation #disable=print-statement, # parameter-unpacking, # unpacking-in-except, # old-raise-syntax, # backtick, # long-suffix, # old-ne-operator, # old-octal-literal, # import-star-module-level, # non-ascii-bytes-literal, # raw-checker-failed, # bad-inline-option, # locally-disabled, # locally-enabled, # file-ignored, # suppressed-message, # useless-suppression, # deprecated-pragma, # apply-builtin, # basestring-builtin, # buffer-builtin, # cmp-builtin, # coerce-builtin, # execfile-builtin, # file-builtin, # long-builtin, # raw_input-builtin, # reduce-builtin, # standarderror-builtin, # unicode-builtin, # xrange-builtin, # coerce-method, # delslice-method, # getslice-method, # setslice-method, # no-absolute-import, # old-division, # dict-iter-method, # dict-view-method, # next-method-called, # metaclass-assignment, # indexing-exception, # raising-string, # reload-builtin, # oct-method, # hex-method, # nonzero-method, # cmp-method, # input-builtin, # round-builtin, # intern-builtin, # unichr-builtin, # map-builtin-not-iterating, # zip-builtin-not-iterating, # range-builtin-not-iterating, # filter-builtin-not-iterating, # using-cmp-argument, # eq-without-hash, # div-method, # idiv-method, # rdiv-method, # exception-message-attribute, # invalid-str-codec, # sys-max-int, # bad-python3-import, # deprecated-string-function, # deprecated-str-translate-call, # deprecated-itertools-function, # deprecated-types-field, # next-method-defined, # dict-items-not-iterating, # dict-keys-not-iterating, # dict-values-not-iterating # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio).You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Tells whether to display a full report or only the messages reports=no # Activate the evaluation score. score=no [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=optparse.Values,sys.exit [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins=gmp,osp,args # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX [BASIC] # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{1,40}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{1,40}$ # Bad variable names which should always be refused, separated by a comma bad-names=foo, bar, baz, toto, tutu, tata # Regular expression matching correct class attribute names. class-attribute-rgx=([a-z_][a-z0-9_]{1,40})|([A-Z_][A-Z0-9_]{1,30})$ # Naming style matching correct class names class-naming-style=PascalCase # Naming style matching correct constant names const-naming-style=UPPER_CASE # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=3 # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]+$ # Good variable names which should always be accepted, separated by a comma good-names=e, f, i, j, k, ex, Run, logger, _ # Include a hint for the correct naming format with invalid-name include-naming-hint=yes # Regular expression matching correct inline iteration names. inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]+$ # Regular expression which should only match correct module names module-rgx=([a-z]+)|(test_*)$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. property-classes=abc.abstractproperty # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]+$ [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format=LF # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=80 # Maximum number of lines in a module max-module-lines=1000 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma, dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [IMPORTS] # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant [DESIGN] # Maximum number of arguments for function / method max-args=15 # Maximum number of attributes for a class (see R0902). max-attributes=20 # Maximum number of boolean expressions in a if statement max-bool-expr=5 # Maximum number of branch for function / method body max-branches=12 # Maximum number of locals for function / method body max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=30 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of statements in function / method body max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=0 [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception gvm-tools-21.1.0/scripts/README.md000066400000000000000000000264161400201773500165000ustar00rootroot00000000000000![Greenbone Logo](https://www.greenbone.net/wp-content/uploads/gb_logo_resilience_horizontal.png) # GVM Example Scripts ## `application-detection.gmp.py` This script will search the reports and display all hosts with the requested applications! ### Arguments * ``: Name of the application ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/application-detection.gmp.py ` --- ## `cfg-gen-for-certs.gmp.py` This script creates a new scan config with nvts from a given CERT-Bund! ### Arguments * ``: Name or ID of the CERT-Bund ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/cfg-gen-for-certs.gmp.py CB-K16/0943` --- ## `check-gmp.gmp.py` This script can test different methods of the gmp API. | Optional argument | Description | | --- | --- | |`-H`: | Show this help message and exit |`-V`, `--version`: | Show program's version number and exit |`--cache [CACHE]`: | Path to cache file. Default: `/var/folders/mk/ dfxkj16j4779x98r26n21qnr0000gn/ T/check_gmp/reports.db` | `--clean` | Activate to clean the database | `-u GMP_USERNAME`, `--gmp-username GMP_USERNAME` | GMP username | `-w GMP_PASSWORD`, `--gmp-password GMP_PASSWORD` | GMP password |`-F HOSTADDRESS`, `--hostaddress HOSTADDRESS` | Report last report status of host ``. |`-T TASK`, `--task TASK` | Report status of task ``. |`--apply-overrides` | Apply overrides. |`--overrides` | Include overrides. |`-d`, `--details` | Include connection details in output. |`-l`, `--report-link` | Include URL of report in output. |`--dfn` | Include DFN-CERT IDs on vulnerabilities in output. |`--oid` | Include OIDs of NVTs finding vulnerabilities in output. |`--descr` | Include descriptions of NVTs finding vulnerabilities in output. |`--showlog` | Include log messages in output. | `--show-ports` | Include port of given vulnerable nvt in output. | `--scanend` | Include timestamp of scan end in output. | `--autofp {0,1,2}` | Trust vendor security updates for automatic false positive filtering (`0=No`, `1=full match`, `2=partial`). | `-e`, `--empty-as-unknown` | Respond with `UNKNOWN` on empty results. | `-I MAX_RUNNING_INSTANCES`, `--max-running-instances MAX_RUNNING_INSTANCES` | Set the maximum simultaneous processes of check-gmp | `--hostname [HOSTNAME]` | `--ping` | Ping the gsm appliance. | `--status` | Report status of task. | `--days DAYS` | Delete database entries that are older than given days. | `--ip IP` | Delete database entry for given ip. | `--trend` | Report status by trend. | `--last-report` | Report status by last report. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/check-gmp.gmp.py --ip 127.0.0.1 --ping` --- ## `clean-sensor.gmp.py` This script removes all resources from a sensor, except active tasks. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/clean-sensor.gmp.py` --- ## `combine-reports.gmp.py` This script will combine desired reports into a single report. The combined report will then be sent to a desired container task. This script will create a container task for the combined report to be sent to, however, if you would like the report to be sent to an existing task, place the report of the desired task first and add the argument 'first_task'. ### Arguments * `, ..., `: UUIDs of the reports to be combined ### Example `$ gvm-script --gmp-username=namessh --gmp-password=pass ssh --hostname=hostname scripts/combine-reports.gmp.py "d15a337c-56f3-4208-a462-afeb79eb03b7" "303fa0a6-aa9b-43c4-bac0-66ae0b2d1698" 'first_task'` --- ## `create-dummy-data.gmp.py` This script will create random data in the given GVM database. ### Arguments * ``: Number of datasets to create ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/create-dummy-data.gmp.py ` --- ## `create-targets-from-host-list.gmp.py` This script pulls hostnames from a text file and creates a target for each. ### Arguments * ``: IP of the GVM host * ``: text file containing hostnames ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/create_targets_from_host_list.gmp.py ` --- ## `delete-overrides-by-filter.gmp.py` This script deletes overrides with a specific filter value. ### Arguments * ``: the parameter for the filter. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/delete-overrides-by-filter.gmp.py ` --- ## `gen-random-targets.gmp.py` This script generates random task data and feeds it to a desired GSM database. ### Arguments * ``: number of dummy hosts to select from * ``: number of targets to be generated * `'with-gauss'`: (optional), if you would like for the number of targets generated to be randomized on a Gaussian distribution ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/gen-random-targets.gmp.py 3 40 with-gauss` --- ## `list-tasks.gmp.py` Lists the tasks stored in an GSM Database ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/list-tasks.gmp.py` --- ## `monthly-report.gmp.py` This script will display all vulnerabilities from the hosts of the reports in a given month! ### Arguments * ``: month of the monthly report * ``: year of the monthly report * `'with-tables'`: (optional), parameter to activate a verbose output of hosts. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/monthly-report.gmp.py 05 2019 with-tables` --- ## `monthly-report2.gmp.py` This script will display all vulnerabilities from the hosts of the reports in a given month! ### Arguments * ``: month of the monthly report * ``: year of the monthly report ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/monthly-report2.gmp.py 05 2019` --- ## `nvt-scan.gmp.py` This script creates a new task with specific host and nvt! ### Arguments * ``: oid of the nvt * ``: scan target. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname 1.3.6.1.4.1.25623.1.0.106223 localhost` --- ## `pdf-report.gmp.py` This script requests the given report and saves it as a pdf file locally. ### Arguments * ``: ID of the report * ``: (optional), pdf file name ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/pdf-report.gmp.py ` --- ## `random-report-gen.gmp.py` This script generates randomized report data. ### Arguments * ``: number of tasks to be generated * ``: number of reports per task * ``: number of results per report * ``: number of randomized hosts to select from * `'with-gauss'`: if you would like for the number of reports/task and results/report to be randomized along a Gaussian distribution ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/random-report-gen.gmp.py 10 50 2500 256 with-gauss` --- ## `scan-new-system.gmp.py` This script starts a new scan on the given host. ### Arguments * `` IP Address of the host system ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/scan-new-system.gmp.py ` --- ## `send-delta-emails.gmp.py` This script, once started, will continuously send delta reports via email for selected tasks. The routine follows this procedure: Every `` minutes do: * Get all tasks where the tag `` is attached. * For each of these tasks get the finished reports: * If less than 2 reports, continue with next task * If latest report has tag "delta_alert_sent", continue with next task * Create a CSV report from the delta of latest vs. previous report where filtered for only the new results. * Send the CSV as an attachment to the configured email address. > You may edit the scripts hardcoded variables like `from_address`, `to_address`, etc. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/send-delta-emails.gmp.py` --- ## `send-schedules.gmp.py` This script pulls schedule data from an xml document and feeds it to a desired GSM. ### Arguments * ``: .xml file containing schedules ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/send-schedules.gmp.py example_file.xml` --- ## `send-targets.gmp.py` This script pulls target data from an xml document and feeds it to a desired GSM. ### Arguments * ``: .xml file containing schedules ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/send-targets.gmp.py example_file.xml` --- ## `send-tasks.gmp.py` This script pulls tasks data from an xml document and feeds it to a desired GSM. ### Arguments * ``: .xml file containing schedules ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/send-tasks.gmp.py example_file.xml` --- ## `start-alert-scan.gmp.py` This script makes an alert scan and sends the report via email. ### Arguments * ``: E-Mail of the sender * ``: E-Mail of the receiver ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/start-alert-scan.gmp.py ` --- ## `start-multiple-alerts-scan.gmp.py` This script makes an alert scan and sends the report via email. ### Arguments * ``: E-Mail of the sender * ``: E-Mail of the receiver ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/start-multiple-alerts-scan.gmp.py ` --- ## `start-nvt-scan.gmp.py` This script creates a new task (if the target is not existing) with specific host and nvt! ### Arguments * ``: oid of the nvt * ``: scan target. ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/start-nvt-scan.gmp.py 1.3.6.1.4.1.25623.1.0.106223 localhost` --- ## `sync-assets.gmp.py` This script reads asset data from a csv file and sync it with the gsm. ### Arguments * ``: should contain a table of IP-addresses with an optional a comment ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/sync-assets.gmp.py ` --- ## `update-task-target.gmp.py` This script will update target hosts information for a desired task. ### Arguments * ``: .csv file containing desired target hosts separated by ',' * ``: uuid of task to be modified ### Example `$ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/update-task-target.gmp.py hosts_file.csv "303fa0a6-aa9b-43c4-bac0-66ae0b2d1698"` gvm-tools-21.1.0/scripts/application-detection.gmp.py000066400000000000000000000037561400201773500226360ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys def check_args(args): len_args = len(args.script) - 1 if len_args is not 1: message = """ This script will display all hosts with the searched applications! 1. -- Name of the application Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/application-detection.gmp.py """ print(message) sys.exit() def print_assets(gmp, appname): res = gmp.get_reports() hosts = res.xpath('//host') for host in hosts: ip = host.xpath('ip/text()') hostname = host.xpath('detail/name[text()="hostname"]/../value/text()') if len(hostname) is 0: hostname = "" else: hostname = hostname[0] print('{ip} ({hostname})'.format(ip=ip, hostname=hostname)) apps = host.xpath( 'detail/name[text() = "App"]/../value[' 'contains(text(), "{0}")]/text()'.format(appname) ) for app in apps: print('\t' + app) print('\n') def main(gmp, args): # pylint: disable=undefined-variable check_args(args) print_assets(gmp, args.script[1]) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/cfg-gen-for-certs.gmp.py000066400000000000000000000062701400201773500215610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from gvm.errors import GvmError def check_args(args): len_args = len(args.script) - 1 if len_args is not 1: message = """ This script creates a new scan config with nvts from a given CERT-Bund! It needs one parameter after the script name. 1. -- Name or ID of the CERT-Bund Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/cfg-gen-for-certs.gmp.py CB-K16/0943 """ print(message) sys.exit() def create_config(gmp, cert_bund_name): cert_bund_details = gmp.get_info( info_id=cert_bund_name, info_type=gmp.types.InfoType.CERT_BUND_ADV ) list_cves = cert_bund_details.xpath( 'info/cert_bund_adv/raw_data/Advisory/CVEList/CVE/text()' ) nvt_dict = dict() counter = 0 for cve in list_cves: # Get all nvts of this cve cve_info = gmp.get_info(info_id=cve, info_type=gmp.types.InfoType.CVE) nvts = cve_info.xpath('info/cve/nvts/nvt') for nvt in nvts: counter += 1 oid = nvt.xpath('@oid')[0] # We need the nvt family to modify scan config nvt_data = gmp.get_nvt(oid) family = nvt_data.xpath('nvt/family/text()')[0] # Create key value map if family in nvt_dict and oid not in nvt_dict[family]: nvt_dict[family].append(oid) else: nvt_dict[family] = [oid] # Create new config copy_id = '085569ce-73ed-11df-83c3-002264764cea' config_name = 'scanconfig_for_%s' % cert_bund_name config_id = '' try: res = gmp.create_config(copy_id, config_name) config_id = res.xpath('@id')[0] # Modify the config with the nvts oid for family, nvt_oid in nvt_dict.items(): gmp.modify_config(config_id, nvt_oids=nvt_oid, family=family) # This nvts must be present to work family = 'Port scanners' nvts = ['1.3.6.1.4.1.25623.1.0.14259', '1.3.6.1.4.1.25623.1.0.100315'] gmp.modify_config(config_id=config_id, nvt_oids=nvts, family=family) except GvmError: print('Config exist') def main(gmp, args): # pylint: disable=undefined-variable check_args(args) cert_bund_name = args.script[1] print('Creating scan config for {0}'.format(cert_bund_name)) create_config(gmp, cert_bund_name) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/check-gmp.gmp.py000066400000000000000000001232511400201773500202060ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # pylint: disable=too-many-lines import logging import os import re import signal import sqlite3 import sys import tempfile from argparse import ArgumentParser, RawTextHelpFormatter from datetime import datetime, timedelta, tzinfo from decimal import Decimal from pathlib import Path from lxml import etree __version__ = "2.0.0" logger = logging.getLogger(__name__) HELP_TEXT = """ Check-GMP Nagios Command Plugin {version} (C) 2017-2021 Greenbone Networks GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """.format( version=__version__ ) NAGIOS_OK = 0 NAGIOS_WARNING = 1 NAGIOS_CRITICAL = 2 NAGIOS_UNKNOWN = 3 NAGIOS_MSG = ["OK", "WARNING", "CRITICAL", "UNKNOWN"] MAX_RUNNING_INSTANCES = 10 class InstanceManager: """Class for managing instances of this plugin All new reports will be cached in a sqlite database. The first call with a unknown host takes longer, because the remote gvmd/openvasmd has to generate the report. The second call will retrieve the data from the database if the scan duration does not differ. Additionally this class handles all instances of check-gmp. No more than MAX_RUNNING_INSTANCES can run simultaneously. Other instances are stopped and wait for continuation. """ def __init__(self, path, parser): """Initialise the sqlite database. Create it if it does not exist else connect to it. Arguments: path (string): Path to the database. """ self.cursor = None self.con_db = None self.db = Path(path) self.pid = os.getpid() # Try to read file with information about cached reports # First check whether the file exist or not try: exist = self.db.is_file() logger.debug("DB file exist?: %s ", exist) if not exist: if not self.db.parent.is_dir(): self.db.parent.mkdir(parents=True, exist_ok=True) else: self.db.touch() # Connect to db self.connect_db() # Create the tables self.cursor.execute( """CREATE TABLE Report( host text, scan_end text, params_used text, report text )""" ) self.cursor.execute( """CREATE TABLE Instance( created_at text, pid integer, pending integer default 0 )""" ) logger.debug("Tables created") else: self.connect_db() except PermissionError: parser.error( "The selected temporary database file {} or the parent dir has" " not the correct permissions.".format(self.db) ) @staticmethod def _to_sql_bool(pending): """Replace True/False with 1/0.""" return '1' if pending else '0' def connect_db(self): """Connect to the database Simply connect to the database at location """ try: logger.debug("connect db: %s", self.db) self.con_db = sqlite3.connect(str(self.db)) self.cursor = self.con_db.cursor() logger.debug(sqlite3.sqlite_version) except Exception as e: # pylint: disable=broad-except logger.debug(e) def close_db(self): """Close database""" self.con_db.close() def set_host(self, host): """Sets the host variable Arguments: host (string): Given ip or hostname of target. """ self.host = host def is_old_report(self, last_scan_end, params_used): """Decide whether the current report is old or not At first the last scanend and the params that were used are fetched from the database. If no report is fetched, then True will be returned. The next step is to compare the old and the new scanend. If the scanends matches, then return False, because it is the same report. Else the old report will be deleted. Arguments: last_scan_end (string): Last scan end of report params_used (string): Params used for this check Returns: True if it is an old report or empty. False if it is the same report. """ # Before we do anything here, check existing instance # Retrieve the scan_end value self.cursor.execute( "SELECT scan_end, params_used FROM Report WHERE" " host=?", (self.host,), ) db_entry = self.cursor.fetchone() logger.debug("%s %s", db_entry, last_scan_end) if not db_entry: return True else: old = parse_date(db_entry[0]) new = parse_date(last_scan_end) logger.debug( "Old time (from db): %s\n" "New time (from rp): %s", old, new ) if new <= old and params_used == db_entry[1]: return False else: # Report is newer. Delete old entry. logger.debug("Delete old report for host %s", self.host) self.delete_report() return True def load_local_report(self): """Load report from local database Select the report from the database according due the hostname or ip. Returns: An lxml ElementTree """ self.cursor.execute( "SELECT report FROM Report WHERE host=?", (self.host,) ) db_entry = self.cursor.fetchone() if db_entry: return etree.fromstring(db_entry[0]) else: logger.debug("Report from host %s is not in the db", self.host) def add_report(self, scan_end, params_used, report): """Create new entry with the lxml report Create a string from the lxml object and add it to the database. Additional data is the scanend and the params used. Arguments: scan_end (string): Scan end of the report params_used (string): Params used for this check report (obj): An lxml ElementTree """ data = etree.tostring(report) logger.debug("add_report: %s, %s, %s", self.host, scan_end, params_used) # Insert values self.cursor.execute( "INSERT INTO Report VALUES (?, ?, ?, ?)", (self.host, scan_end, params_used, data), ) # Save the changes self.con_db.commit() def delete_report(self): """Delete report from database""" self.cursor.execute("DELETE FROM Report WHERE host=?", (self.host,)) # Save the changes self.con_db.commit() def delete_entry_with_ip(self, ip): """Delete report from database with given ip Arguments: ip (string): IP-Adress """ logger.debug("Delete entry with ip: %s", ip) self.cursor.execute("DELETE FROM Report WHERE host=?", (ip,)) self.con_db.isolation_level = None self.cursor.execute("VACUUM") self.con_db.isolation_level = '' # see: https://github.com/CxAalto/gtfspy/commit/8d05c3c94a6d4ca3ed675d88af93def7d5053bfe # pylint: disable=line-too-long # Save the changes self.con_db.commit() def delete_older_entries(self, days): """Delete reports from database older than given days Arguments: days (int): Number of days in past """ logger.debug("Delete entries older than: %s days", days) self.cursor.execute( "DELETE FROM Report WHERE scan_end <= " 'date("now", "-%s day")' % days ) self.cursor.execute("VACUUM") # Save the changes self.con_db.commit() def has_entries(self, pending): """Return number of instance entries Arguments: pending (bool): True for pending instances. False for running instances. Returns: The number of pending or non pending instances entries. """ self.cursor.execute( "SELECT count(*) FROM Instance WHERE pending=?", (self._to_sql_bool(pending),), ) res = self.cursor.fetchone() return res[0] def check_instances(self): """This method checks the status of check-gmp instances. Checks whether instances are pending or not and start instances according to the number saved in the MAX_RUNNING_INSTANCES variable. """ # Need to check whether any instances are in the database that were # killed f.e. because a restart of nagios self.clean_orphaned_instances() # How many processes are currently running? number_instances = self.has_entries(pending=False) # How many pending entries are waiting? number_pending_instances = self.has_entries(pending=True) logger.debug( "check_instances: %i %i", number_instances, number_pending_instances ) if ( number_instances < MAX_RUNNING_INSTANCES and number_pending_instances == 0 ): # Add entry for running process and go on logger.debug("Fall 1") self.add_instance(pending=False) elif ( number_instances < MAX_RUNNING_INSTANCES and number_pending_instances > 0 ): # Change pending entries and wake them up until enough instances # are running logger.debug("Fall 2") while ( number_instances < MAX_RUNNING_INSTANCES and number_pending_instances > 0 ): pending_entries = self.get_oldest_pending_entries( MAX_RUNNING_INSTANCES - number_instances ) logger.debug("Oldest pending pids: %s", pending_entries) for entry in pending_entries: created_at = entry[0] pid = entry[1] # Change status to not pending and continue the process self.update_pending_status(created_at, False) self.start_process(pid) # Refresh number of instances for next while loop number_instances = self.has_entries(pending=False) number_pending_instances = self.has_entries(pending=True) # TODO: Check if this is really necessary # self.add_instance(pending=False) # if number_instances >= MAX_RUNNING_INSTANCES: # self.stop_process(self.pid) elif ( number_instances >= MAX_RUNNING_INSTANCES and number_pending_instances == 0 ): # There are running enough instances and no pending instances # Add new entry with pending status true and stop this instance logger.debug("Fall 3") self.add_instance(pending=True) self.stop_process(self.pid) elif ( number_instances >= MAX_RUNNING_INSTANCES and number_pending_instances > 0 ): # There are running enough instances and there are min one # pending instance # Add new entry with pending true and stop this instance logger.debug("Fall 4") self.add_instance(pending=True) self.stop_process(self.pid) # If an entry is pending and the same params at another process is # starting, then exit with gmp pending since data # if self.has_pending_entries(): # Check if an pending entry is the same as this process # If hostname # date = datetime.now() # end_session('GMP PENDING: since %s' % date, NAGIOS_OK) # end_session('GMP RUNNING: since', NAGIOS_OK) def add_instance(self, pending): """Add new instance entry to database Retrieve the current time in ISO 8601 format. Create a new entry with pending status and the dedicated pid Arguments: pending (bool): State of instance """ current_time = datetime.now().isoformat() # Insert values self.cursor.execute( "INSERT INTO Instance VALUES (?, ?, ?)", (current_time, self.pid, self._to_sql_bool(pending)), ) # Save the changes self.con_db.commit() def get_oldest_pending_entries(self, number): """Return the oldest last entries of pending entries from database Return: the oldest instances with status pending limited by the variable """ self.cursor.execute( "SELECT * FROM Instance WHERE pending=1 ORDER BY " "created_at LIMIT ? ", (number,), ) return self.cursor.fetchall() def update_pending_status(self, date, pending): """Update pending status of instance The date variable works as a primary key for the instance table. The entry with date get his pending status updated. Arguments: date (string): Date of creation for entry pending (bool): Status of instance """ self.cursor.execute( "UPDATE Instance SET pending=? WHERE created_at=?", (self._to_sql_bool(pending), date), ) # Save the changes self.con_db.commit() def delete_instance(self, pid=None): """Delete instance from database If a pid different from zero is given, then delete the entry with given pid. Else delete the entry with the pid stored in this class instance. Keyword Arguments: pid (number): Process Indentificattion Number (default: {0}) """ if not pid: pid = self.pid logger.debug("Delete entry with pid: %i", pid) self.cursor.execute("DELETE FROM Instance WHERE pid=?", (pid,)) # Save the changes self.con_db.commit() def clean_orphaned_instances(self): """Delete non existing instance entries This method check whether a pid exist on the os and if not then delete the orphaned entry from database. """ self.cursor.execute("SELECT pid FROM Instance") pids = self.cursor.fetchall() for pid in pids: if not self.check_pid(pid[0]): self.delete_instance(pid[0]) def wake_instance(self): """Wake up a pending instance This method is called at the end of any session from check_gmp. Get the oldest pending entries and wake them up. """ # How many processes are currently running? number_instances = self.has_entries(pending=False) # How many pending entries are waiting? number_pending_instances = self.has_entries(pending=True) if ( number_instances < MAX_RUNNING_INSTANCES and number_pending_instances > 0 ): pending_entries = self.get_oldest_pending_entries( MAX_RUNNING_INSTANCES - number_instances ) logger.debug( "wake_instance: %i %i", number_instances, number_pending_instances, ) for entry in pending_entries: created_at = entry[0] pid = entry[1] # Change status to not pending and continue the process self.update_pending_status(created_at, False) self.start_process(pid) def start_process(self, pid): """Continue a stopped process Send a continue signal to the process with given pid Arguments: pid (int): Process Identification Number """ logger.debug("Continue pid: %i", pid) os.kill(pid, signal.SIGCONT) def stop_process(self, pid): """Stop a running process Send a stop signal to the process with given pid Arguments: pid (int): Process Identification Number """ os.kill(pid, signal.SIGSTOP) def check_pid(self, pid): """Check for the existence of a process. Arguments: pid (int): Process Identification Number """ try: os.kill(pid, 0) except OSError: return False else: return True def ping(gmp, im): """Checks for connectivity This function sends the get_version command and checks whether the status is ok or not. """ version = gmp.get_version() version_status = version.xpath("@status") if "200" in version_status: end_session(im, "GMP OK: Ping successful", NAGIOS_OK) else: end_session(im, "GMP CRITICAL: Machine dead?", NAGIOS_CRITICAL) def status(gmp, im, script_args): """Returns the current status of a host This functions return the current state of a host. Either directly over the asset management or within a task. For a task you can explicitly ask for the trend. Otherwise the last report of the task will be filtered. In the asset management the report id in the details is taken as report for the filter. If the asset information contains any vulnerabilities, then will the report be filtered too. With additional parameters it is possible to add more information about the vulnerabilities. * DFN-Certs * Logs * Autofp * Scanend * Overrides """ params_used = "task=%s autofp=%i overrides=%i apply_overrides=%i" % ( script_args.task, script_args.autofp, int(script_args.overrides), int(script_args.apply_overrides), ) if script_args.task: task = gmp.get_tasks( filter="permission=any owner=any rows=1 " 'name="%s"' % script_args.task ) if script_args.trend: trend = task.xpath("task/trend/text()") if not trend: end_session( im, "GMP UNKNOWN: Trend is not available.", NAGIOS_UNKNOWN ) trend = trend[0] if trend in ["up", "more"]: end_session( im, "GMP CRITICAL: Trend is %s." % trend, NAGIOS_CRITICAL ) elif trend in ["down", "same", "less"]: end_session(im, "GMP OK: Trend is %s." % trend, NAGIOS_OK) else: end_session( im, "GMP UNKNOWN: Trend is unknown: %s" % trend, NAGIOS_UNKNOWN, ) else: last_report_id = task.xpath("task/last_report/report/@id") if not last_report_id: end_session( im, "GMP UNKNOWN: Report is not available", NAGIOS_UNKNOWN ) last_report_id = last_report_id[0] last_scan_end = task.xpath( "task/last_report/report/scan_end/text()" ) if last_scan_end: last_scan_end = last_scan_end[0] else: last_scan_end = "" if im.is_old_report(last_scan_end, params_used): host = script_args.hostaddress full_report = gmp.get_report( report_id=last_report_id, filter="sort-reverse=id result_hosts_only=1 " "min_cvss_base= min_qod= levels=hmlgd autofp={} " "notes=0 apply_overrides={} overrides={} first=1 rows=-1 " "delta_states=cgns host={}".format( script_args.autofp, int(script_args.overrides), int(script_args.apply_overrides), host, ), details=True, ) im.add_report(last_scan_end, params_used, full_report) logger.debug("Report added to db") else: full_report = im.load_local_report() filter_report( im, full_report.xpath("report/report")[0], script_args ) def filter_report(im, report, script_args): """Filter out the information in a report This function filters the results of a given report. Arguments: report (obj): Report as lxml ElementTree. """ report_id = report.xpath("@id") if report_id: report_id = report_id[0] results = report.xpath("//results") if not results: end_session( im, "GMP UNKNOWN: Failed to get results list", NAGIOS_UNKNOWN ) results = results[0] # Init variables any_found = False high_count = 0 medium_count = 0 low_count = 0 log_count = 0 error_count = 0 nvts = {"high": [], "medium": [], "low": [], "log": []} all_results = results.xpath("result") for result in all_results: if script_args.hostaddress: host = result.xpath("host/text()") if not host: end_session( im, "GMP UNKNOWN: Failed to parse result host", NAGIOS_UNKNOWN, ) if script_args.hostaddress != host[0]: continue any_found = True threat = result.xpath("threat/text()") if not threat: end_session( im, "GMP UNKNOWN: Failed to parse result threat.", NAGIOS_UNKNOWN, ) threat = threat[0] if threat in "High": high_count += 1 if script_args.oid: nvts["high"].append(retrieve_nvt_data(result)) elif threat in "Medium": medium_count += 1 if script_args.oid: nvts["medium"].append(retrieve_nvt_data(result)) elif threat in "Low": low_count += 1 if script_args.oid: nvts["low"].append(retrieve_nvt_data(result)) elif threat in "Log": log_count += 1 if script_args.oid: nvts["log"].append(retrieve_nvt_data(result)) else: end_session( im, "GMP UNKNOWN: Unknown result threat: %s" % threat, NAGIOS_UNKNOWN, ) errors = report.xpath("errors") if errors: errors = errors[0] if script_args.hostaddress: for error in errors.xpath("error"): host = error.xpath("host/text()") if script_args.hostaddress == host[0]: error_count += 1 else: error_count = errors.xpath("count/text()")[0] ret = 0 if high_count > 0: ret = NAGIOS_CRITICAL elif medium_count > 0: ret = NAGIOS_WARNING if script_args.empty_as_unknown and ( not all_results or (not any_found and script_args.hostaddress) ): ret = NAGIOS_UNKNOWN print( "GMP %s: %i vulnerabilities found - High: %i Medium: %i " "Low: %i" % ( NAGIOS_MSG[ret], (high_count + medium_count + low_count), high_count, medium_count, low_count, ) ) if not all_results: print("Report did not contain any vulnerabilities") elif not any_found and script_args.hostaddress: print( "Report did not contain vulnerabilities for IP %s" % script_args.hostaddress ) if int(error_count) > 0: if script_args.hostaddress: print_without_pipe( "Report did contain %i errors for IP %s" % (error_count, script_args.hostaddress) ) else: print_without_pipe( "Report did contain %i errors" % int(error_count) ) if script_args.report_link: print( "https://%s/omp?cmd=get_report&report_id=%s" % (script_args.hostname, report_id) ) if script_args.oid: print_nvt_data( nvts, show_log=script_args.showlog, show_ports=script_args.show_ports, descr=script_args.descr, dfn=script_args.dfn, ) if script_args.scanend: end = report.xpath("//end/text()") end = end[0] if end else "Timestamp of scan end not given" print("SCAN_END: %s" % end) if script_args.details: if script_args.hostname: print("GSM_Host: %s:%d" % (script_args.hostname, script_args.port)) if script_args.gmp_username: print("GMP_User: %s" % script_args.gmp_username) if script_args.task: print_without_pipe("Task: %s" % script_args.task) end_session( im, "|High=%i Medium=%i Low=%i" % (high_count, medium_count, low_count), ret, ) def retrieve_nvt_data(result): """Retrieve the nvt data out of the result object This function parse the xml tree to find the important nvt data. Arguments: result (obj): Result as lxml ElementTree Returns: Tuple -- List with oid, name, desc, port and dfn """ oid = result.xpath("nvt/@oid") name = result.xpath("nvt/name/text()") desc = result.xpath("description/text()") port = result.xpath("port/text()") if oid: oid = oid[0] if name: name = name[0] if desc: desc = desc[0] else: desc = "" if port: port = port[0] else: port = "" certs = result.xpath("nvt/cert/cert_ref") dfn_list = [] for ref in certs: ref_type = ref.xpath("@type")[0] ref_id = ref.xpath("@id")[0] if ref_type in "DFN-CERT": dfn_list.append(ref_id) return (oid, name, desc, port, dfn_list) def print_nvt_data( nvts, show_log=False, show_ports=False, descr=False, dfn=False ): """Print nvt data Prints for each nvt found in the array the relevant data Arguments: nvts (obj): Object holding all nvts """ for key, nvt_data in nvts.items(): if key is "log" and not show_log: continue for nvt in nvt_data: print_without_pipe("NVT: %s (%s) %s" % (nvt[0], key, nvt[1])) if show_ports: print_without_pipe("PORT: %s" % (nvt[3])) if descr: print_without_pipe("DESCR: %s" % nvt[2]) if dfn and nvt[4]: dfn_list = ", ".join(nvt[4]) if dfn_list: print_without_pipe("DFN-CERT: %s" % dfn_list) def end_session(im, msg, nagios_status): """End the session Close the socket if open and print the last msg Arguments: msg string): Message to print nagios_status (int): Exit status """ print(msg) # Delete this instance im.delete_instance() # Activate some waiting instances if possible im.wake_instance() # Close the connection to database im.close_db() sys.exit(nagios_status) def print_without_pipe(msg): """Prints the message, but without any pipe symbol If any pipe symbol is in the msg string, then it will be replaced with broken pipe symbol. Arguments: msg (string): Message to print """ if "|" in msg: msg = msg.replace("|", "¦") print(msg) # ISO 8601 date time string parsing # Copyright (c) 2007 - 2015 Michael Twomey # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. __all__ = ["parse_date", "ParseError", "UTC"] _basestring = str # Adapted from http://delete.me.uk/2005/03/iso8601.html ISO8601_REGEX = re.compile( r""" (?P[0-9]{4}) ( ( (-(?P[0-9]{1,2})) | (?P[0-9]{2}) (?!$) # Don't allow YYYYMM ) ( ( (-(?P[0-9]{1,2})) | (?P[0-9]{2}) ) ( ( (?P[ T]) (?P[0-9]{2}) (:{0,1}(?P[0-9]{2})){0,1} ( :{0,1}(?P[0-9]{1,2}) ([.,](?P[0-9]+)){0,1} ){0,1} (?P Z | ( (?P[-+]) (?P[0-9]{2}) :{0,1} (?P[0-9]{2}){0,1} ) ){0,1} ){0,1} ) ){0,1} # YYYY-MM ){0,1} # YYYY only $ """, re.VERBOSE, ) class ParseError(Exception): """Raised when there is a problem parsing a date string""" # Yoinked from python docs ZERO = timedelta(0) class Utc(tzinfo): """UTC Timezone""" def utcoffset(self, dt): return ZERO def tzname(self, dt): return "UTC" def dst(self, dt): return ZERO def __repr__(self): return "" UTC = Utc() class FixedOffset(tzinfo): """Fixed offset in hours and minutes from UTC""" def __init__(self, offset_hours, offset_minutes, name): self.__offset_hours = offset_hours # Keep for later __getinitargs__ # Keep for later __getinitargs__ self.__offset_minutes = offset_minutes self.__offset = timedelta(hours=offset_hours, minutes=offset_minutes) self.__name = name def __eq__(self, other): if isinstance(other, FixedOffset): # pylint: disable=protected-access return (other.__offset == self.__offset) and ( other.__name == self.__name ) if isinstance(other, tzinfo): return other == self return False def __getinitargs__(self): return (self.__offset_hours, self.__offset_minutes, self.__name) def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return ZERO def __repr__(self): return "" % (self.__name, self.__offset) def to_int( source_dict, key, default_to_zero=False, default=None, required=True ): """Pull a value from the dict and convert to int :param default_to_zero: If the value is None or empty, treat it as zero :param default: If the value is missing in the dict use this default """ value = source_dict.get(key) if value in [None, ""]: value = default if (value in ["", None]) and default_to_zero: return 0 if value is None: if required: raise ParseError("Unable to read %s from %s" % (key, source_dict)) return value else: return int(value) def parse_timezone(matches, default_timezone=UTC): """Parses ISO 8601 time zone specs into tzinfo offsets""" if matches["timezone"] == "Z": return UTC # This isn't strictly correct, but it's common to encounter dates without # timezones so I'll assume the default (which defaults to UTC). # Addresses issue 4. if matches["timezone"] is None: return default_timezone sign = matches["tz_sign"] hours = to_int(matches, "tz_hour") minutes = to_int(matches, "tz_minute", default_to_zero=True) description = "%s%02d:%02d" % (sign, hours, minutes) if sign == "-": hours = -1 * hours minutes = -1 * minutes return FixedOffset(hours, minutes, description) def parse_date(datestring, default_timezone=UTC): """Parses ISO 8601 dates into datetime objects The timezone is parsed from the date string. However it is quite common to have dates without a timezone (not strictly correct). In this case the default timezone specified in default_timezone is used. This is UTC by default. Arguments datestring: The date to parse as a string default_timezone: A datetime tzinfo instance to use when no timezone is specified in the datestring. If this is set to None then a naive datetime object is returned. Returns: A datetime.datetime instance Raises: ParseError when there is a problem parsing the date or constructing the datetime instance. """ if not isinstance(datestring, _basestring): raise ParseError("Expecting a string %r" % datestring) match = ISO8601_REGEX.match(datestring) if not match: raise ParseError("Unable to parse date string %r" % datestring) groups = match.groupdict() tz = parse_timezone(groups, default_timezone=default_timezone) groups["second_fraction"] = int( Decimal("0.%s" % (groups["second_fraction"] or 0)) * Decimal("1000000.0") ) try: return datetime( year=to_int(groups, "year"), month=to_int( groups, "month", default=to_int(groups, "monthdash", required=False, default=1), ), day=to_int( groups, "day", default=to_int(groups, "daydash", required=False, default=1), ), hour=to_int(groups, "hour", default_to_zero=True), minute=to_int(groups, "minute", default_to_zero=True), second=to_int(groups, "second", default_to_zero=True), microsecond=groups["second_fraction"], tzinfo=tz, ) except Exception as e: raise ParseError(e) from None def main(gmp, args): tmp_path = "%s/check_gmp/" % tempfile.gettempdir() tmp_path_db = tmp_path + "reports.db" parser = ArgumentParser( prog="check-gmp", prefix_chars="-", description=HELP_TEXT, formatter_class=RawTextHelpFormatter, add_help=False, epilog=""" usage: gvm-script [connection_type] check-gmp.gmp.py ... or: gvm-script [connection_type] check-gmp.gmp.py -H or: gvm-script connection_type --help""", ) parser.add_argument( "-H", action="help", help="Show this help message and exit." ) parser.add_argument( "-V", "--version", action="version", version="%(prog)s {version}".format(version=__version__), help="Show program's version number and exit", ) parser.add_argument( "--cache", nargs="?", default=tmp_path_db, help="Path to cache file. Default: %s." % tmp_path_db, ) parser.add_argument( "--clean", action="store_true", help="Activate to clean the database." ) parser.add_argument( "-u", "--gmp-username", help="GMP username.", required=False ) parser.add_argument( "-w", "--gmp-password", help="GMP password.", required=False ) parser.add_argument( "-F", "--hostaddress", required=False, default="", help="Report last report status of host .", ) parser.add_argument( "-T", "--task", required=False, help="Report status of task ." ) parser.add_argument( "--apply-overrides", action="store_true", help="Apply overrides." ) parser.add_argument( "--overrides", action="store_true", help="Include overrides." ) parser.add_argument( "-d", "--details", action="store_true", help="Include connection details in output.", ) parser.add_argument( "-l", "--report-link", action="store_true", help="Include URL of report in output.", ) parser.add_argument( "--dfn", action="store_true", help="Include DFN-CERT IDs on vulnerabilities in output.", ) parser.add_argument( "--oid", action="store_true", help="Include OIDs of NVTs finding vulnerabilities in output.", ) parser.add_argument( "--descr", action="store_true", help="Include descriptions of NVTs finding vulnerabilities in output.", ) parser.add_argument( "--showlog", action="store_true", help="Include log messages in output." ) parser.add_argument( "--show-ports", action="store_true", help="Include port of given vulnerable nvt in output.", ) parser.add_argument( "--scanend", action="store_true", help="Include timestamp of scan end in output.", ) parser.add_argument( "--autofp", type=int, choices=[0, 1, 2], default=0, help="Trust vendor security updates for automatic false positive" " filtering (0=No, 1=full match, 2=partial).", ) parser.add_argument( "-e", "--empty-as-unknown", action="store_true", help="Respond with UNKNOWN on empty results.", ) parser.add_argument( "-I", "--max-running-instances", default=10, type=int, help="Set the maximum simultaneous processes of check-gmp", ) parser.add_argument("--hostname", nargs="?", required=False) group = parser.add_mutually_exclusive_group(required=False) group.add_argument( "--ping", action="store_true", help="Ping the gsm appliance." ) group.add_argument( "--status", action="store_true", help="Report status of task." ) group = parser.add_mutually_exclusive_group(required=False) group.add_argument( "--days", type=int, help="Delete database entries that are older than" " given days.", ) group.add_argument("--ip", help="Delete database entry for given ip.") group = parser.add_mutually_exclusive_group(required=False) group.add_argument( "--trend", action="store_true", help="Report status by trend." ) group.add_argument( "--last-report", action="store_true", help="Report status by last report.", ) script_args = parser.parse_args(args.script_args) aux_parser = ArgumentParser( prefix_chars="-", formatter_class=RawTextHelpFormatter ) aux_parser.add_argument("--hostname", nargs="?", required=False) gvm_tool_args, _ = aux_parser.parse_known_args(sys.argv) if "hostname" in gvm_tool_args: script_args.hostname = gvm_tool_args.hostname # Set the max running instances variable if script_args.max_running_instances: # TODO should be passed as local variable instead of using a global one # pylint: disable=global-statement global MAX_RUNNING_INSTANCES MAX_RUNNING_INSTANCES = script_args.max_running_instances # Set the report manager if script_args.cache: tmp_path_db = script_args.cache im = InstanceManager(tmp_path_db, parser) # Check if command holds clean command if script_args.clean: if script_args.ip: logger.info("Delete entry with ip %s", script_args.ip) im.delete_entry_with_ip(script_args.ip) elif script_args.days: logger.info("Delete entries older than %s days", script_args.days) im.delete_older_entries(script_args.days) sys.exit(1) # Set the host im.set_host(script_args.hostaddress) # Check if no more than 10 instances of check-gmp runs simultaneously im.check_instances() try: gmp.get_version() except Exception as e: # pylint: disable=broad-except end_session(im, "GMP CRITICAL: %s" % str(e), NAGIOS_CRITICAL) if script_args.ping: ping(gmp, im) if "status" in script_args: status(gmp, im, script_args) if __name__ == "__gmp__": main(gmp, args) gvm-tools-21.1.0/scripts/clean-sensor.gmp.py000066400000000000000000000053241400201773500207410ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . def clean_sensor(gmp): tasks = gmp.get_tasks( filter="rows=-1 not status=Running and " "not status=Requested and not " "status="Stop Requested"" ) for tid in tasks.xpath('task/@id'): print('Removing task %s ... ' % tid) status_text = gmp.delete_task(tid, ultimate=True).xpath('@status_text')[ 0 ] print(status_text) targets = gmp.get_targets(filter="rows=-1 not _owner=""") for tid in targets.xpath('target/@id'): print('Removing target %s ... ' % tid) status_text = gmp.delete_target(tid, ultimate=True).xpath( '@status_text' )[0] print(status_text) configs = gmp.get_configs(filter="rows=-1 not _owner=""") for cid in configs.xpath('config/@id'): print('Removing config %s ... ' % cid) status_text = gmp.delete_config(cid, ultimate=True).xpath( '@status_text' )[0] print(status_text) port_lists = gmp.get_port_lists(filter="rows=-1 not _owner=""") for pid in port_lists.xpath('port_list/@id'): print('Removing port_list %s ... ' % pid) status_text = gmp.delete_port_list(pid, ultimate=True).xpath( '@status_text' )[0] print(status_text) credentials = gmp.get_credentials(filter="rows=-1 not _owner=""") for cid in credentials.xpath('credential/@id'): print('Removing credential %s ... ' % cid) status_text = gmp.delete_credential(cid, ultimate=True).xpath( '@status_text' )[0] print(status_text) print('Emptying trash... ') status_text = gmp.empty_trashcan().xpath('@status_text')[0] print(status_text) def main(gmp, args): # pylint: disable=unused-argument message = """ This script removes all resources from a sensor, except active tasks. """ print(message) clean_sensor(gmp) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/combine-reports.gmp.py000066400000000000000000000070221400201773500214550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import time import sys from lxml import etree as e from gvmtools.helper import generate_uuid def check_args(args): len_args = len(args.script) - 1 if len_args < 2: message = """ This script will combine desired reports into a single report. \ The combined report will then be sent to a desired container task. \ This script will create a container task for the combined report to\ be sent to, however, if you would like the report to be sent to an \ existing task, place the report of the desired task first and add \ the argument 'first_task'. 1. --uuid of report to be combined 2. --uuid of report to be combined ... n. --uuid of report to be combined Example for starting up the routine: $ gvm-script --gmp-username=namessh --gmp-password=pass ssh --hostname=hostname \ scripts/combine-reports.gmp.py \ "d15a337c-56f3-4208-a462-afeb79eb03b7" \ "303fa0a6-aa9b-43c4-bac0-66ae0b2d1698" 'first_task' """ print(message) sys.exit() def combine_reports(gmp, args): new_uuid = generate_uuid() combined_report = e.Element( 'report', { 'id': new_uuid, 'format_id': 'd5da9f67-8551-4e51-807b-b6a873d70e34', 'extension': 'xml', 'content_type': 'text/xml', }, ) report_elem = e.Element('report', {'id': new_uuid}) results_elem = e.Element('results', {'start': '1', 'max': '-1'}) combined_report.append(report_elem) report_elem.append(results_elem) if 'first_task' in args.script: arg_len = args.script[1:-1] else: arg_len = args.script[1:] for argument in arg_len: current_report = gmp.get_report(argument, details=True)[0] for result in current_report.xpath('report/results/result'): results_elem.append(result) return combined_report def send_report(gmp, args, combined_report): if 'first_task' in args.script: main_report = gmp.get_report(args.script[1])[0] task_id = main_report.xpath('//task/@id')[0] else: the_time = time.strftime("%Y/%m/%d-%H:%M:%S") task_id = '' task_name = "Combined_Report_{}".format(the_time) res = gmp.create_container_task( name=task_name, comment="Created with gvm-tools." ) task_id = res.xpath('//@id')[0] combined_report = e.tostring(combined_report) res = gmp.import_report(combined_report, task_id=task_id) return res.xpath('//@id')[0] def main(gmp, args): # pylint: disable=undefined-variable check_args(args) combined_report = combine_reports(gmp, args) send_repot(gmp, args, combined_report) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/create-dummy-data.gmp.py000066400000000000000000000053011400201773500216460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from random import choice from gvmtools.helper import generate_id def check_args(args): len_args = len(args.script) - 1 if len_args is not 1: message = """ This script will create random data in the given GVM database 1. -- Number of datasets to create Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/create-dummy-data.gmp.py """ print(message) sys.exit() def create_data(gmp, count): config_ids = [] target_ids = [] for _ in range(0, count): name = generate_id() gmp.create_credential( name, login=name, password=name, credential_type=gmp.types.CredentialType.PASSWORD_ONLY, ) print(str(count) + ' random credentials generated.') for _ in range(0, count): name = generate_id() gmp.create_port_list(name, port_range='T:1-42') print(str(count) + ' random port lists generated.') for _ in range(0, count): name = generate_id() res = gmp.create_config('085569ce-73ed-11df-83c3-002264764cea', name) config_ids.append(res.xpath('@id')[0]) print(str(count) + ' random scan configs generated.') for _ in range(0, count): name = generate_id() res = gmp.create_target(name, hosts=['127.0.0.1']) target_ids.append(res.xpath('@id')[0]) print(str(count) + ' random targets generated.') for _ in range(0, count): name = generate_id() config_id = choice(config_ids) target_id = choice(target_ids) gmp.create_task( name, config_id, target_id, '08b69003-5fc2-4037-a479-93b440211c73' ) print(str(count) + ' random tasks generated.') def main(gmp, args): # pylint: disable=undefined-variable check_args(args) create_data(gmp, int(args.script[1])) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/create-targets-from-host-list.gmp.py000066400000000000000000000047541400201773500241550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import time from gvmtools.helper import error_and_exit def check_args(args): len_args = len(args.script) - 1 if len_args is not 2: message = """ This script pulls hostnames from a text file and creates a target \ for each. One parameter after the script name is required. 1. -- IP of the GVM host 2. -- text file containing hostnames Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/create_targets_from_host_list.gmp \ """ print(message) sys.exit() def load_host_list(host_file): try: with open(host_file) as f: content = f.readlines() host_list = [x.strip() for x in content] host_list = list(filter(None, host_list)) except IOError as e: error_and_exit("Failed to read host_file: {} (exit)".format(str(e))) if len(host_list) == 0: error_and_exit("Host file is empty (exit)") return host_list def send_targets(gmp, host_name, host_file, host_list): print('\nSending targets from {} to {}...'.format(host_file, host_name)) for host in host_list: name = "Target for {}".format(host) comment = "Created: {}".format(time.strftime("%Y/%m/%d-%H:%M:%S")) hosts = [host] gmp.create_target(name=name, comment=comment, hosts=hosts) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) hostname = args.script[1] hostfile = args.script[2] hostlist = load_host_list(hostfile) send_targets(gmp, hostname, hostfile, hostlist) print('\n Target(s) created!\n') if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/default_report_data.json000066400000000000000000000664371400201773500221330ustar00rootroot00000000000000{ "vulns": [ { "oid": "1.3.6.1.4.1.25623.1.0.10056", "port": "80/tcp", "severity": "5.0", "name": "/doc directory browsable" }, { "oid": "1.3.6.1.4.1.25623.1.0.902830", "port": "80/tcp", "severity": "4.3", "name": "Apache HTTP Server 'httpOnly' Cookie Information Disclosure Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.108082", "port": "8009/tcp", "severity": "0.0", "name": "Apache JServ Protocol v1.3 Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.900498", "port": "80/tcp", "severity": "0.0", "name": "Apache Web Server Version Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103210", "port": "80/tcp", "severity": "5.0", "name": "awiki Multiple Local File Include Vulnerabilities" }, { "oid": "1.3.6.1.4.1.25623.1.0.111038", "port": "80/tcp", "severity": "0.0", "name": "CGI Scanning Consolidation" }, { "oid": "1.3.6.1.4.1.25623.1.0.900600", "port": "21/tcp", "severity": "6.4", "name": "Check for Anonymous FTP Login" }, { "oid": "1.3.6.1.4.1.25623.1.0.100111", "port": "512/tcp", "severity": "10.0", "name": "Check for rexecd Service" }, { "oid": "1.3.6.1.4.1.25623.1.0.901202", "port": "513/tcp", "severity": "7.5", "name": "Check for rlogin Service" }, { "oid": "1.3.6.1.4.1.25623.1.0.100074", "port": "1524/tcp", "severity": "0.0", "name": "Check for Telnet Server" }, { "oid": "1.3.6.1.4.1.25623.1.0.100072", "port": "25/tcp", "severity": "5.0", "name": "Check if Mailserver answer to VRFY and EXPN requests" }, { "oid": "1.3.6.1.4.1.25623.1.0.810002", "port": "general/CPE-T", "severity": "0.0", "name": "CPE Inventory" }, { "oid": "1.3.6.1.4.1.25623.1.0.902799", "port": "5432/tcp", "severity": "0.0", "name": "Database Open Access Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.902799", "port": "3306/tcp", "severity": "0.0", "name": "Database Open Access Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.10028", "port": "53/tcp", "severity": "0.0", "name": "Determine which version of BIND name daemon is running" }, { "oid": "1.3.6.1.4.1.25623.1.0.12638", "port": "3632/tcp", "severity": "8.5", "name": "DistCC Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103553", "port": "3632/tcp", "severity": "9.3", "name": "DistCC Remote Code Execution Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.108010", "port": "8787/tcp", "severity": "10.0", "name": "Distributed Ruby (dRuby/DRb) Multiple Remote Code Execution Vulnerabilities" }, { "oid": "1.3.6.1.4.1.25623.1.0.108018", "port": "53/tcp", "severity": "0.0", "name": "DNS Server Detection (TCP)" }, { "oid": "1.3.6.1.4.1.25623.1.0.20108", "port": "80/tcp", "severity": "0.0", "name": "Fingerprint web server with favicon.ico" }, { "oid": "1.3.6.1.4.1.25623.1.0.10092", "port": "21/tcp", "severity": "0.0", "name": "FTP Banner Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.10092", "port": "2121/tcp", "severity": "0.0", "name": "FTP Banner Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.11213", "port": "80/tcp", "severity": "5.8", "name": "HTTP Debugging Methods (TRACE/TRACK) Enabled" }, { "oid": "1.3.6.1.4.1.25623.1.0.112081", "port": "80/tcp", "severity": "0.0", "name": "HTTP Security Headers Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.10107", "port": "80/tcp", "severity": "0.0", "name": "HTTP Server type and version" }, { "oid": "1.3.6.1.4.1.25623.1.0.103190", "port": "general/icmp", "severity": "0.0", "name": "ICMP Timestamp Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.11156", "port": "6667/tcp", "severity": "0.0", "name": "IRC daemon identification" }, { "oid": "1.3.6.1.4.1.25623.1.0.140051", "port": "1099/tcp", "severity": "10.0", "name": "Java RMI Server Insecure Default Configuration Remote Code Execution Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.802726", "port": "445/tcp", "severity": "0.0", "name": "Microsoft SMB Signing Disabled" }, { "oid": "1.3.6.1.4.1.25623.1.0.902425", "port": "445/tcp", "severity": "0.0", "name": "Microsoft Windows SMB Accessible Shares" }, { "oid": "1.3.6.1.4.1.25623.1.0.103935", "port": "25/tcp", "severity": "6.8", "name": "Multiple Vendors STARTTLS Implementation Plaintext Arbitrary Command Injection Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.103551", "port": "3306/tcp", "severity": "9.0", "name": "MySQL / MariaDB weak password" }, { "oid": "1.3.6.1.4.1.25623.1.0.100152", "port": "3306/tcp", "severity": "0.0", "name": "MySQL/MariaDB Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.11111", "port": "111/tcp", "severity": "0.0", "name": "Obtain list of all port mapper registered programs via RPC" }, { "oid": "1.3.6.1.4.1.25623.1.0.105937", "port": "general/tcp", "severity": "0.0", "name": "OS Detection Consolidation and Reporting" }, { "oid": "1.3.6.1.4.1.25623.1.0.103674", "port": "general/tcp", "severity": "10.0", "name": "OS End Of Life Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.800109", "port": "80/tcp", "severity": "0.0", "name": "PHP Version Detection (Remote)" }, { "oid": "1.3.6.1.4.1.25623.1.0.103482", "port": "80/tcp", "severity": "7.5", "name": "PHP-CGI-based setups vulnerability when parsing query string parameters from php files." }, { "oid": "1.3.6.1.4.1.25623.1.0.11229", "port": "80/tcp", "severity": "7.5", "name": "phpinfo() output accessible" }, { "oid": "1.3.6.1.4.1.25623.1.0.801660", "port": "80/tcp", "severity": "4.3", "name": "phpMyAdmin 'error.php' Cross Site Scripting Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.900129", "port": "80/tcp", "severity": "0.0", "name": "phpMyAdmin Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103549", "port": "1524/tcp", "severity": "10.0", "name": "Possible Backdoor: Ingreslock" }, { "oid": "1.3.6.1.4.1.25623.1.0.111086", "port": "25/tcp", "severity": "0.0", "name": "Postfix SMTP Server Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.100151", "port": "5432/tcp", "severity": "0.0", "name": "PostgreSQL Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.105013", "port": "5432/tcp", "severity": "0.0", "name": "PostgreSQL TLS Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103552", "port": "5432/tcp", "severity": "9.0", "name": "PostgreSQL weak password" }, { "oid": "1.3.6.1.4.1.25623.1.0.900815", "port": "2121/tcp", "severity": "0.0", "name": "ProFTPD Server Version Detection (Remote)" }, { "oid": "1.3.6.1.4.1.25623.1.0.10281", "port": "23/tcp", "severity": "0.0", "name": "Report Telnet Banner" }, { "oid": "1.3.6.1.4.1.25623.1.0.10281", "port": "1524/tcp", "severity": "0.0", "name": "Report Telnet Banner" }, { "oid": "1.3.6.1.4.1.25623.1.0.105839", "port": "1099/tcp", "severity": "0.0", "name": "RMI-Registry Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.108090", "port": "111/tcp", "severity": "0.0", "name": "RPC portmapper (TCP)" }, { "oid": "1.3.6.1.4.1.25623.1.0.108011", "port": "445/tcp", "severity": "6.0", "name": "Samba MS-RPC Remote Shell Command Execution Vulnerability (Active Check)" }, { "oid": "1.3.6.1.4.1.25623.1.0.108204", "port": "512/tcp", "severity": "0.0", "name": "Service Detection with 'BINARY' Request" }, { "oid": "1.3.6.1.4.1.25623.1.0.17975", "port": "8787/tcp", "severity": "0.0", "name": "Service Detection with 'GET' Request" }, { "oid": "1.3.6.1.4.1.25623.1.0.11153", "port": "6667/tcp", "severity": "0.0", "name": "Service Detection with 'HELP' Request" }, { "oid": "1.3.6.1.4.1.25623.1.0.66286", "port": "514/tcp", "severity": "0.0", "name": "Service Detection with nmap" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "23/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "21/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "2121/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "5432/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "25/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "22/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "80/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10330", "port": "3306/tcp", "severity": "0.0", "name": "Services" }, { "oid": "1.3.6.1.4.1.25623.1.0.10394", "port": "445/tcp", "severity": "0.0", "name": "SMB log in" }, { "oid": "1.3.6.1.4.1.25623.1.0.102011", "port": "445/tcp", "severity": "0.0", "name": "SMB NativeLanMan" }, { "oid": "1.3.6.1.4.1.25623.1.0.807830", "port": "445/tcp", "severity": "0.0", "name": "SMB Remote Version Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.11011", "port": "139/tcp", "severity": "0.0", "name": "SMB/CIFS Server Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.11011", "port": "445/tcp", "severity": "0.0", "name": "SMB/CIFS Server Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.10263", "port": "25/tcp", "severity": "0.0", "name": "SMTP Server type and version" }, { "oid": "1.3.6.1.4.1.25623.1.0.103118", "port": "25/tcp", "severity": "0.0", "name": "SMTP STARTTLS Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103239", "port": "22/tcp", "severity": "7.5", "name": "SSH Brute Force Logins With Default Credentials Reporting" }, { "oid": "1.3.6.1.4.1.25623.1.0.105565", "port": "22/tcp", "severity": "0.0", "name": "SSH Protocol Algorithms Supported" }, { "oid": "1.3.6.1.4.1.25623.1.0.100259", "port": "22/tcp", "severity": "0.0", "name": "SSH Protocol Versions Supported" }, { "oid": "1.3.6.1.4.1.25623.1.0.10267", "port": "22/tcp", "severity": "0.0", "name": "SSH Server type and version" }, { "oid": "1.3.6.1.4.1.25623.1.0.105611", "port": "22/tcp", "severity": "4.3", "name": "SSH Weak Encryption Algorithms Supported" }, { "oid": "1.3.6.1.4.1.25623.1.0.105610", "port": "22/tcp", "severity": "2.6", "name": "SSH Weak MAC Algorithms Supported" }, { "oid": "1.3.6.1.4.1.25623.1.0.805188", "port": "25/tcp", "severity": "4.3", "name": "SSL/TLS: 'DHE_EXPORT' Man in the Middle Security Bypass Vulnerability (LogJam)" }, { "oid": "1.3.6.1.4.1.25623.1.0.103140", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Certificate - Self-Signed Certificate Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103140", "port": "5432/tcp", "severity": "0.0", "name": "SSL/TLS: Certificate - Self-Signed Certificate Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103955", "port": "25/tcp", "severity": "5.0", "name": "SSL/TLS: Certificate Expired" }, { "oid": "1.3.6.1.4.1.25623.1.0.103955", "port": "5432/tcp", "severity": "5.0", "name": "SSL/TLS: Certificate Expired" }, { "oid": "1.3.6.1.4.1.25623.1.0.105880", "port": "5432/tcp", "severity": "4.0", "name": "SSL/TLS: Certificate Signed Using A Weak Signature Algorithm" }, { "oid": "1.3.6.1.4.1.25623.1.0.105880", "port": "25/tcp", "severity": "4.0", "name": "SSL/TLS: Certificate Signed Using A Weak Signature Algorithm" }, { "oid": "1.3.6.1.4.1.25623.1.0.103692", "port": "5432/tcp", "severity": "0.0", "name": "SSL/TLS: Collect and Report Certificate Details" }, { "oid": "1.3.6.1.4.1.25623.1.0.103692", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Collect and Report Certificate Details" }, { "oid": "1.3.6.1.4.1.25623.1.0.111012", "port": "5432/tcp", "severity": "4.3", "name": "SSL/TLS: Deprecated SSLv2 and SSLv3 Protocol Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.111012", "port": "25/tcp", "severity": "4.3", "name": "SSL/TLS: Deprecated SSLv2 and SSLv3 Protocol Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.106223", "port": "25/tcp", "severity": "4.0", "name": "SSL/TLS: Diffie-Hellman Key Exchange Insufficient DH Group Strength Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.106223", "port": "5432/tcp", "severity": "4.0", "name": "SSL/TLS: Diffie-Hellman Key Exchange Insufficient DH Group Strength Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.111010", "port": "general/tcp", "severity": "0.0", "name": "SSL/TLS: Hostname discovery from server certificate" }, { "oid": "1.3.6.1.4.1.25623.1.0.105042", "port": "5432/tcp", "severity": "6.8", "name": "SSL/TLS: OpenSSL CCS Man in the Middle Security Bypass Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.902816", "port": "5432/tcp", "severity": "0.0", "name": "SSL/TLS: Report Medium Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.902816", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Report Medium Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.103441", "port": "5432/tcp", "severity": "0.0", "name": "SSL/TLS: Report Non Weak Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.103441", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Report Non Weak Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.105018", "port": "5432/tcp", "severity": "0.0", "name": "SSL/TLS: Report Perfect Forward Secrecy (PFS) Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.105018", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Report Perfect Forward Secrecy (PFS) Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.802067", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Report Supported Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.802067", "port": "5432/tcp", "severity": "0.0", "name": "SSL/TLS: Report Supported Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.103440", "port": "5432/tcp", "severity": "4.3", "name": "SSL/TLS: Report Weak Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.103440", "port": "25/tcp", "severity": "0.0", "name": "SSL/TLS: Report Weak Cipher Suites" }, { "oid": "1.3.6.1.4.1.25623.1.0.805142", "port": "25/tcp", "severity": "4.3", "name": "SSL/TLS: RSA Temporary Key Handling 'RSA_EXPORT' Downgrade Issue (FREAK)" }, { "oid": "1.3.6.1.4.1.25623.1.0.802087", "port": "25/tcp", "severity": "4.3", "name": "SSL/TLS: SSLv3 Protocol CBC Cipher Suites Information Disclosure Vulnerability (POODLE)" }, { "oid": "1.3.6.1.4.1.25623.1.0.802087", "port": "5432/tcp", "severity": "4.3", "name": "SSL/TLS: SSLv3 Protocol CBC Cipher Suites Information Disclosure Vulnerability (POODLE)" }, { "oid": "1.3.6.1.4.1.25623.1.0.80091", "port": "general/tcp", "severity": "2.6", "name": "TCP timestamps" }, { "oid": "1.3.6.1.4.1.25623.1.0.10498", "port": "80/tcp", "severity": "7.5", "name": "Test HTTP dangerous methods" }, { "oid": "1.3.6.1.4.1.25623.1.0.108064", "port": "80/tcp", "severity": "5.0", "name": "Tiki Wiki CMS Groupware 'fixedURLData' Local File Inclusion Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.100537", "port": "80/tcp", "severity": "7.5", "name": "Tiki Wiki CMS Groupware < 4.2 Multiple Unspecified Vulnerabilities" }, { "oid": "1.3.6.1.4.1.25623.1.0.800315", "port": "80/tcp", "severity": "5.0", "name": "Tiki Wiki CMS Groupware Input Sanitation Weakness Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.901001", "port": "80/tcp", "severity": "0.0", "name": "Tiki Wiki CMS Groupware Version Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.140797", "port": "80/tcp", "severity": "6.5", "name": "Tiki Wiki CMS Groupware XSS Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.51662", "port": "general/tcp", "severity": "0.0", "name": "Traceroute" }, { "oid": "1.3.6.1.4.1.25623.1.0.800400", "port": "80/tcp", "severity": "6.0", "name": "TWiki Cross-Site Request Forgery Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.801281", "port": "80/tcp", "severity": "6.8", "name": "TWiki Cross-Site Request Forgery Vulnerability - Sep10" }, { "oid": "1.3.6.1.4.1.25623.1.0.800399", "port": "80/tcp", "severity": "0.0", "name": "TWiki Version Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.800320", "port": "80/tcp", "severity": "10.0", "name": "TWiki XSS and Command Execution Vulnerabilities" }, { "oid": "1.3.6.1.4.1.25623.1.0.106056", "port": "5900/tcp", "severity": "9.0", "name": "VNC Brute Force Login" }, { "oid": "1.3.6.1.4.1.25623.1.0.19288", "port": "5900/tcp", "severity": "0.0", "name": "VNC security types" }, { "oid": "1.3.6.1.4.1.25623.1.0.10342", "port": "5900/tcp", "severity": "0.0", "name": "VNC Server and Protocol Version Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.103185", "port": "6200/tcp", "severity": "7.5", "name": "vsftpd Compromised Source Packages Backdoor Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.103185", "port": "21/tcp", "severity": "7.5", "name": "vsftpd Compromised Source Packages Backdoor Vulnerability" }, { "oid": "1.3.6.1.4.1.25623.1.0.111050", "port": "21/tcp", "severity": "0.0", "name": "vsFTPd FTP Server Detection" }, { "oid": "1.3.6.1.4.1.25623.1.0.10407", "port": "6000/tcp", "severity": "0.0", "name": "X Server Detection" } ], "oss": { "Ubuntu 16.04": "cpe:/o:canonical:ubuntu_linux:16.04", "Debian GNU/Linux": "cpe:/o:debian:debian_linux:9", "Linux/Unix": "cpe:/o:linux:kernel", "Greenbone OS (GOS)": "cpe:/o:greenbone:greenbone_os:5.0.10" }, "apps": { "Greenbone Security Manager (GSM) / Greenbone OS (GOS) Detection (Version)": "cpe:/a:greenbone:gsm_expo", "OpenSSH 4.3": "cpe:/a:openbsd:openssh:4.3", "OpenSSH 5.3": "cpe:/a:openbsd:openssh:5.3", "OpenSSH 6.6.1": "cpe:/a:openbsd:openssh:6.6.1", "Plone": "cpe:/a:plone:plone", "Apache Server 2.2.3": "cpe:/a:apache:http_server:2.2.3", "Apache Tomcat": "cpe:/a:apache:tomcat", "PHP 5.1.6": "cpe:/a:php:php:5.1.6", "MySQL 5.1.73": "cpe:/a:oracle:mysql:5.1.73", "Webmin 1.791": "cpe:/a:webmin:webmin:1.791", "Samba 3.3.9": "cpe:/a:samba:samba:3.3.9" }, "host_details": [ { "name": "MAC", "value": "00:CC:29:DD:01:D6", "source_name": "1.3.6.1.4.1.25623.1.0.103585", "source_description": "Nmap MAC Scan" }, { "name": "Services", "value": "6000,tcp,X11", "source_name": "1.3.6.1.4.1.25623.1.0.10407", "source_description": "Service detection (1.3.6.1.4.1.25623.1.0.10407)" }, { "name": "TLS/5432", "value": "SSLv3", "source_name": "1.3.6.1.4.1.25623.1.0.103823", "source_description": "SSL/TLS: Version Detection Report" }, { "name": "Services", "value": "2049,tcp,RPC/nfs", "source_name": "1.3.6.1.4.1.25623.1.0.11111", "source_description": "Service detection (1.3.6.1.4.1.25623.1.0.11111)" }, { "name": "tcp_ports", "value": "80,8787,5900,3632,8009,6667,445,21,2049,111,22,6000,512,23,513,1099,25,514,3306,2121,139,1524,53,5432", "source_name": "1.3.6.1.4.1.25623.1.0.900239", "source_description": "Check Open TCP Ports" }, { "name": "SSLInfo", "value": "25::E7A7FA0D63E457C7C4A59B31230849C6A70BDA6F830C7AF1E32DEE436DE813CC", "source_name": "1.3.6.1.4.1.25623.1.0.103692", "source_description": "SSL/TLS Certificate Information" }, { "name": "Services", "value": "23,tcp,telnet,A telnet server seems to be running on this port", "source_name": "1.3.6.1.4.1.25623.1.0.100074", "source_description": "Service detection (1.3.6.1.4.1.25623.1.0.100074)" }, { "name": "Auth-SMB-Success", "value": "Protocol SMB, Port 445, User", "source_name": "1.3.6.1.4.1.25623.1.0.10394" }, { "name": "TLS/25", "value": "TLSv1.0", "source_name": "1.3.6.1.4.1.25623.1.0.103823", "source_description": "SSL/TLS: Version Detection Report" }, { "name": "ssh-key", "value": "22 ssh-rsa AAAABCNzaC1yc2EAAAABIwAAAQEA123nuFMBOZvO3WTEjP4TUdjgWkIVNdTq6kboEDjteOfc65TlI7sRvQBwqAhQjeeyyIk8T55gMDkOD0akSlSXvLDcmcdYfxeIF0ZSuT+nkRhij7XSSA/Oc5QSk3sJ/SInfb78e3anbRHpmkJcVgETJ5WhKObUNf1AKZW++4Xlc63M4KI5cjvMMIPEVOyR3AKmI78Fo3HJjYucg87JjLeC66I7+dlEYX6zT8i1XYwa/L1vZ3qSJISGVu8kRPikMv/cNSvki4j+qDYyZ2E5497W87+Ed46/8P42LNGoOV8OcX/ro6pAcbEPUdUEfkJrqi2YXbhvwIJ0gFMb6wfe5cnQew==", "source_name": "1.3.6.1.4.1.25623.1.0.100259", "source_description": "SSH Key" } ], "not_vuln": { "name": "EXIT_CODE", "value": "EXIT_NOTVULN", "source_name": "1.3.6.1.4.1.25623.1.0." } }gvm-tools-21.1.0/scripts/delete-overrides-by-filter.gmp.py000066400000000000000000000035661400201773500235130ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import time import sys def check_args(args): len_args = len(args.script) - 1 if len_args is not 1: message = """ This script deletes overrides with a specific filter value -- the parameter for the filter. Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/delete-overrides-by-filter.gmp.py """ print(message) sys.exit() def delete_overrides(gmp, filter_value): filters = gmp.get_overrides(filter=filter_value) if not filters.xpath('override'): print('No overrides with filter: %s' % filter_value) for f_id in filters.xpath('override/@id'): print('Delete override: %s' % f_id, end='') res = gmp.delete_override(f_id) if 'OK' in res.xpath('@status_text')[0]: print(' OK') else: print(' ERROR') time.sleep(60) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) filter_value = args.script[1] delete_overrides(gmp, filter_value) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/gen-random-targets.gmp.py000066400000000000000000000043701400201773500220460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from random import choice, gauss from gvmtools.helper import generate_random_ips def check_args(args): len_args = len(args.script) - 1 if len_args < 2: message = """ This script generates random task data and feeds it to\ a desired GSM It needs two parameters after the script name. 1. -- number of dummy hosts to select from 2. -- number of targets to be generated In addition, if you would like for the number of targets generated to be randomized on a Gaussian distribution, add 'with-gauss' Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/gen-random-targets.gmp.py 3 40 with-gauss """ print(message) sys.exit() def generate(gmp, args, n_targets, n_ips): ips = generate_random_ips(n_ips) if 'with-gauss' in args.script: n_targets = int(gauss(n_targets, 2)) for i in range(n_targets): host_ip = choice(ips) index = '{{0:0>{}}}'.format(len(str(n_targets))) name = 'Target_{}'.format(index.format(i + 1)) gmp.create_target(name=name, make_unique=True, hosts=[host_ip]) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) host_number = int(args.script[1]) number_targets = int(args.script[2]) print('Generating random targets...') generate(gmp, args, number_targets, host_number) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/list-tasks.gmp.py000066400000000000000000000024461400201773500204500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gvmtools.helper import Table def main(gmp, args): # pylint: disable=unused-argument response_xml = gmp.get_tasks() tasks_xml = response_xml.xpath('task') heading = ['ID', 'Name', 'Severity'] rows = [] for task in tasks_xml: name = ''.join(task.xpath('name/text()')) task_id = task.get('id') severity = ''.join(task.xpath('last_report/report/severity/text()')) rows.append([task_id, name, severity]) print(Table(heading=heading, rows=rows)) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/monthly-report.gmp.py000066400000000000000000000077511400201773500213610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from datetime import date, timedelta from terminaltables import AsciiTable def check_args(args): len_args = len(args.script) - 1 if len_args < 2: message = """ This script will display all vulnerabilities from the hosts of the reports in a given month! 1. -- month of the monthly report 2. -- year of the monthly report The third is 'with-tables' parameter to activate a verbose output of hosts. Explicitly made for GOS 3.1. Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/monthly-report.gmp.py 05 2017 with-tables """ print(message) sys.exit() def print_reports(gmp, args, from_date, to_date): report_filter = "rows=-1 and created>{0} and created<{1}".format( from_date.isoformat(), to_date.isoformat() ) reports_xml = gmp.get_reports(filter=report_filter) report_list = reports_xml.xpath('report') sum_high = reports_xml.xpath( 'sum(report/report/result_count/hole/full/' 'text())' ) sum_medium = reports_xml.xpath( 'sum(report/report/result_count/warning/' 'full/text())' ) sum_low = reports_xml.xpath( 'sum(report/report/result_count/info/full/' 'text())' ) print('Found {0} reports'.format(len(report_list))) if 'with-tables' in args.script: for report in report_list: report_id = report.xpath('report/@id')[0] name = report.xpath('name/text()')[0] res = gmp.get_report(report_id) print('\nReport: {0}'.format(report_id)) table_data = [ ['Hostname', 'IP', 'Bericht', 'high', 'medium', 'low'] ] for host in res.xpath('report/report/host'): hostname = host.xpath( 'detail/name[text()="hostname"]/../' 'value/text()' ) if len(hostname) > 0: hostname = str(hostname[0]) else: hostname = "" ip = host.xpath('ip/text()')[0] high = host.xpath('result_count/hole/page/text()')[0] medium = host.xpath('result_count/warning/page/text()')[0] low = host.xpath('result_count/info/page/text()')[0] table_data.append([hostname, ip, name, high, medium, low]) host.clear() del host table = AsciiTable(table_data) print(table.table + '\n') res.clear() del res print( 'Summary of results from {3} to {4}\nHigh: {0}\nMedium: {1}\nLow: ' '{2}\n\n'.format( int(sum_high), int(sum_medium), int(sum_low), from_date.isoformat(), to_date.isoformat(), ) ) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) month = int(args.script[1]) year = int(args.script[2]) from_date = date(year, month, 1) to_date = from_date + timedelta(days=31) # To have the first day in month to_date = to_date.replace(day=1) print_reports(gmp, args, from_date, to_date) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/monthly-report2.gmp.py000066400000000000000000000071261400201773500214370ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from datetime import date, timedelta from terminaltables import AsciiTable def check_args(args): len_args = len(args.script) - 1 if len_args < 2: message = """ This script will display all vulnerabilities from the hosts of the reports in a given month! It needs two parameters after the script name. First one is the month and second one is the year. Both parameters are plain numbers, so no text. Explicitly made for GOS 4.X. 1. -- month of the monthly report 2. -- year of the monthly report Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/monthly-report2.gmp.py 05 2019 """ print(message) sys.exit() def print_reports(gmp, from_date, to_date): asset_filter = "rows=-1 and modified>{0} and modified<{1}".format( from_date.isoformat(), to_date.isoformat() ) assets_xml = gmp.get_assets( asset_type=gmp.types.AssetType.HOST, filter=asset_filter ) sum_high = 0 sum_medium = 0 sum_low = 0 table_data = [['Hostname', 'IP', 'Bericht', 'high', 'medium', 'low']] for asset in assets_xml.xpath('asset'): ip = asset.xpath('name/text()')[0] hostnames = asset.xpath( 'identifiers/identifier/name[text()="hostname"]/../value/text()' ) if len(hostnames) == 0: continue hostname = hostnames[0] results = gmp.get_results( details=False, filter='host={0} and severity>0.0'.format(ip) ) low = int(results.xpath('count(//result/threat[text()="Low"])')) sum_low += low medium = int(results.xpath('count(//result/threat[text()="Medium"])')) sum_medium += medium high = int(results.xpath('count(//result/threat[text()="High"])')) sum_high += high best_os_cpe_report_id = asset.xpath( 'host/detail/name[text()="best_os_cpe"]/../source/@id' )[0] table_data.append( [hostname, ip, best_os_cpe_report_id, high, medium, low] ) table = AsciiTable(table_data) print(table.table + '\n') print( 'Summary of results from {3} to {4}\nHigh: {0}\nMedium: {1}' '\nLow: {2}\n\n'.format( int(sum_high), int(sum_medium), int(sum_low), from_date.isoformat(), to_date.isoformat(), ) ) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) month = int(args.script[1]) year = int(args.script[2]) from_date = date(year, month, 1) to_date = from_date + timedelta(days=31) # To have the first day in month to_date = to_date.replace(day=1) print_reports(gmp, from_date, to_date) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/nvt-scan.gmp.py000066400000000000000000000065321400201773500201030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from datetime import datetime from gvm.errors import GvmError def check_args(args): len_args = len(args.script) - 1 if len_args != 2: message = """ This script creates a new task with specific host and nvt! It needs two parameters after the script name. -- oid of the nvt -- scan target Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname 1.3.6.1.4.1.25623.1.0.106223 localhost """ print(message) sys.exit() def create_config(gmp, nvt_oid): # Create new config copy_id = '085569ce-73ed-11df-83c3-002264764cea' config_name = nvt_oid config_id = '' try: res = gmp.create_config(copy_id, config_name) config_id = res.xpath('@id')[0] # Modify the config with an nvt oid nvt = gmp.get_nvt(nvt_oid) family = nvt.xpath('nvt/family/text()')[0] gmp.modify_config( config_id, 'nvt_selection', nvt_oids=[nvt_oid], family=family ) # This nvts must be present to work family = 'Port scanners' nvts = ['1.3.6.1.4.1.25623.1.0.14259', '1.3.6.1.4.1.25623.1.0.100315'] gmp.modify_config( config_id, 'nvt_selection', nvt_oids=nvts, family=family ) except GvmError: res = gmp.get_configs(filter='name=%s' % config_name) config_id = res.xpath('config/@id')[0] return config_id def create_target(gmp, name): try: res = gmp.create_target(name, hosts=[name]) target_id = res.xpath('@id')[0] except GvmError: res = gmp.get_targets(filter='name=%s hosts=%s' % (name, name)) target_id = res.xpath('target/@id')[0] return target_id def create_and_start_task(gmp, name, nvt_oid, config_id, target_id): # Standard Scanner OpenVAS Default scanner_id = '08b69003-5fc2-4037-a479-93b440211c73' # Create task task_name = '%s_%s_%s' % ( name, nvt_oid, datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ) res = gmp.create_task(task_name, config_id, target_id, scanner_id) task_id = res.xpath('@id')[0] # Start the task gmp.start_task(task_id) print('\nTask %s started' % task_id) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) nvt_oid = args.script[1] target_name = args.script[2] config_id = create_config(gmp, nvt_oid) target_id = create_target(gmp, target_name) create_and_start_task(gmp, target_name, nvt_oid, config_id, target_id) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/pdf-report.gmp.py000066400000000000000000000052051400201773500204300ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from base64 import b64decode from pathlib import Path def check_args(args): len_args = len(args.script) - 1 if len_args < 1: message = """ This script requests the given report and saves it as a pdf file locally. It needs one parameters after the script name. 1. -- ID of the report Optional a file name to save the pdf in. Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/pdf-report.gmp.py """ print(message) sys.exit() def main(gmp, args): # check if report id and PDF filename are provided to the script # argv[0] contains the script name check_args(args) report_id = args.argv[1] if len(args.argv) == 3: pdf_filename = args.argv[2] else: pdf_filename = args.argv[1] + ".pdf" pdf_report_format_id = "c402cc3e-b531-11e1-9163-406186ea4fc5" response = gmp.get_report( report_id=report_id, report_format_id=pdf_report_format_id ) report_element = response.find("report") # get the full content of the report element content = report_element.find("report_format").tail if not content: print( 'Requested report is empty. Either the report does not contain any ' ' results or the necessary tools for creating the report are ' 'not installed.', file=sys.stderr, ) sys.exit(1) # convert content to 8-bit ASCII bytes binary_base64_encoded_pdf = content.encode('ascii') # decode base64 binary_pdf = b64decode(binary_base64_encoded_pdf) # write to file and support ~ in filename path pdf_path = Path(pdf_filename).expanduser() pdf_path.write_bytes(binary_pdf) print('Done. PDF created: ' + str(pdf_path)) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/random-report-gen.gmp.py000066400000000000000000000323761400201773500217170ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # pylint: disable=too-many-lines import time import textwrap import json from random import randrange, choice, gauss, seed from argparse import ArgumentParser, RawTextHelpFormatter from pathlib import Path from lxml import etree as e from gvmtools.helper import ( generate_uuid, generate_id, generate_random_ips, ) __version__ = "0.1.0" HELP_TEXT = """ Random Report Generation Script {version} (C) 2017-2021 Greenbone Networks GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . This script generates randomized report data. """.format( version=__version__ ) def generate_ports(n_ports): protocol = ['/tcp', '/udp'] return [str(randrange(0, 65536)) + choice(protocol) for i in range(n_ports)] def generate_report_elem(task, **kwargs): rep_format_id = 'a994b278-1f62-11e1-96ac-406186ea4fc5' rep_id = generate_uuid() outer_report_elem = e.Element( 'report', attrib={ 'extension': 'xml', 'id': rep_id, 'format_id': rep_format_id, 'content_type': 'text/xml', }, ) owner_elem = e.SubElement(outer_report_elem, 'owner') e.SubElement(owner_elem, 'name').text = 'testowner' e.SubElement(outer_report_elem, 'name').text = 'testname' e.SubElement(outer_report_elem, 'writeable').text = str(0) e.SubElement(outer_report_elem, 'in_use').text = str(0) task_elem = e.SubElement(outer_report_elem, 'task', attrib={'id': task[0]}) e.SubElement(task_elem, 'name').text = task[1] repform_elem = e.SubElement( outer_report_elem, 'report_format', attrib={'id': rep_format_id} ) e.SubElement(repform_elem, 'name').text = 'XML' # Generating inner tag outer_report_elem.append(generate_inner_report(rep_id, **kwargs)) return outer_report_elem def generate_inner_report(rep_id, n_results, n_hosts, data, **kwargs): report_elem = e.Element('report', attrib={'id': rep_id}) results_elem = e.SubElement( report_elem, 'results', {'max': str(n_results), 'start': '1'} ) # Create Hosts, Ports, Data hosts = generate_random_ips(n_hosts) # Host IPs ports = generate_ports(n_hosts) oid_dict = {host: [] for host in hosts} asset_dict = {host: generate_uuid() for host in hosts} host_names = {host: generate_id() for host in hosts} max_sev = 0.0 # Create tags with random data for _ in range(n_results): host_ip = choice(hosts) host_port = choice(ports) result_elem, oid, severity = generate_result_elem( data["vulns"], host_ip, host_port, asset_dict[host_ip], host_names[host_ip], ) if float(severity) > max_sev: max_sev = float(severity) oid_dict[host_ip].append(oid) results_elem.append(result_elem) e.SubElement(report_elem, "result_count").text = str(n_results) sev_elem = e.Element("severity") e.SubElement(sev_elem, "full").text = str(max_sev) e.SubElement(sev_elem, "filtered").text = str(max_sev) report_elem.append(sev_elem) # Create tags with random data for host in hosts: if len(oid_dict[host]) > 0: report_elem.append( generate_host_elem( host, oid_dict[host][0], asset_dict[host], host_names[host], data=data, **kwargs, ) ) return report_elem def generate_result_elem(vulns, host_ip, host_port, host_asset, host_name): result_elem = e.Element('result', {'id': generate_uuid()}) e.SubElement(result_elem, 'name').text = "a_result" + generate_id() own = e.SubElement(result_elem, 'owner') e.SubElement(own, 'name').text = generate_id() elem = e.Element('modification_time') e.SubElement(result_elem, 'modification_time').text = ( time.strftime("%Y-%m-%dT%H:%M:%S%z", time.localtime(time.time()))[:-2] + ':00' ) # Hell of a Timeformat :D e.SubElement(result_elem, 'comment').text = '' e.SubElement(result_elem, 'creation_time').text = ( time.strftime("%Y-%m-%dT%H:%M:%S%z", time.localtime(time.time() - 20))[ :-2 ] + ':00' ) host_elem = e.Element('host') host_elem.text = host_ip e.SubElement(host_elem, 'asset', {'asset_id': host_asset}).text = '' e.SubElement(host_elem, 'hostname').text = host_name result_elem.append(host_elem) port_elem = e.Element('port') port_elem.text = host_port result_elem.append(port_elem) nvt = vulns[randrange(len(vulns))] e.SubElement(result_elem, 'severity').text = nvt['severity'] nvt_elem = e.Element('nvt', {'oid': nvt['oid']}) result_elem.append(nvt_elem) e.SubElement(result_elem, 'notes').text = 'TestNotes' result_elem.append(elem) return result_elem, nvt['oid'], nvt['severity'] def generate_host_detail_elem( name, value, source_name=None, source_description=None ): host_detail_elem = e.Element('detail') e.SubElement(host_detail_elem, 'name').text = name e.SubElement(host_detail_elem, 'value').text = value if source_name: source_elem = e.SubElement(host_detail_elem, 'source') e.SubElement(source_elem, 'name').text = source_name if source_description: e.SubElement(source_elem, 'description').text = source_description return host_detail_elem def generate_additional_host_details( n_details, host_details, *, not_vuln=False ): host_detail_elems = [] for _ in range(n_details): details = None if not_vuln: details = host_details.copy() details["source_name"] += str(randrange(14259, 103585)) else: details = choice(host_details) host_detail_elems.append( generate_host_detail_elem( details['name'], details['value'], source_name=details.get('source_name'), source_description=details.get('source_description'), ) ) return host_detail_elems def generate_host_elem( host_ip, oid, host_asset, host_name, n_host_details, n_not_vuln, data ): host_elem = e.Element('host') e.SubElement(host_elem, 'ip').text = host_ip e.SubElement(host_elem, 'asset', {'asset_id': host_asset}).text = '' e.SubElement(host_elem, 'start').text = ( time.strftime( "%Y-%m-%dT%H:%M:%S%z", time.localtime(time.time() - 1000) )[:-2] + ':00' ) e.SubElement(host_elem, 'end').text = ( time.strftime("%Y-%m-%dT%H:%M:%S%z", time.localtime(time.time() - 30))[ :-2 ] + ':00' ) app = choice(list(data["apps"])) os = choice(list(data["oss"])) host_elem.append( generate_host_detail_elem('App', data["apps"].get(app), source_name=oid) ) host_elem.append( generate_host_detail_elem( data["apps"].get(app), '/usr/bin/foo', source_name=oid ) ) host_elem.append( generate_host_detail_elem( 'hostname', host_name, source_name=oid, source_description="Host Details", ) ) host_elem.append( generate_host_detail_elem( 'best_os_txt', list(os)[0], source_name=oid, source_description="Host Details", ) ) host_elem.append( generate_host_detail_elem( 'best_os_cpe', data["oss"].get(os), source_name=oid, source_description="Host Details", ) ) if n_host_details: host_elem.extend( generate_additional_host_details( n_host_details, data["host_details"] ) ) dev = n_not_vuln / 10 if n_not_vuln: host_elem.extend( generate_additional_host_details( n_not_vuln + randrange(-dev, dev), data["not_vuln"], not_vuln=True, ) ) return host_elem def generate_reports(task, n_reports, with_gauss, **kwargs): reports = [] if with_gauss: n_reports = abs(int(gauss(n_reports, 1))) if n_reports == 0: n_reports += 1 for _ in range(n_reports): if with_gauss: n_results = abs(int(gauss(n_results, 2))) report_elem = generate_report_elem(task, **kwargs) report_elem = e.tostring(report_elem) reports.append(report_elem) return reports def generate_data(gmp, n_tasks, **kwargs): for i in range(n_tasks): index = '{{0:0>{}}}'.format(len(str(n_tasks))) task_name = 'Task_for_GenReport:_{}'.format(index.format(i + 1)) gmp.create_container_task(task_name) task_id = gmp.get_tasks(filter='name={}'.format(task_name)).xpath( '//@id' )[0] reports = generate_reports(task=(task_id, task_name), **kwargs) for report in reports[0:]: gmp.import_report(report, task_id=task_id, in_assets=True) def main(gmp, args): # pylint: disable=undefined-variable, line-too-long parser = ArgumentParser( prog="random-report-gen", prefix_chars="-", description=HELP_TEXT, formatter_class=RawTextHelpFormatter, add_help=False, epilog=textwrap.dedent( """ Example: $ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/gen-random-reports.gmp.py -T 5 -r 4 -R 3 --hosts 10 """ ), ) parser.add_argument( "-H", action="help", help="Show this help message and exit." ) parser.add_argument( "--datafile", default=Path(args.script[0]).parent / "default_report_data.json", help="A json file containing the following information: " "vulnerabilities, operating systems, applications and host details. " "Take the default json file as an example.", ) parser.add_argument( "--tasks", "-T", type=int, default="1", help="Number of Tasks to be generated.", ) parser.add_argument( "--reports", "-r", type=int, default="5", help="Number of Reports per Task.", ) parser.add_argument( "--results", "-R", type=int, default="5", help="Number of Results per Report.", ) parser.add_argument( "--hosts", type=int, default="5", help="Number of randomized hosts to select from.", ) parser.add_argument( "--host-details", dest="host_details", type=int, default="2", help="Number of additional host details per host.", ) parser.add_argument( "--not-vuln-details", dest="not_vuln", type=int, default="10", help="Number of 'NOT_VULN' host details per host.", ) parser.add_argument( "--with-gauss", dest="with_gauss", action="store_true", help="if you would like for the number of reports/task and " "results/report to be randomized along a Gaussian distribution.", ) parser.add_argument( "--seed", help="RNG Seed, in case the same data should be generated." ) script_args = parser.parse_args(args.script_args) if not script_args.seed: seed() else: seed(script_args.seed) with open(str(script_args.datafile)) as file: data = json.load(file) print('\n Generating randomized data(s)...\n') generate_data( gmp, n_tasks=script_args.tasks, n_reports=script_args.reports, n_results=script_args.results, n_hosts=script_args.hosts, n_host_details=script_args.host_details, n_not_vuln=script_args.not_vuln, data=data, with_gauss=script_args.with_gauss, ) print('\n Generation done.\n') if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/requirements.txt000066400000000000000000000001011400201773500204640ustar00rootroot00000000000000# required for monthly-report and monthly-report2 terminaltables gvm-tools-21.1.0/scripts/scan-new-system.gmp.py000066400000000000000000000057561400201773500214160ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import datetime import sys def check_args(args): len_args = len(args.script) - 1 message = """ This script starts a new scan on the given host. It needs one parameters after the script name. 1. -- IP Address of the host system 2. -- Port List UUID for scanning the host system. Preconfigured UUID might be under /var/lib/gvm/data-objects/gvmd/20.08/port_lists/. ex. iana-tcp-udp is "4a4717fe-57d2-11e1-9a26-406186ea4fc5". Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/scan-new-system.gmp.py """ if len_args != 2: print(message) sys.exit() def create_target(gmp, ipaddress, port_list_id): # create a unique name by adding the current datetime name = "Suspect Host {} {}".format(ipaddress, str(datetime.datetime.now())) response = gmp.create_target( name=name, hosts=[ipaddress], port_list_id=port_list_id ) return response.get('id') def create_task(gmp, ipaddress, target_id, scan_config_id, scanner_id): name = "Scan Suspect Host {}".format(ipaddress) response = gmp.create_task( name=name, config_id=scan_config_id, target_id=target_id, scanner_id=scanner_id, ) return response.get('id') def start_task(gmp, task_id): response = gmp.start_task(task_id) # the response is # id return response[0].text def main(gmp, args): check_args(args) ipaddress = args.argv[1] port_list_id = args.argv[2] target_id = create_target(gmp, ipaddress, port_list_id) full_and_fast_scan_config_id = 'daba56c8-73ec-11df-a475-002264764cea' openvas_scanner_id = '08b69003-5fc2-4037-a479-93b440211c73' task_id = create_task( gmp, ipaddress, target_id, full_and_fast_scan_config_id, openvas_scanner_id, ) report_id = start_task(gmp, task_id) print( "Started scan of host {}. Corresponding report ID is {}".format( ipaddress, report_id ) ) if __name__ == '__gmp__': # pylint: disable=undefined-variable main(gmp, args) gvm-tools-21.1.0/scripts/send-delta-emails.gmp.py000066400000000000000000000164601400201773500216430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # GMP script for gvm-pyshell to send emails with delta reports. import base64 import datetime import sched import smtplib import sys import time from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart from email.utils import formatdate def check_args(args): len_args = len(args.script) - 1 if len_args is not 0: message = """ This script, once started, will continuously send delta reports via email for selected tasks. Example for starting up the routine: $ gvm-script --gmp-username name --gmp-password pass ssh --hostname scripts/send-delta-emails.gmp.py The routine follows this procedure: Every minutes do: Get all tasks where the tag is attached. For each of these tasks get the finished reports: If less than 2 reports, continue with next task If latest report has tag "delta_alert_sent", continue with next task Create a CSV report from the delta of latest vs. previous report where filtered for only the new results. Send the CSV as an attachment to the configured email address. """ print(message) sys.exit() def execute_send_delta_emails(sc, **kwargs): gmp = kwargs.get('gmp') task_tag = kwargs.get('task_tag') interval = kwargs.get('interval') email_subject = kwargs.get('email_subject') to_addresses = kwargs.get('to_addresses') from_address = kwargs.get('from_address') mta_address = kwargs.get('mta_address') mta_user = kwargs.get('mta_user') mta_port = kwargs.get('mta_port') mta_password = kwargs.get('mta_password') report_tag_name = kwargs.get('report_tag_name') print('Retrieving task list ...') task_filter = 'tag=%s' % task_tag tasks = gmp.get_tasks(filter=task_filter).xpath('task') print('Found %d task(s) with tag "%s".' % (len(tasks), task_tag)) for task in tasks: task_id = task.xpath('@id')[0] print( 'Processing task "%s" (%s)...' % (task.xpath('name/text()')[0], task_id) ) reports = gmp.get_reports( filter='task_id={0} and status=Done ' 'sort-reverse=date'.format(task_id) ).xpath('report') print(' Found %d report(s).' % len(reports)) if len(reports) < 2: print(' Delta-reporting requires at least 2 finished reports.') continue if reports[0].xpath( 'report/user_tags/tag/' 'name[text()="delta_alert_sent"]' ): print(' Delta report for latest finished report already sent') continue print( ' Latest finished report not send yet. Preparing delta ' 'report...' ) delta_report = gmp.get_report( report_id=reports[0].xpath('@id')[0], delta_report_id=reports[1].xpath('@id')[0], filter='delta_states=n', format_id='c1645568-627a-11e3-a660-406186ea4fc5', ) csv_in_b64 = delta_report.xpath('report/text()')[0] csv = base64.b64decode(csv_in_b64) print(" Composing Email...") alert_email = MIMEMultipart() alert_email['Subject'] = email_subject alert_email['To'] = ', '.join(to_addresses) alert_email['From'] = from_address alert_email['Date'] = formatdate(localtime=True) report_attachment = MIMEBase('application', "octet-stream") report_attachment.add_header( 'Content-Disposition', 'attachment', filename='delta.csv' ) report_attachment.set_payload(csv) alert_email.attach(report_attachment) print(" Sending Email...") try: with smtplib.SMTP(mta_address, mta_port) as smtp: smtp.ehlo() smtp.starttls() smtp.ehlo() smtp.login(mta_user, mta_password) # if required smtp.sendmail( from_address, to_addresses, alert_email.as_string() ) smtp.close() print(" Email has been sent!") gmp.create_tag( name=report_tag_name, resource_id=reports[0].xpath('@id')[0], resource_type='report', value=datetime.datetime.now(), ) except Exception: # pylint: disable=broad-except print(" Unable to send the email. Error: ", sys.exc_info()[0]) # raise # in case an error should stop the script continue # ignore the problem for the time being print("\nCheck will be repeated in {} minutes...\n".format(interval)) sc.enter( interval * 60, 1, execute_send_delta_emails, argument=(sc,), kwargs=kwargs, ) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) interval = 1 # in minutes task_tag = 'send_delta_alert' report_tag_name = 'delta_alert_sent' email_subject = 'Delta Report' from_address = 'admin@example.com' to_addresses = ['user1@example.com', 'user2@example.com'] mta_address = 'mail.example.com' mta_port = 25 mta_user = 'admin@example.com' mta_password = 'mysecret' print('send_delta_alerts starting up with following settings:') print('User: %s' % args.username) print('Interval: %d minutes' % interval) print('Task tag: %s' % task_tag) print('Email subject: %s' % email_subject) print('From Address: %s' % from_address) print('To Addresses: %s' % to_addresses) print('MTA Address: %s' % mta_address) print('MTA Port: %s' % mta_port) print('MTA User: %s' % mta_user) print('MTA Password: ') print() print('Entering loop with interval %s minutes ...' % interval) schedule = sched.scheduler(time.time, time.sleep) # Enter the scheduled execution with the given interval schedule.enter( 0, 1, execute_send_delta_emails, argument=(schedule,), kwargs={ 'gmp': gmp, 'task_tag': task_tag, 'interval': interval, 'email_subject': email_subject, 'to_addresses': to_addresses, 'from_address': from_address, 'mta_address': mta_address, 'mta_password': mta_password, 'mta_port': mta_port, 'mta_user': mta_user, 'report_tag_name': report_tag_name, }, ) schedule.run() if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/send-schedules.gmp.py000066400000000000000000000042621400201773500212560ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from gvmtools.helper import create_xml_tree def check_args(args): len_args = len(args.script) - 1 if len_args != 1: message = """ This script pulls schedule data from an xml document and feeds it to \ a desired GSM One parameter after the script name is required. 1. -- .xml file containing schedules Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/send-schedules.gmp.py example_file.xml """ print(message) sys.exit() if int(gmp.get_protocol_version()[0]) < 8: print("This script requires GMP version 8") sys.exit() def parse_send_xml_tree(gmp, xml_tree): for schedule in xml_tree.xpath('schedule'): name = schedule.find('name').text comment = schedule.find('comment').text if comment is None: comment = '' ical = schedule.find('icalendar').text timezone = schedule.find('timezone').text gmp.create_schedule( name=name, comment=comment, timezone=timezone, icalendar=ical ) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) xml_doc = args.script[1] print('\nSending schedules...') xml_tree = create_xml_tree(xml_doc) parse_send_xml_tree(gmp, xml_tree) print('\n Schedule(s) created!\n') if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/send-targets.gmp.py000066400000000000000000000105011400201773500207410ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from gvm.protocols.gmpv9.types import get_alive_test_from_string from gvmtools.helper import create_xml_tree, yes_or_no def check_args(args): len_args = len(args.script) - 1 if len_args != 1: message = """ This script pulls target data from an xml document and feeds it to \ a desired GSM One parameter after the script name is required. 1. -- .xml file containing targets Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/send-targets.gmp.py example_file.xml """ print(message) sys.exit() def parse_send_xml_tree(gmp, xml_tree): credential_options = [ 'ssh_credential', 'smb_credential', 'esxi_credential', 'snmp_credential', ] counter = 1 for target in xml_tree.xpath('target'): keywords = {} # {'make_unique': True} keywords['name'] = target.find('name').text keywords['hosts'] = target.find('hosts').text.split(',') exclude_hosts = target.find('exclude_hosts').text if exclude_hosts is not None: keywords['exclude_hosts'] = exclude_hosts.split(',') comment = target.find('comment').text if comment is not None: keywords['comment'] = comment credentials = gmp.get_credentials()[0].xpath("//credential/@id") for credential in credential_options: cred_id = target.find(credential).xpath('@id')[0] if cred_id == '': continue if cred_id not in credentials: response = yes_or_no( "\nThe credential '{}' for 'target {}' could not be " "located...\nWould you like to continue?".format( credential, counter ) ) if response is False: print("Terminating...\n") sys.exit() else: continue key = '{}_id'.format(credential) keywords[key] = cred_id elem_path = target.find(credential) port = elem_path.find('port') if port is not None and port.text is not None: port_key = '{}_port'.format(credential) keywords[port_key] = elem_path.find('port').text alive_test = get_alive_test_from_string(target.find('alive_tests').text) if alive_test is not None: keywords['alive_test'] = alive_test reverse_lookup_only = target.find('reverse_lookup_only').text if reverse_lookup_only == '1': keywords['reverse_lookup_only'] = 1 reverse_lookup_unify = target.find('reverse_lookup_unify').text if reverse_lookup_unify == '1': keywords['reverse_lookup_unify'] = 1 port_range = target.find('port_range') if port_range is not None: keywords['port_range'] = port_range.text if target.xpath('port_list/@id') is not None: port_list = {} port_list = target.xpath('port_list/@id')[0] keywords['port_list_id'] = port_list print(keywords) gmp.create_target(**keywords) counter += 1 def main(gmp, args): # pylint: disable=undefined-variable check_args(args) xml_doc = args.script[1] print('\nSending targets...') xml_tree = create_xml_tree(xml_doc) parse_send_xml_tree(gmp, xml_tree) print('\n Target(s) created!\n') if __name__ == '__gmp__': main(gmp, args) # pylint: disable=undefined-variable gvm-tools-21.1.0/scripts/send-tasks.gmp.py000066400000000000000000000134061400201773500204240ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys from argparse import ArgumentParser, RawTextHelpFormatter from gvmtools.helper import create_xml_tree, error_and_exit, yes_or_no HELP_TEXT = """ This script pulls tasks data from an xml document and feeds it to \ a desired GSM Usage examples: $ gvm-script --gmp-username name --gmp-password pass ssh --hostname ... send-task.gmp.py +h ... send-task.gmp.py ++x xml_file """ def numerical_option(statement, list_range): choice = int(input(statement)) if choice in range(1, list_range + 1): return choice else: return numerical_option( "Please enter valid number from {} to {}...".format(1, list_range), list_range, ) def interactive_options(gmp, task, keywords): options_dict = {} options_dict['config'] = gmp.get_configs() options_dict['scanner'] = gmp.get_scanners() options_dict['target'] = gmp.get_targets() for option in options_dict: object_dict, object_list = {}, [] object_id = task.find(option).get('id') object_xml = options_dict[option] for i in object_xml.findall(option): object_dict[i.find('name').text] = i.xpath('@id')[0] object_list.append(i.find('name').text) if object_id in object_dict.values(): keywords['{}_id'.format(option)] = object_id elif object_id not in object_dict.values() and len(object_dict) != 0: response = yes_or_no( "\nRequired Field: failed to detect {}_id: {}... " "\nWould you like to select from available options, or exit " "the script?".format( option, task.xpath('{}/@id'.format(option))[0] ) ) if response is True: counter = 1 print("{} options:".format(option.capitalize())) for j in object_list: print(" {} - {}".format(counter, j)) counter += 1 answer = numerical_option( "\nPlease enter the number of your choice.", len(object_list), ) keywords['{}_id'.format(option)] = object_dict[ object_list[answer - 1] ] else: print("\nTerminating...") sys.exit() else: error_and_exit( "Failed to detect {}_id" "\nThis field is required therefore the script is unable to " "continue.\n".format(option) ) def parse_send_xml_tree(gmp, xml_tree): task_xml_elements = xml_tree.xpath('task') print(task_xml_elements) if not task_xml_elements: error_and_exit("No tasks found.") tasks = [] for task in task_xml_elements: keywords = {'name': task.find('name').text} if task.find('comment').text is not None: keywords['comment'] = task.find('comment').text interactive_options(gmp, task, keywords) if task.find('schedule_periods') is not None: keywords['schedule_periods'] = int( task.find('schedule_periods').text ) if task.find('observers').text: keywords['observers'] = task.find('observers').text if task.xpath('schedule/@id')[0]: keywords['schedule_id'] = task.xpath('schedule/@id')[0] if task.xpath('preferences/preference'): preferences, scanner_name_list, value_list = {}, [], [] for preference in task.xpath('preferences/preference'): scanner_name_list.append(preference.find('scanner_name').text) if preference.find('value').text is not None: value_list.append(preference.find('value').text) else: value_list.append('') preferences['scanner_name'] = scanner_name_list preferences['value'] = value_list keywords['preferences'] = preferences new_task = gmp.create_task(**keywords) tasks.append(new_task.xpath('//@id')[0]) return tasks def main(gmp, args): # pylint: disable=undefined-variable, unused-argument parser = ArgumentParser( prefix_chars="+", add_help=False, formatter_class=RawTextHelpFormatter, description=HELP_TEXT, ) parser.add_argument( "+h", "++help", action="help", help="Show this help message and exit.", ) parser.add_argument( "+x", "++xml-file", dest='xml', type=str, required=True, help='xml file containing tasks', ) script_args, _ = parser.parse_known_args() # check_args(args) print('\nSending task(s)...') xml_tree = create_xml_tree(script_args.xml) tasks = parse_send_xml_tree(gmp, xml_tree) for task in tasks: print(task) print('\nTask(s) sent!\n') if __name__ == '__gmp__': main(gmp, args) # pylint: disable=undefined-variable gvm-tools-21.1.0/scripts/start-alert-scan.gmp.py000066400000000000000000000260461400201773500215400ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 Henning Häcker # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from typing import List from argparse import ArgumentParser, RawTextHelpFormatter HELP_TEXT = """ This script makes an E-Mail alert scan. Usage examples: $ gvm-script --gmp-username name --gmp-password pass ssh --hostname ... start-alert-scan.gmp.py +h ... start-alert-scan.gmp.py ++target-name ++hosts ++ports \ ++port-list-name +C +R +S ... start-alert-scan.gmp.py ++target-name ++hosts ++port-list-id \ +C ++recipient ++sender ... start-alert-scan.gmp.py ++target-id +C ++recipient ++sender """ def get_config(gmp, config, debug=False): # get all configs of the openvas instance # filter for all rows! res = gmp.get_configs(filter="rows=-1") if config < 0 or config > 4: raise ValueError("Wrong config identifier. Choose between [0,4].") # match the config abbreviation to accepted config names config_list = [ 'Full and fast', 'Full and fast ultimate', 'Full and very deep', 'Full and very deep ultimate', 'System Discovery', ] template_abbreviation_mapper = { 0: config_list[0], 1: config_list[1], 2: config_list[2], 3: config_list[3], 4: config_list[4], } for conf in res.xpath('config'): cid = conf.xpath('@id')[0] name = conf.xpath('name/text()')[0] # get the config id of the desired template if template_abbreviation_mapper.get(config) == name: config_id = cid if debug: print(name + ": " + config_id) break return config_id def get_target( gmp, target_name: str = None, hosts: List[str] = None, ports: str = None, port_list_name: str = None, port_list_id: str = None, debug: bool = True, ): if target_name is None: target_name = "target" targets = gmp.get_targets(filter=target_name) existing_targets = [""] for target in targets.findall("target"): existing_targets.append(str(target.find('name').text)) counter = 0 # iterate over existing targets and find a vacant targetName if target_name in existing_targets: while True: tmp_name = "{} ({})".format(target_name, str(counter)) if tmp_name in existing_targets: counter += 1 else: target_name = tmp_name break if debug: print("target name: {}".format(target_name)) if not port_list_id: existing_port_lists = [""] port_lists_tree = gmp.get_port_lists() for plist in port_lists_tree.findall("port_list"): existing_port_lists.append(str(plist.find('name').text)) print(existing_port_lists) if port_list_name is None: port_list_name = "portlist" if port_list_name in existing_port_lists: counter = 0 while True: tmp_name = "{} ({})".format(port_list_name, str(counter)) if tmp_name in existing_port_lists: counter += 1 else: port_list_name = tmp_name break port_list = gmp.create_port_list(port_list_name, ports) # create port list port_list_id = port_list.xpath('@id')[0] if debug: print("New Portlist-name:\t{}".format(str(port_list_name))) print("New Portlist-id:\t{}".format(str(port_list_id))) # integrate port list id into create_target res = gmp.create_target(target_name, hosts=hosts, port_list_id=port_list_id) print("New target '{}' created.".format(target_name)) return res.xpath('@id')[0] def get_alert( gmp, sender_email: str, recipient_email: str, alert_name: str = None, debug=False, ): # create alert if necessary alert_object = gmp.get_alerts(filter='name={}'.format(alert_name)) alert = alert_object.xpath('alert') if len(alert) == 0: print("creating new alert {}".format(alert_name)) gmp.create_alert( alert_name, event=gmp.types.AlertEvent.TASK_RUN_STATUS_CHANGED, event_data={"status": "Done"}, condition=gmp.types.AlertCondition.ALWAYS, method=gmp.types.AlertMethod.EMAIL, method_data={ """Task '$n': $e After the event $e, the following condition was met: $c This email escalation is configured to attach report format '$r'. Full details and other report formats are available on the scan engine. $t Note: This email was sent to you as a configured security scan escalation. Please contact your local system administrator if you think you should not have received it. """: "message", "2": "notice", sender_email: "from_address", "[OpenVAS-Manager] Task": "subject", "c402cc3e-b531-11e1-9163-406186ea4fc5": "notice_attach_format", recipient_email: "to_address", }, ) alert_object = gmp.get_alerts(filter='name={}'.format(recipient_email)) alert = alert_object.xpath('alert') alert_id = alert[0].get('id', 'no id found') if debug: print("alert_id: {}".format(str(alert_id))) return alert_id def get_scanner(gmp): res = gmp.get_scanners() scanner_ids = res.xpath('scanner/@id') return scanner_ids[1] # "default scanner" def create_and_start_task( gmp, config_id: str, target_id: str, scanner_id: str, alert_id: str, alert_name: str, debug: bool = False, ): # Create the task task_name = "Alert Scan for Alert {}".format(alert_name) tasks = gmp.get_tasks(filter='name="{}"'.format(task_name)) task_objects = tasks.findall('task') print(task_objects) if task_objects: task_name = "Alert Scan for Alert {} ({})".format( alert_name, len(task_objects) ) task_comment = "Alert Scan" res = gmp.create_task( task_name, config_id, target_id, scanner_id, alert_ids=[alert_id], comment=task_comment, ) # Start the task task_id = res.xpath('@id')[0] gmp.start_task(task_id) if debug: # Stop the task (for performance reasons) gmp.stop_task(task_id) print('Task stopped') return task_name def parse_args(args): # pylint: disable=unused-argument parser = ArgumentParser( prefix_chars="+", add_help=False, formatter_class=RawTextHelpFormatter, description=HELP_TEXT, ) parser.add_argument( "+h", "++help", action="help", help="Show this help message and exit.", ) target = parser.add_mutually_exclusive_group(required=True) target.add_argument( "++target-id", type=str, dest="target_id", help="Use an existing target by target id", ) target.add_argument( "++target-name", type=str, dest="target_name", help="Create a target by name", ) parser.add_argument( "++hosts", nargs='+', dest='hosts', help="Host(s) for the new target", ) ports = parser.add_mutually_exclusive_group() ports.add_argument( "++port-list-id", type=str, dest="port_list_id", help="An existing portlist id for the new target", ) ports.add_argument( "++ports", type=str, dest='ports', help="Ports in the new target: e.g. T:80-80,8080", ) parser.add_argument( "++port-list-name", type=str, dest="port_list_name", help="Name for the new portlist in the new target", ) config = parser.add_mutually_exclusive_group() config.add_argument( "+C", "++scan-config", default=0, type=int, dest='config', help="Choose from existing scan config:" "\n 0: Full and fast" "\n 1: Full and fast ultimate" "\n 2: Full and very deep" "\n 3: Full and very deep ultimate" "\n 4: System Discovery", ) config.add_argument( "++scan-config-id", type=str, dest='scan_config_id', help="Use existing scan config by id", ) parser.add_argument( "++scanner-id", type=str, dest='scanner_id', help="Use existing scanner by id", ) parser.add_argument( "+R", "++recipient", required=True, dest='recipient_email', type=str, help="Alert recipient E-Mail address", ) parser.add_argument( "+S", "++sender", required=True, dest='sender_email', type=str, help="Alert senders E-Mail address", ) parser.add_argument( "++alert-name", dest='alert_name', type=str, help="Optional Alert name", ) script_args, _ = parser.parse_known_args() return script_args def main(gmp, args): # pylint: disable=undefined-variable, unused-argument script_args = parse_args(args) # set alert_name to recipient email if no other name # is given if script_args.alert_name is None: script_args.alert_name = script_args.recipient_email # use existing config from argument if not script_args.scan_config_id: config_id = get_config(gmp, script_args.config) else: config_id = script_args.scan_config_id # create new target or use existing one from id if not script_args.target_id: target_id = get_target( gmp, target_name=script_args.target_name, hosts=script_args.hosts, ports=script_args.ports, port_list_name=script_args.port_list_name, port_list_id=script_args.port_list_id, ) else: target_id = script_args.target_id alert_id = get_alert( gmp, script_args.sender_email, script_args.recipient_email, script_args.alert_name, ) if not script_args.scanner_id: scanner_id = get_scanner(gmp) else: scanner_id = script_args.scanner_id create_and_start_task( gmp, config_id, target_id, scanner_id, alert_id, script_args.alert_name ) print('Task started: ' + task_name) print("\nScript finished\n") if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/start-multiple-alerts-scan.gmp.py000066400000000000000000000207241400201773500235510ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2018 inovex GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys def check_args(args): len_args = len(args.script) - 1 message = """ This script makes an alert scan It needs two parameters after the script name. 1. -- E-Mail of the sender 2. -- E-Mail of the receiver Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/start-multiple-alert-scan.gmp.py """ if len_args != 2: print(message) sys.exit() # returns a list containing all port_list names def get_port_list_names(gmp): res = gmp.get_port_lists() port_names_list = [""] for name in res.findall("port_list/name"): port_names_list.append(str(name.text)) return port_names_list def get_config(gmp, debug=False): # get all configs of the openvas instance res = gmp.get_configs() # configurable template template = "fast" # match the config abbreviation to accepted config names config_list = [ 'Full and fast', 'Full and fast ultimate', 'Full and very deep', 'Full and very deep ultimate', 'System Discovery', ] template_abbreviation_mapper = { "fast": config_list[0], "fast-ulti": config_list[1], "deep": config_list[2], "deep-ulti": config_list[3], "discovery": config_list[4], } config_id = "-" for conf in res.xpath('config'): cid = conf.xpath('@id')[0] name = conf.xpath('name/text()')[0] # get the config id of the desired template if template_abbreviation_mapper.get(template, "-") == name: config_id = cid if debug: print("%s: %s" % (name, config_id)) break # check for existence of the desired config if config_id == "-": print( "error: could not recognize template '%s'\n" "valid template names are: %s\n" % (template, config_list) ) exit() return config_id def get_target(gmp, debug=False): # find a targetName targets = gmp.get_targets() counter = 0 exists = True # iterate over existing targets and find a vacant targetName while exists: exists = False target_name = "targetName%s" % str(counter) for target in targets.xpath('target'): name = target.xpath('name/text()')[0] if name == target_name: exists = True break counter += 1 if debug: print("target name: %s" % target_name) # iterate over existing port lists and find a vacant name new_port_list_name = "portlistName" counter = 0 while True: portlist_name = '%s%s' % (new_port_list_name, str(counter)) if portlist_name not in get_port_list_names(gmp): break counter += 1 # configurable port string port_string = "T:80-80" # create port list portlist = gmp.create_port_list(portlist_name, port_string) portlist_id = portlist.xpath('@id')[0] if debug: print("Portlist-name:\t%s" % str(portlist_name)) print("Portlist-id:\t%s" % str(portlist_id)) # configurable hosts hosts = ["localhost"] # integrate port list id into create_target res = gmp.create_target(target_name, hosts=hosts, port_list_id=portlist_id) return res.xpath('@id')[0] def get_alerts(gmp, sender_email, recipient_email, debug=False): # configurable alert name alert_name = recipient_email # create alert if necessary alert_object = gmp.get_alerts(filter='name=%s' % alert_name) alert_id = None alert = alert_object.xpath('alert') if len(alert) == 0: gmp.create_alert( alert_name, event=gmp.types.AlertEvent.TASK_RUN_STATUS_CHANGED, event_data={'status': 'Done'}, condition=gmp.types.AlertCondition.ALWAYS, method=gmp.types.AlertMethod.EMAIL, method_data={ """Task '$n': $e After the event $e, the following condition was met: $c This email escalation is configured to attach report format '$r'. Full details and other report formats are available on the scan engine. $t Note: This email was sent to you as a configured security scan escalation. Please contact your local system administrator if you think you should not have received it. """: "message", "2": "notice", sender_email: "from_address", "[OpenVAS-Manager] Task": "subject", "c402cc3e-b531-11e1-9163-406186ea4fc5": "notice_attach_format", recipient_email: "to_address", }, ) alert_object = gmp.get_alerts(filter='name=%s' % recipient_email) alert = alert_object.xpath('alert') alert_id = alert[0].get('id', 'no id found') else: alert_id = alert[0].get('id', 'no id found') if debug: print("alert_id: %s" % str(alert_id)) # second configurable alert name alert_name2 = "%s-2" % recipient_email # create second alert if necessary alert_object2 = gmp.get_alerts(filter='name=%s' % alert_name2) alert_id2 = None alert2 = alert_object2.xpath('alert') if len(alert2) == 0: gmp.create_alert( alert_name2, event=gmp.types.AlertEvent.TASK_RUN_STATUS_CHANGED, event_data={'status': 'Done'}, condition=gmp.types.AlertCondition.ALWAYS, method=gmp.types.AlertMethod.EMAIL, method_data={ """Task '$n': $e After the event $e, the following condition was met: $c This email escalation is configured to attach report format '$r'. Full details and other report formats are available on the scan engine. $t Note: This email was sent to you as a configured security scan escalation. Please contact your local system administrator if you think you should not have received it. """: "message", "2": "notice", sender_email: "from_address", "[OpenVAS-Manager] Task": "subject", recipient_email: "to_address", }, ) alert_object2 = gmp.get_alerts(filter='name=%s' % recipient_email) alert2 = alert_object2.xpath('alert') alert_id2 = alert2[0].get('id', 'no id found') else: alert_id2 = alert2[0].get('id', 'no id found') if debug: print("alert_id2: %s" % str(alert_id2)) return (alert_id, alert_id2) def get_scanner(gmp): res = gmp.get_scanners() scanner_ids = res.xpath('scanner/@id') return scanner_ids[1] # default scanner def create_and_start_task( gmp, config_id, target_id, scanner_id, alerts, debug=False ): # Create the task tasks = gmp.get_tasks(filter="name~ScanDoneMultipleAlert") task_name = "ScanDoneMultipleAlert{0}".format(len(tasks.xpath('tasks/@id'))) task_comment = "test comment" res = gmp.create_task( task_name, config_id, target_id, scanner_id, alert_ids=alerts, comment=task_comment, ) # Start the task task_id = res.xpath('@id')[0] gmp.start_task(task_id) print('Task started: %s' % task_name) if debug: # Stop the task (for performance reasons) gmp.stop_task(task_id) print('Task stopped') def main(gmp, args): # pylint: disable=undefined-variable check_args(args) sender_email = args.script[1] recipient_email = args.script[2] config_id = get_config(gmp) target_id = get_target(gmp) alerts = get_alerts(gmp, sender_email, recipient_email) scanner_id = get_scanner(gmp) create_and_start_task(gmp, config_id, target_id, scanner_id, alerts) print("\nScript finished\n") if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/start-nvt-scan.gmp.py000066400000000000000000000130621400201773500212320ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys def check_args(args): len_args = len(args.script) - 1 if len_args != 2: message = """ This script creates a new task with specific host and nvt! It needs two parameters after the script name. First one is the oid of the nvt and the second one is the chosen scan target. Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/start-nvt-scan.gmp.py \ 1.3.6.1.4.1.25623.1.0.106223 localhost """ print(message) sys.exit() def get_config(gmp, nvt_oid): # Choose from existing config, which to copy or create new config res = gmp.get_configs() config_ids = res.xpath('config/@id') for i, conf in enumerate(res.xpath('config')): config_id = conf.xpath('@id')[0] name = conf.xpath('name/text()')[0] print('\n({0}) {1}: ({2})'.format(i, name, config_id)) while True: chosen_config = input( '\nChoose your config or create new one[0-{len} | n]: '.format( len=len(config_ids) - 1 ) ) if chosen_config == 'n': chosen_copy_config = int( input( 'Which config to copy? [0-{len}]: '.format( len=len(config_ids) - 1 ) ) ) config_name = input('Enter new Name for config: ') copy_id = config_ids[chosen_copy_config] res = gmp.clone_config(copy_id) config_id = res.xpath('@id')[0] # Modify the config with an nvt oid if len(nvt_oid) is 0: nvt_oid = input('NVT OID: ') nvt = gmp.get_nvt(nvt_oid=nvt_oid) family = nvt.xpath('nvt/family/text()')[0] gmp.modify_config( config_id, 'nvt_selection', name=config_name, nvt_oids=[nvt_oid], family=family, ) # This nvts must be present to work family = 'Port scanners' nvts = [ '1.3.6.1.4.1.25623.1.0.14259', '1.3.6.1.4.1.25623.1.0.100315', ] gmp.modify_config( config_id, 'nvt_selection', nvt_oids=nvts, family=family ) return config_id if 0 <= int(chosen_config) < len(config_ids): return config_ids[int(chosen_config)] def get_target(gmp, hosts): # create a new target or use an existing targets = gmp.get_targets() target_ids = targets.xpath('target/@id') for i, target in enumerate(targets.xpath('target')): name = target.xpath('name/text()')[0] print('\n({0}) {1}'.format(i, name)) while True: if target_ids: chosen_target = input( '\nChoose your target or create new one[0-{len} | n]: '.format( len=len(target_ids) - 1 ) ) else: chosen_target = 'n' if chosen_target == 'n': if len(hosts) is 0: hosts = input('Target hosts (comma separated): ') name = input('Name of target: ') res = gmp.create_target(name, hosts=hosts.split(',')) return res.xpath('@id')[0] if 0 <= int(chosen_target) < len(target_ids): return target_ids[int(chosen_target)] def get_scanner(gmp): res = gmp.get_scanners() scanner_ids = res.xpath('scanner/@id') for i, scanner in enumerate(res.xpath('scanner')): scanner_id = scanner.xpath('@id')[0] name = scanner.xpath('name/text()')[0] # configs[id] = name print("\n({0})\n{1}: ({2})".format(i, name, scanner_id)) while True: chosen_scanner = int( input( '\nChoose your scanner [0-{len}]: '.format( len=len(scanner_ids) - 1 ) ) ) if 0 <= chosen_scanner < len(scanner_ids): return scanner_ids[chosen_scanner] def create_and_start_task( gmp, task_name, task_comment, config_id, target_id, scanner_id ): res = gmp.create_task( task_name, config_id, target_id, scanner_id, comment=task_comment ) # Start the task task_id = res.xpath('@id')[0] gmp.start_task(task_id) print('Task started') def main(gmp, args): # pylint: disable=undefined-variable check_args(args) nvt_oid = args.script[1] hosts = args.script[2] task_name = input('Task name: ') task_comment = input('Task comment: ') config_id = get_config(gmp, nvt_oid) target_id = get_target(gmp, hosts) scanner_id = get_scanner(gmp) create_and_start_task( gmp, task_name, task_comment, config_id, target_id, scanner_id ) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/sync-assets.gmp.py000066400000000000000000000047011400201773500206220ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import csv import sys def check_args(args): len_args = len(args.script) - 1 if len_args is not 1: message = """ This script reads asset data from a csv file and sync it with the gsm. It needs one parameters after the script name. 1. - should contain a table of IP-addresses with an optional a comment Example: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/sync-assets.gmp.py """ print(message) sys.exit() def sync_assets(gmp, filename): with open(filename, newline='') as f: reader = csv.reader(f, delimiter=',', quotechar='|') for row in reader: if len(row) == 2: ip = row[0] comment = row[1] # print('%s %s %s %s' % (host, ip, contact, location)) # check if asset is already there ret = gmp.get_assets( asset_type=gmp.types.AssetType.HOST, filter='ip=%s' % ip ) if ret.xpath('asset'): print('\nAsset with IP %s exist' % ip) asset_id = ret.xpath('asset/@id')[0] gmp.delete_asset(asset_id=asset_id) else: print('Asset with ip %s does not exist. Sync...' % ip) ret = gmp.create_host(name=ip, comment=comment) if 'OK' in ret.xpath('@status_text')[0]: print('Asset synced') def main(gmp, args): # pylint: disable=undefined-variable check_args(args) file = args.script[1] sync_assets(gmp, file) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/scripts/update-task-target.gmp.py000066400000000000000000000074161400201773500220620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2017-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import time from gvmtools.helper import error_and_exit def check_args(args): len_args = len(args.script) - 1 if len_args != 2: message = """ This script will update target hosts information for a desired task. Two parameters after the script name are required. 1. -- .csv file containing desired target hosts separated by ',' 2. -- uuid of task to be modified Example for starting up the routine: $ gvm-script --gmp-username name --gmp-password pass \ ssh --hostname scripts/update-task-target.gmp.py hosts_file.csv \ "303fa0a6-aa9b-43c4-bac0-66ae0b2d1698" """ print(message) sys.exit() def load_host_file(filename): host_list = list() try: f = open(filename) for line in f: host = line.split(",")[0] host = host.strip() if len(host) == 0: continue host_list.append(host) except IOError as e: error_and_exit("Failed to read host_file: {} (exit)".format(str(e))) if len(host_list) == 0: error_and_exit("Host file is empty (exit)") hosts_string = ', '.join(map(str, host_list)) return hosts_string def copy_send_target(gmp, hosts_file, old_target_id): hosts_string = load_host_file(hosts_file) keywords = {'hosts': hosts_string} keywords['comment'] = 'This target was automatically modified: {}'.format( time.strftime("%Y/%m/%d-%H:%M:%S") ) old_target = gmp.get_target(target_id=old_target_id)[0] objects = ('reverse_lookup_only', 'reverse_lookup_unify', 'name') for obj in objects: var = old_target.xpath('{}/text()'.format(obj))[0] if var is '0': var = '' keywords['{}'.format(obj)] = var port_list = {} port_list = old_target.xpath('port_list/@id')[0] keywords['port_list_id'] = port_list keywords['name'] += "_copy" # the name must differ from existing names new_target_id = gmp.create_target(**keywords).xpath('@id')[0] print('\n New target created!\n') print('Target_id: {}'.format(new_target_id)) print('Target_name: {}\n'.format(keywords['name'])) return new_target_id def create_target_hosts(gmp, host_file, task_id, old_target_id): new_target_id = copy_send_target(gmp, host_file, old_target_id) gmp.modify_task(task_id=task_id, target_id=new_target_id) print(' Task successfully modified!\n') def check_to_delete(gmp, target_id): target = gmp.get_target(target_id=target_id)[0] if '0' in target.xpath("in_use/text()"): gmp.delete_target(target_id=target_id) def main(gmp, args): # pylint: disable=undefined-variable check_args(args) hosts_file = args.script[1] task_id = args.script[2] task = gmp.get_task(task_id=task_id)[1] old_target_id = task.xpath('target/@id')[0] create_target_hosts(gmp, hosts_file, task_id, old_target_id) check_to_delete(gmp, old_target_id) if __name__ == '__gmp__': main(gmp, args) gvm-tools-21.1.0/tests/000077500000000000000000000000001400201773500146635ustar00rootroot00000000000000gvm-tools-21.1.0/tests/__init__.py000066400000000000000000000031331400201773500167740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import os class SuppressOutput: def __init__(self, *, suppress_stdout=False, suppress_stderr=False): self.suppress_stdout = suppress_stdout self.suppress_stderr = suppress_stderr self.original_stdout = None self.original_stderr = None def __enter__(self): self.devnull = open(os.devnull, "w") # Suppress streams if self.suppress_stdout: self.original_stdout = sys.stdout sys.stdout = self.devnull if self.suppress_stderr: self.original_stderr = sys.stderr sys.stderr = self.devnull def __exit__(self, *args, **kwargs): # Restore streams if self.suppress_stdout: sys.stdout = self.original_stdout if self.suppress_stderr: sys.stderr = self.original_stderr self.devnull.close() gvm-tools-21.1.0/tests/root_help.snap000066400000000000000000000023371400201773500175460ustar00rootroot00000000000000usage: gvm-test-cli [-h] [-c [CONFIG]] [--log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}]] [--timeout TIMEOUT] [--gmp-username GMP_USERNAME] [--gmp-password GMP_PASSWORD] [-V] CONNECTION_TYPE ... optional arguments: -h, --help show this help message and exit -c [CONFIG], --config [CONFIG] Configuration file path (default: ~/.config/gvm- tools.conf) --log [{DEBUG,INFO,WARNING,ERROR,CRITICAL}] Activate logging (default level: None) --timeout TIMEOUT Response timeout in seconds, or -1 to wait indefinitely (default: 60) --gmp-username GMP_USERNAME Username for GMP service (default: None) --gmp-password GMP_PASSWORD Password for GMP service (default: None) -V, --version Show version information and exit connections: valid connection types CONNECTION_TYPE Connection type to use ssh Use SSH to connect to service tls Use TLS secured connection to connect to service socket Use UNIX Domain socket to connect to service gvm-tools-21.1.0/tests/scripts/000077500000000000000000000000001400201773500163525ustar00rootroot00000000000000gvm-tools-21.1.0/tests/scripts/__init__.py000066400000000000000000000041011400201773500204570ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from unittest.mock import patch, MagicMock, create_autospec from typing import Union from pathlib import Path from importlib.util import spec_from_file_location, module_from_spec from lxml import etree from gvm.errors import GvmResponseError from gvm.protocols.latest import Gmp def load_script(path: Union[str, Path], script_name: str): """loading a script for a test case""" spec = spec_from_file_location( script_name, '{}/{}.gmp.py'.format(str(path), script_name) ) script = module_from_spec(spec) spec.loader.exec_module(script) return script class GmpMockFactory: def __init__(self, *args, **kwargs): # pylint: disable=unused-argument gmp_protocol_mock = create_autospec(Gmp) self.gmp_protocol = gmp_protocol_mock self.gmp = MagicMock() self.gmp.is_authenticated = MagicMock(return_value=True) self.gmp.__enter__.return_value = gmp_protocol_mock def __call__(self, *args, **kwargs): return self.gmp def mock_response(self, request_name: str, content: str): func = getattr(self.gmp_protocol, request_name) func.return_value = etree.fromstring(content) def mock_responses(self, request_name: str, content: str): func = getattr(self.gmp_protocol, request_name) func.side_effect = [etree.fromstring(c) for c in content] gvm-tools-21.1.0/tests/scripts/example_schedules.xml000066400000000000000000000154041400201773500225720ustar00rootroot00000000000000 jloechte 2020-08-23T08:51:15Z 2020-09-29T22:12:27Z 1 1 Everything BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Greenbone.net//NONSGML Greenbone Security Manager 20.08.0//EN BEGIN:VEVENT DTSTART:20200826T094100Z DURATION:PT0S RRULE:FREQ=DAILY UID:7ae6ad13-1e5f-4581-ac95-f1c25c59d602 DTSTAMP:20200929T221226Z END:VEVENT END:VCALENDAR UTC jloechte Another Testzone Zone Testing ... 2020-09-27T06:45:25Z 2020-09-27T06:45:25Z 1 0 Everything BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Greenbone.net//NONSGML Greenbone Security Manager 20.08.0//EN BEGIN:VTIMEZONE TZID:/freeassociation.sourceforge.net/Europe/Berlin X-LIC-LOCATION:Europe/Berlin BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19160426T230000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19160430T220000Z;BYDAY=-1SU;BYMONTH=4 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19161004T010000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19160930T230000Z;BYDAY=1SU;BYMONTH=10 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19170420T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19180415T010000Z;BYDAY=3MO;BYMONTH=4 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19170921T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19180916T010000Z;BYDAY=3MO;BYMONTH=9 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19400406T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19400401T010000Z;BYDAY=1MO;BYMONTH=4 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19421102T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19421102T010000Z;BYDAY=1MO;BYMONTH=11 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19430330T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19430329T010000Z;BYDAY=-1MO;BYMONTH=3 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19431005T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19441002T010000Z;BYDAY=1MO;BYMONTH=10 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19440406T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19450402T000000Z;BYDAY=1MO;BYMONTH=4 END:DAYLIGHT BEGIN:DAYLIGHT TZNAME:CEMT DTSTART:19450521T020000 TZOFFSETFROM:+0200 TZOFFSETTO:+0300 RRULE:FREQ=YEARLY;UNTIL=19450523T230000Z;BYDAY=-2TH;BYMONTH=5 END:DAYLIGHT BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19450928T030000 TZOFFSETFROM:+0300 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19450924T020000Z;BYDAY=-1MO;BYMONTH=9 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19451115T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19451118T020000Z;BYDAY=3SU;BYMONTH=11 END:STANDARD BEGIN:STANDARD TZNAME:CET DTSTART:19460107T000000 TZOFFSETFROM:+0100 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19451231T220000Z;BYDAY=1TU;BYMONTH=1 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19460412T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19460414T010000Z;BYDAY=2SU;BYMONTH=4 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19461005T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19461007T010000Z;BYDAY=1MO;BYMONTH=10 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19470405T030000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19470406T010000Z;BYDAY=1SU;BYMONTH=4 END:DAYLIGHT BEGIN:DAYLIGHT TZNAME:CEMT DTSTART:19470510T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0300 RRULE:FREQ=YEARLY;UNTIL=19470511T000000Z;BYDAY=2SU;BYMONTH=5 END:DAYLIGHT BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19470628T030000 TZOFFSETFROM:+0300 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19470629T020000Z;BYDAY=-1SU;BYMONTH=6 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19471004T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19491002T020000Z;BYDAY=1SU;BYMONTH=10 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19480419T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19480418T010000Z;BYDAY=3SU;BYMONTH=4 END:DAYLIGHT BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19490412T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19490410T010000Z;BYDAY=2SU;BYMONTH=4 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19800107T000000 TZOFFSETFROM:+0100 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19791231T220000Z;BYDAY=1TU;BYMONTH=1 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19800405T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;UNTIL=19800406T010000Z;BYDAY=1SU;BYMONTH=4 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19800927T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;UNTIL=19950924T010000Z;BYDAY=-1SU;BYMONTH=9 END:STANDARD BEGIN:DAYLIGHT TZNAME:CEST DTSTART:19810329T020000 TZOFFSETFROM:+0100 TZOFFSETTO:+0200 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3 END:DAYLIGHT BEGIN:STANDARD TZNAME:CET DTSTART:19961025T030000 TZOFFSETFROM:+0200 TZOFFSETTO:+0100 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 END:STANDARD END:VTIMEZONE BEGIN:VEVENT DTSTART;TZID=/freeassociation.sourceforge.net/Europe/Berlin: 20200927T090000 DURATION:PT0S RRULE:FREQ=DAILY UID:5aae8a71-b0e8-43b2-91da-01961dcf9c4f DTSTAMP:20200927T084524Z END:VEVENT END:VCALENDAR Europe/Berlin rows=2 first=1 sort=name rows = 2 first = 1 sort = name nameascending 33 2 gvm-tools-21.1.0/tests/scripts/example_target.xml000066400000000000000000000220531400201773500220770ustar00rootroot00000000000000 jloechte Unnamed 2020-09-30T05:16:36Z 2020-09-30T10:33:21Z 1 0 Everything 123.0.1.123 1 All IANA assigned TCP 0 Unnamed 22 0 0 0 0 0 0 Scan Config Default T:1-3,5,7,9,11,13,17-25,27,29,31,33,35,37-39,41-46,48-50,52-59,62-80,82-99,101-113,115-224,242-248,256-257,259-269,271,280-284,286-287,308-324,333,344-584,586-658,660-702,704-707,709-715,729-731,741-742,744,747-754,758-765,767,769-777,780,800-802,810,828-833,847-848,853-854,860-862,873,886-888,900-903,910-913,953,989-993,995-1001,1010,1021-1022,1025-1026,1029,1033-1108,1110-1275,1277-1300,1303-1490,1492-1527,1529-1782,1784-2193,2197-2199,2201-2258,2260-2368,2370-2377,2379-2681,2683-2692,2694-2793,2795-2824,2826-2872,2874-2924,2926-3091,3093-3096,3098-3125,3127-3300,3302-3321,3326-3366,3372-3402,3405-3545,3547-3693,3695-3993,3995-4047,4049-4076,4078-4083,4085,4087-4143,4145-4172,4174-4190,4192-4193,4197,4199,4300-4314,4316,4320-4323,4325-4336,4340,4343-4360,4368-4379,4389-4393,4395-4396,4400-4411,4413-4417,4419-4423,4425-4433,4442-4458,4484-4488,4500,4535-4538,4545-4556,4559,4563,4566-4570,4573,4590-4591,4593-4605,4646,4658-4692,4700-4704,4711,4725,4727-4728,4730-4731,4733,4737-4745,4749-4753,4756,4774,4784,4786-4788,4800-4803,4827,4837-4851,4867-4871,4876-4877,4879-4880,4883-4885,4888-4889,4894,4899-4902,4912-4915,4940-4942,4949-4953,4969-4971,4984-4991,4999-5013,5015,5020-5030,5032-5034,5042-5045,5048-5057,5059-5075,5080-5087,5093-5094,5099-5103,5106-5107,5111-5112,5114-5115,5117,5120,5133-5135,5137,5145-5146,5150-5152,5154-5157,5161-5168,5172,5190-5197,5200-5203,5209,5215,5221-5237,5245,5248-5254,5264-5265,5269-5272,5280-5282,5298-5310,5312-5318,5320-5321,5343-5344,5349,5352-5363,5397-5435,5443,5445,5450,5453-5456,5461-5465,5470-5473,5475,5500-5507,5550,5553-5557,5565-5569,5573-5575,5579-5586,5597-5605,5618,5627-5639,5646,5666,5670-5681,5683-5684,5688-5689,5693,5696,5700,5705,5713-5730,5741-5748,5750,5755,5757,5766-5771,5777,5780-5783,5785,5793,5813-5814,5841-5842,5859,5863,5868,5883,5900,5910-5913,5963,5968-5969,5984-5993,5999,6064-6066,6068-6077,6084-6088,6099-6117,6121-6124,6130,6133,6140-6149,6159-6163,6200,6209,6222,6241-6244,6251-6253,6267-6269,6300-6301,6306,6315-6317,6320-6322,6324-6326,6343-6344,6346-6347,6350,6355,6360,6370,6379,6382,6389-6390,6417-6421,6432,6440,6442-6446,6455-6456,6464,6471,6480-6489,6500-6503,6505-6510,6513-6515,6543-6544,6547-6551,6558,6566,6568,6579-6583,6600-6602,6619-6629,6632,6640,6653,6655-6656,6670-6673,6678-6679,6687-6690,6697,6701-6703,6714-6716,6767-6771,6777-6778,6785-6791,6801,6817,6831,6841-6842,6850,6868,6888,6900-6901,6924,6935-6936,6946,6951,6961-6966,6969-6970,6997-7026,7030-7031,7070-7073,7080,7099-7101,7117,7121,7128-7129,7161-7174,7200-7202,7215-7216,7227-7229,7236-7237,7244,7262,7272-7283,7365,7391-7395,7397,7400-7402,7410-7411,7421,7426-7431,7437,7443,7471,7473-7474,7478,7491,7500-7501,7508-7511,7542-7549,7551,7560,7563,7566,7569-7570,7574,7588,7606,7624,7626-7631,7633,7648,7663,7672-7677,7680,7683,7687,7689,7697,7700,7707-7708,7720,7724-7728,7734,7738,7741-7744,7747,7775,7777-7779,7781,7786-7787,7789,7794,7797-7801,7810,7845-7847,7869-7871,7878,7880,7887,7900-7903,7913,7932-7933,7962,7967,7979-7982,7997,7999-8009,8015-8016,8019-8023,8025-8026,8032-8034,8040-8044,8051-8059,8066-8067,8070,8074,8077,8080-8084,8086-8088,8090-8091,8097,8100-8102,8115-8118,8121-8122,8128-8132,8140,8148,8153,8160-8162,8181-8184,8190-8192,8194-8195,8199-8201,8204-8208,8230,8243,8270,8276,8280,8282,8292-8294,8300-8301,8313,8320-8322,8351,8376-8380,8383,8400-8405,8415-8417,8423,8442-8445,8450,8457,8470-8474,8500-8502,8554-8555,8567,8600,8610-8615,8665-8666,8675,8686,8688,8699,8710-8711,8733,8750,8763-8770,8778,8786-8787,8793,8800,8804,8873,8880-8881,8883,8888-8894,8899-8901,8910-8913,8937,8953-8954,8980,8989-8991,8997-9002,9005,9008-9010,9020-9026,9050-9051,9060,9080,9083-9093,9100-9107,9111,9119,9122-9123,9131,9160-9164,9191,9200-9217,9222,9255,9278-9285,9287,9292-9295,9300,9306,9310,9312,9318,9321,9339,9343-9346,9374,9380,9387-9390,9396-9397,9400-9402,9418,9443-9445,9450,9500,9535-9536,9555,9592-9600,9612,9614,9616-9618,9628-9631,9640,9666-9668,9694-9695,9700,9747,9750,9753,9762,9800-9802,9875-9877,9888-9889,9898,9900,9909,9911,9925,9950-9955,9966,9978-9979,9981,9987-9988,9990-10010,10020,10050-10051,10055,10080-10081,10100-10104,10107,10110,10113-10117,10125,10128-10129,10160-10162,10200-10201,10252,10260-10261,10288,10321,10443,10540-10544,10548,10631,10800,10805,10809,10860,10880,10933,10990,11000-11001,11095,11103-11106,11109-11112,11161-11165,11172-11175,11201-11202,11208,11211,11319-11321,11367,11371,11489,11600,11623,11720,11723,11751,11796,11876,11967,11971,12000-12008,12010,12012-12013,12109,12121,12168,12172,12300,12302,12321-12322,12345,12753,12865,13160,13216-13218,13223-13224,13400,13720-13722,13724,13782-13783,13785-13786,13818-13823,13894,13929-13930,14000-14001,14033-14034,14141-14143,14145,14149-14150,14154,14250,14414,14500,14936-14937,15000,15002,15345,15363,15555,15660,15740,15999-16002,16020-16021,16161-16162,16309-16311,16360-16361,16367-16368,16384-16385,16619,16665,16789,16900,16950,16991-16995,17007,17184-17185,17219-17221,17223,17225,17234-17235,17500,17555,17729,17754-17756,17777,18000,18104,18136,18181-18187,18241-18243,18262,18463,18634-18635,18668,18769,18881,18888,19000,19007,19020,19191,19194,19220,19283,19315,19398,19410-19412,19539-19541,19998-20003,20005,20013-20014,20034,20046,20048-20049,20057,20167,20202,20222,20480,20670,20999-21000,21010,21212-21213,21221,21553-21554,21590,21800,21845-21849,22000-22005,22125,22128,22222,22273,22305,22335,22343,22347,22350-22351,22537,22555,22763,22800,22951,23000-23005,23053,23294,23333,23400-23402,23456-23457,23546,24000-24006,24242,24249,24321,24323,24386,24465,24554,24577,24666,24676-24678,24680,24754,24922,25000-25009,25576,25604,25793,25900-25903,26000,26133,26208,26257,26260-26263,26486-26487,26489,27010,27017,27345,27442,27504,27782,27876,27999-28001,28010,28200,28240,28589,29167,29999-30003,30100,30260,30400,30999,31016,31020,31400,31416,31457,31620,31685,31765,31948-31949,32034,32249,32400,32483,32635-32636,32767-32777,32801,32811,32896,33000,33060,33123,33331,33333-33334,33434,33656,34249,34378-34379,34567,34962-34964,34980,35000-35006,35100,35354-35357,36001,36524,36602,36700,36865,37475,37483,37601,37654,38000-38002,38201-38203,38800,38865,39681,40000,40404,40841-40843,41111,41121,41230,41794-41797,42508-42510,43000,43188-43191,43210,43439-43441,44123,44321-44323,44444-44445,44553,44818,44900,45000-45002,45045,45054,45514,45678,45824-45825,45966,46336,46998-47001,47557,47624,47806,47808,48000-48005,48048-48050,48128-48129,48556,48619,48653,49000-49001,49150 first=1 rows=-1 uuid= uuid=f362f2cb-c218-4e8b-8ae8-dc818edcb0b8 sort=name first = 1 rows = -1 uuid = uuid = f362f2cb-c218-4e8b-8ae8-dc818edcb0b8 sort = name nameascending 51 1 gvm-tools-21.1.0/tests/scripts/example_task.xml000066400000000000000000000117651400201773500215630ustar00rootroot00000000000000 0 jloechte sgdfg 2020-11-02T10:18:51Z 2020-11-02T10:18:58Z 1 1 Everything 0 scan -1 0 Target for waitress 0 CVE 3 0 Running 0 10 0 1 2020-11-02T10:18:58Z 2020-11-02T10:18:58Z 0 0 Maximum concurrently executed NVTs per host max_checks 4 Maximum concurrently scanned hosts max_hosts 20 Network Source Interface source_iface Add results to Asset Management in_assets no Apply Overrides when adding Assets assets_apply_overrides yes Min QOD when adding Assets assets_min_qod 70 Auto Delete Reports auto_delete no Auto Delete Reports Data auto_delete_data 5 apply_overrides=0 min_qod=70 first=1 rows=-1 uuid= uuid=c8ef0597-e2c1-4e23-869f-072fa2914bf2 sort=name apply_overrides = 0 min_qod = 70 first = 1 rows = -1 uuid = uuid = c8ef0597-e2c1-4e23-869f-072fa2914bf2 sort = name nameascending 101 1 gvm-tools-21.1.0/tests/scripts/get_alerts.xml000066400000000000000000000041441400201773500212300ustar00rootroot00000000000000 jloechte test_alert 2021-01-03T13:45:20Z 2021-01-03T13:45:20Z 1 0 Everything Always Task run status changedstatusDone EmailTask '$n': $e After the event $e, the following condition was met: $c This email escalation is configured to attach report format '$r'. Full details and other report formats are available on the scan engine. $t Note: This email was sent to you as a configured security scan escalation. Please contact your local system administrator if you think you should not have received it. message2noticesender@test.comfrom_address[OpenVAS-Manager] Tasksubjectc402cc3e-b531-11e1-9163-406186ea4fc5notice_attach_formatrecipient@test.comto_address 1 name=test_alert first=1 rows=100 sort=name name = test_alert first = 1 rows = 100 sort = name nameascending 1311 gvm-tools-21.1.0/tests/scripts/get_configs.xml000066400000000000000000000070241400201773500213660ustar00rootroot00000000000000 Base Basic configuration template with a minimum set of NVTs required for a scan. Version 20200827. 2020-02-26T23:52:51Z 2020-12-02T04:09:50Z Discovery Network Discovery scan configuration. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:55Z empty Empty and static configuration template. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:56Z EulerOS Linux Security Configuration Check compliance status of EulerOS installation against above named Policy as distributed by Huawei. Version 20200910. 2020-09-28T09:50:58Z 2020-12-02T04:09:59Z Full and fast Most NVT's; optimized by using previously collected information. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:55Z Full and fast ultimate Most NVT's including those that can stop services/hosts; optimized by using previously collected information. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:50Z Full and very deep Most NVT's; don't trust previously collected information; slow. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:56Z Full and very deep ultimate Most NVT's including those that can stop services/hosts; don't trust previously collected information; slow. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:56Z Host Discovery Network Host Discovery scan configuration. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:56Z System Discovery Network System Discovery scan configuration. Version 20200827. 2019-09-05T12:25:40Z 2020-12-02T04:09:55Z gvm-tools-21.1.0/tests/scripts/invalid_xml.xml000066400000000000000000000003101400201773500213740ustar00rootroot00000000000000 jloechte gvm-tools-21.1.0/tests/scripts/test_combine_reports.py000066400000000000000000000163701400201773500231640ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import unittest from unittest.mock import patch from pathlib import Path from argparse import Namespace from lxml import etree from . import GmpMockFactory, load_script CWD = Path(__file__).absolute().parent class CombineReportsTestCase(unittest.TestCase): def setUp(self): self.combine_reports = load_script( (CWD.parent.parent / 'scripts'), 'combine-reports' ) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_combine_reports(self, mock_gmp: GmpMockFactory): # bah! mock_gmp.mock_responses( 'get_report', [ '' '' '2020-11-13T14:47:28Z' '2020-11-13T14:47:28Z' '2020-11-13T14:47:28Z' '' 'Offline Scan from 2020-11-13T15:47:28+01:00 8' '' '' 'Done' '2020-11-13T14:47:48Z' '2020-11-13T14:47:28Z' '' '' '' '' '' '' '2020-11-13T14:47:28Z' '' '' '', '' '' '2020-11-13T14:47:28Z' '2020-11-13T14:47:28Z' '2020-11-13T14:47:28Z' '' 'Offline Scan from 2020-11-13T15:47:28+01:00 8' '' '' 'Done' '2020-11-13T14:47:48Z' '2020-11-13T14:47:28Z' '' '' '' '' '' '' '2020-11-13T14:47:28Z' '' '' '', '' '' '2020-11-13T14:47:28Z' '2020-11-13T14:47:28Z' '2020-11-13T14:47:28Z' '' 'Offline Scan from 2020-11-13T15:47:28+01:00 8' '' '' 'Done' '2020-11-13T14:47:48Z' '2020-11-13T14:47:28Z' '' '' '' '' '2020-11-13T14:47:28Z' '' '' '', ], ) args = Namespace( script=[ 'foo', '00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000002', ] ) combined_report = self.combine_reports.combine_reports( gmp=mock_gmp.gmp_protocol, args=args ) results = ( combined_report.find('report').find('results').findall('result') ) i = 0 for result in results: self.assertEqual( result.get('id'), f'00000001-0000-0000-0000-00000000000{str(i)}' ) i += 1 self.assertEqual(i, 5) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_send_report(self, mock_gmp: GmpMockFactory): args = Namespace( script=[ 'foo', '00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000002', ] ) combined_report = etree.fromstring( '' '' '' '' '' '' '' '' '' ) report_id = '0e4d8fb2-47fa-494e-a242-d5327d3772f9' mock_gmp.mock_response( 'import_report', '', ) mock_gmp.mock_response( 'create_container_task', '', ) created_report_id = self.combine_reports.send_report( gmp=mock_gmp.gmp_protocol, args=args, combined_report=combined_report, ) self.assertEqual(report_id, created_report_id) gvm-tools-21.1.0/tests/scripts/test_send_schedules.py000066400000000000000000000043061400201773500227560ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see import unittest from unittest.mock import patch from pathlib import Path from argparse import Namespace from lxml import etree from . import GmpMockFactory, load_script CWD = Path(__file__).absolute().parent class SendSchedulesTestCase(unittest.TestCase): def setUp(self): self.send_schedules = load_script( (CWD.parent.parent / 'scripts'), 'send-schedules' ) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_sent_schedule(self, mock_gmp: GmpMockFactory): schedule_xml_path = CWD / 'example_schedules.xml' schedule_xml_str = schedule_xml_path.read_text() mock_gmp.mock_responses( 'create_schedule', [ '', '', ], ) schedule = etree.XML(schedule_xml_str) self.send_schedules.parse_send_xml_tree(mock_gmp.gmp_protocol, schedule) def test_args(self): args = Namespace(script=['foo']) with self.assertRaises(SystemExit): self.send_schedules.check_args(args) args2 = Namespace(script=['foo', 'bar', 'baz']) with self.assertRaises(SystemExit): self.send_schedules.check_args(args2) gvm-tools-21.1.0/tests/scripts/test_send_targets.py000066400000000000000000000071211400201773500224460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import unittest from unittest.mock import patch from pathlib import Path from argparse import Namespace from lxml import etree from . import GmpMockFactory, load_script CWD = Path(__file__).absolute().parent class SendTargetTestCase(unittest.TestCase): def setUp(self): self.send_targets = load_script( (CWD.parent.parent / 'scripts'), 'send-targets' ) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_sent_target(self, mock_gmp: GmpMockFactory): target_xml_path = CWD / 'example_target.xml' target_xml_str = target_xml_path.read_text() mock_gmp.mock_response( 'get_credentials', '' '' '' '' '' '' '' '' '' '', ) mock_gmp.mock_response( 'create_target', '', ) target = etree.XML(target_xml_str) self.send_targets.parse_send_xml_tree(mock_gmp.gmp_protocol, target) @patch('builtins.input', lambda *args: 'n') @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_sent_target_no_credential(self, mock_gmp: GmpMockFactory): target_xml_path = CWD / 'example_target.xml' target_xml_str = target_xml_path.read_text() mock_gmp.mock_response( 'get_credentials', '' '' '' '' '' '', ) mock_gmp.mock_response( 'create_target', '', ) target = etree.XML(target_xml_str) with self.assertRaises(SystemExit): self.send_targets.parse_send_xml_tree(mock_gmp.gmp_protocol, target) def test_args(self): args = Namespace(script=['foo']) with self.assertRaises(SystemExit): self.send_targets.check_args(args) args2 = Namespace(script=['foo', 'bar', 'baz']) with self.assertRaises(SystemExit): self.send_targets.check_args(args2) gvm-tools-21.1.0/tests/scripts/test_send_tasks.py000066400000000000000000000064371400201773500221330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see import unittest from unittest.mock import patch, MagicMock from pathlib import Path from lxml import etree from . import GmpMockFactory, load_script CWD = Path(__file__).absolute().parent class SendTasksTestCase(unittest.TestCase): def setUp(self): self.send_tasks = load_script( (CWD.parent.parent / 'scripts'), 'send-tasks' ) @patch('builtins.input', lambda *args: 'y') @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_sent_task(self, mock_gmp: GmpMockFactory): task_xml_path = CWD / 'example_task.xml' task_xml_str = task_xml_path.read_text() self.send_tasks.numerical_option = MagicMock(return_value=1) configs_file = CWD / 'get_configs.xml' configs = configs_file.read_text() mock_gmp.mock_response('get_configs', configs) mock_gmp.mock_response( 'get_scanners', '' '' 'as' '' '' 'CVE' '' '' 'OpenVAS Default' '' '', ) mock_gmp.mock_response( 'get_targets', '' '' 'own' '' '' 'Target for xn' '' '' 'Unnamed' '' '' 'work' '' '' 'work2' '' '', ) mock_gmp.mock_response( 'create_task', '', ) task = etree.XML(task_xml_str) tasks = self.send_tasks.parse_send_xml_tree(mock_gmp.gmp_protocol, task) self.assertEqual(tasks, ['c8ef0597-e2c1-4e23-869f-072fa2914bf2']) gvm-tools-21.1.0/tests/scripts/test_start_alert_scan.py000066400000000000000000000155671400201773500233310ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see import unittest from unittest.mock import patch from pathlib import Path from . import GmpMockFactory, load_script CWD = Path(__file__).absolute().parent class StartAlertScanTestCase(unittest.TestCase): def setUp(self): self.start_alert_scan = load_script( (CWD.parent.parent / 'scripts'), 'start-alert-scan' ) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_get_config(self, mock_gmp: GmpMockFactory): configs_file = CWD / 'get_configs.xml' configs = configs_file.read_text() mock_gmp.mock_response('get_configs', configs) # Full and Fast config_id = self.start_alert_scan.get_config( gmp=mock_gmp.gmp_protocol, config=0 ) self.assertEqual(config_id, 'daba56c8-73ec-11df-a475-002264764cea') # Full and Fast ultimate config_id = self.start_alert_scan.get_config( gmp=mock_gmp.gmp_protocol, config=1 ) self.assertEqual(config_id, '698f691e-7489-11df-9d8c-002264764cea') # Full and Fast deep config_id = self.start_alert_scan.get_config( gmp=mock_gmp.gmp_protocol, config=2 ) self.assertEqual(config_id, '708f25c4-7489-11df-8094-002264764cea') # Full and Fast deep ultimate config_id = self.start_alert_scan.get_config( gmp=mock_gmp.gmp_protocol, config=3 ) self.assertEqual(config_id, '74db13d6-7489-11df-91b9-002264764cea') # System Discovery config_id = self.start_alert_scan.get_config( gmp=mock_gmp.gmp_protocol, config=4 ) self.assertEqual(config_id, 'bbca7412-a950-11e3-9109-406186ea4fc5') with self.assertRaises(ValueError): config_id = self.start_alert_scan.get_config( gmp=mock_gmp.gmp_protocol, config=-1 ) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_get_alert(self, mock_gmp: GmpMockFactory): sender_email = "sender@test.com" recipient_email = "recipient@test.com" alert_name = "test_alert" alert_id = '3eefd4b9-59ec-48d6-b84d-f6a73bdb909f' alerts_file = CWD / 'get_alerts.xml' alerts = alerts_file.read_text() mock_gmp.mock_response('get_alerts', alerts) mock_gmp.mock_response( 'create_alert', '', ) returned_id = self.start_alert_scan.get_alert( gmp=mock_gmp.gmp_protocol, alert_name=alert_name, recipient_email=recipient_email, sender_email=sender_email, ) self.assertEqual(alert_id, returned_id) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_get_target(self, mock_gmp: GmpMockFactory): target_name = "test_target" hosts = ['127.0.0.1', '8.8.8.8'] ports = 'T:1-3,5,7,9,11,13,17-25' port_list_name = "test_port_list" port_list_id = '6742e61a-a7b0-45dd-a8e1-35751c970958' target_id = '3b76a0c2-14fc-4de2-868c-35132977a25e' mock_gmp.mock_response( 'create_port_list', '', ) mock_gmp.mock_response( 'create_target', '', ) returned_id = self.start_alert_scan.get_target( gmp=mock_gmp.gmp_protocol, target_name=target_name, hosts=hosts, ports=ports, port_list_name=port_list_name, ) self.assertEqual(target_id, returned_id) @patch('gvm.protocols.latest.Gmp', new_callable=GmpMockFactory) def test_create_and_start_task(self, mock_gmp: GmpMockFactory): alert_name = 'test_alert' alert_id = '3eefd4b9-59ec-48d6-b84d-f6a73bdb909f' target_id = '3b76a0c2-14fc-4de2-868c-35132977a25e' config_id = 'daba56c8-73ec-11df-a475-002264764cea' scanner_id = '08b69003-5fc2-4037-a479-93b440211c73' task_id = 'd78453ab-d907-44b6-abe0-2ef54a77f1c2' mock_gmp.mock_response( 'create_task', '', ) mock_gmp.mock_response( 'get_tasks', """ 0 apply_overrides=0 min_qod=70 name="Alert Scan for Alert test_alert" first=1 rows=100 sort=name apply_overrides = 0 min_qod = 70 name = "Alert Scan for Alert test_alert" first = 1 rows = 100 sort = name nameascending 2700 """, ) task_name = "Alert Scan for Alert {}".format(alert_name) returned_name = self.start_alert_scan.create_and_start_task( gmp=mock_gmp.gmp_protocol, config_id=config_id, target_id=target_id, scanner_id=scanner_id, alert_id=alert_id, alert_name=alert_name, ) self.assertEqual(task_name, returned_name) gvm-tools-21.1.0/tests/socket_help.snap000066400000000000000000000005641400201773500200530ustar00rootroot00000000000000usage: gvm-test-cli socket [-h] [--sockpath [SOCKETPATH] | --socketpath [SOCKETPATH]] optional arguments: -h, --help show this help message and exit --sockpath [SOCKETPATH] Deprecated, use --socketpath instead --socketpath [SOCKETPATH] Path to UNIX Domain socket (default: None) gvm-tools-21.1.0/tests/ssh_help.snap000066400000000000000000000010251400201773500173510ustar00rootroot00000000000000usage: gvm-test-cli ssh [-h] [--hostname HOSTNAME] [--port PORT] [--ssh-username SSH_USERNAME] [--ssh-password SSH_PASSWORD] optional arguments: -h, --help show this help message and exit --hostname HOSTNAME Hostname or IP address (default: 127.0.0.1) --port PORT SSH port (default: 22) --ssh-username SSH_USERNAME SSH username (default: 'gmp') --ssh-password SSH_PASSWORD SSH password (default: 'gmp') gvm-tools-21.1.0/tests/test.cfg000066400000000000000000000003261400201773500163240ustar00rootroot00000000000000[main] foo=bar timeout=1000 username=ipsum [gmp] username=%(foo)s password=bar [unixsocket] socketpath=/foo/bar.sock [ssh] password=lorem port=123 [tls] port=123 certfile=foo.cert keyfile=foo.key cafile=foo.ca gvm-tools-21.1.0/tests/test_auth.cfg000066400000000000000000000000511400201773500173400ustar00rootroot00000000000000[Auth] gmp_username=foo gmp_password=bar gvm-tools-21.1.0/tests/test_config.py000066400000000000000000000065421400201773500175500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import logging import unittest from pathlib import Path from gvm.connections import DEFAULT_UNIX_SOCKET_PATH, DEFAULT_GVM_PORT from gvmtools.config import Config, DEFAULT_SSH_PORT, __name__ as name __here__ = Path(__file__).parent.resolve() class ConfigTestCase(unittest.TestCase): def test_config_defaults(self): config = Config() self.assertEqual(config.get('gmp', 'username'), '') self.assertEqual(config.get('gmp', 'password'), '') self.assertEqual(config.get('ssh', 'username'), 'gmp') self.assertEqual(config.get('ssh', 'password'), 'gmp') self.assertEqual(config.get('ssh', 'port'), DEFAULT_SSH_PORT) self.assertEqual( config.get('unixsocket', 'socketpath'), DEFAULT_UNIX_SOCKET_PATH ) self.assertEqual(config.get('tls', 'port'), DEFAULT_GVM_PORT) def test_get_unknown_setting(self): config = Config() self.assertIsNone(config.get('foo', 'bar')) def test_load(self): test_config_path = __here__ / 'test.cfg' self.assertTrue(test_config_path.is_file()) config = Config() config.load(test_config_path) self.assertEqual(config.get('gmp', 'username'), 'bar') self.assertEqual(config.get('gmp', 'password'), 'bar') self.assertEqual(config.get('ssh', 'username'), 'ipsum') self.assertEqual(config.get('ssh', 'password'), 'lorem') self.assertEqual(config.get('ssh', 'port'), '123') self.assertEqual( config.get('unixsocket', 'socketpath'), '/foo/bar.sock' ) self.assertEqual(config.get('tls', 'port'), '123') self.assertEqual(config.get('tls', 'certfile'), 'foo.cert') self.assertEqual(config.get('tls', 'keyfile'), 'foo.key') self.assertEqual(config.get('tls', 'cafile'), 'foo.ca') self.assertDictEqual( config.defaults(), dict(timeout='1000', foo='bar', username='ipsum') ) def test_load_auth(self): root = logging.getLogger(name) root.disabled = True test_config_path = __here__ / 'test_auth.cfg' self.assertTrue(test_config_path.is_file()) config = Config() config.load(test_config_path) self.assertEqual(config.get('gmp', 'username'), 'foo') self.assertEqual(config.get('gmp', 'password'), 'bar') root.disabled = False def test_load_with_non_existing_configfile(self): test_config_path = __here__ / 'foo.cfg' self.assertFalse(test_config_path.is_file()) config = Config() with self.assertRaises(FileNotFoundError): config.load(test_config_path) gvm-tools-21.1.0/tests/test_helper.py000066400000000000000000000210341400201773500175530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020-2021 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import uuid import unittest import ipaddress from unittest.mock import patch, MagicMock from io import BytesIO from pathlib import Path from lxml import etree from gvm.errors import GvmError from gvmtools.helper import ( Table, do_not_run_as_root, authenticate, run_script, generate_id, generate_random_ips, generate_uuid, create_xml_tree, error_and_exit, yes_or_no, ) CWD = Path(__file__).absolute().parent class TableTestCase(unittest.TestCase): def setUp(self): self.heading = ['ID', 'Name', 'Severity'] self.rows = [ ['1', 'foobar', 'high'], ['2', 'bla', 'low'], ['3', 'blub', 'medium'], ] self.divider = ' - ' self.table = Table( heading=self.heading, rows=self.rows, divider=self.divider ) def test_generate_uuid(self): random_uuid = generate_uuid() try: uuid.UUID(random_uuid, version=4) except (ValueError, TypeError, AttributeError): self.fail("No valid UUID.") def test_generate_id(self): random_id = generate_id(size=1, chars="a") self.assertEqual(random_id, 'a') random_id = generate_id(size=10) self.assertEqual(len(random_id), 10) self.assertTrue(random_id.isalnum()) def test_generate_random_ips(self): random_ip = generate_random_ips(1) ip_addr = ipaddress.ip_address(random_ip[0]) self.assertEqual(ip_addr.version, 4) self.assertEqual(str(ip_addr), random_ip[0]) num = 10 random_ips = generate_random_ips(num) self.assertEqual(len(random_ips), num) def test_init_no_args(self): table = Table() self.assertListEqual(table.heading, []) self.assertListEqual(table.rows, []) self.assertEqual(table.divider, ' | ') def test_init_with_args(self): self.assertListEqual(self.table.heading, self.heading) self.assertListEqual(self.table.rows, self.rows) self.assertEqual(self.table.divider, self.divider) def test_calculate_dimensions(self): expected_result = [ len(self.heading[0]), len(self.rows[0][1]), len(self.heading[2]), ] column_sizes = ( self.table._calculate_dimensions() # pylint: disable=protected-access ) self.assertEqual(column_sizes, expected_result) def test_create_column(self): column = 'foobar' size = 20 expected = 'foobar ' result = self.table._create_column( # pylint: disable=protected-access column, size ) self.assertEqual(result, expected) def test_create_row(self): columns = ['foo', 'bar', 'blub'] expected = self.divider.join(columns) result = self.table._create_row(columns) # pylint: disable=W0212 self.assertEqual(result, expected) def test_str(self): expected = ( 'ID - Name - Severity\n' + '-- - ------ - --------\n' + '1 - foobar - high \n' + '2 - bla - low \n' + '3 - blub - medium ' ) self.assertEqual(str(self.table), expected) class DoNotRunAsRootTestCase(unittest.TestCase): @patch('gvmtools.helper.os') def test_do_not_run_as_root_as_root(self, mock_os): mock_os.geteuid = MagicMock(spec='geteuid') mock_os.geteuid.return_value = 0 self.assertRaises(RuntimeError, do_not_run_as_root) @patch('gvmtools.helper.os') def test_do_not_run_as_root_as_non_root(self, mock_os): mock_os.geteuid = MagicMock(spec='geteuid') mock_os.geteuid.return_value = 123 self.assertIsNone(do_not_run_as_root()) class AuthenticateTestCase(unittest.TestCase): def test_authenticate_already_authenticated(self): mock_gmp = self.create_gmp_mock(True) self.assertIsNone(authenticate(mock_gmp)) @patch('gvmtools.helper.input', return_value='foo') def test_authenticate_username_is_none( self, mock_input ): # pylint: disable=unused-argument,line-too-long mock_gmp = self.create_gmp_mock(False) return_value = authenticate(mock_gmp, password='bar') self.assertTrue(isinstance(return_value, tuple)) self.assertEqual(return_value[0], 'foo') self.assertEqual(return_value[1], 'bar') @patch('gvmtools.helper.getpass') def test_authenticate_password_is_none(self, mock_getpass): mock_gmp = self.create_gmp_mock(False) mock_getpass.getpass = MagicMock(return_value='SuperSecret123!') return_value = authenticate(mock_gmp, username='user') self.assertTrue(isinstance(return_value, tuple)) self.assertEqual(return_value[0], 'user') self.assertEqual(return_value[1], 'SuperSecret123!') def test_authenticate(self): mock_gmp = self.create_gmp_mock(False) return_value = authenticate( mock_gmp, username='user', password='password' ) self.assertTrue(isinstance(return_value, tuple)) self.assertEqual(return_value[0], 'user') self.assertEqual(return_value[1], 'password') def test_authenticate_bad_credentials(self): mock_gmp = self.create_gmp_mock(False) def my_authenticate(username, password): raise GvmError('foo') mock_gmp.authenticate = my_authenticate self.assertRaises(GvmError, authenticate, mock_gmp, 'user', 'password') def create_gmp_mock(self, authenticated_return_value): mock_gmp = MagicMock() mock_gmp.is_authenticated = MagicMock( return_value=authenticated_return_value ) return mock_gmp class RunScriptTestCase(unittest.TestCase): @patch('gvmtools.helper.open') @patch('gvmtools.helper.exec') def test_run_script(self, mock_exec, mock_open): path = 'foo' global_vars = ['OpenVAS', 'is', 'awesome'] mock_open().read.return_value = 'file content' run_script(path, global_vars) mock_open.assert_called_with(path, 'r', newline='') mock_exec.assert_called_with('file content', global_vars) @patch('gvmtools.helper.open') @patch('gvmtools.helper.print') def test_run_script_file_not_found(self, mock_print, mock_open): def my_open(path, mode, newline): raise FileNotFoundError mock_open.side_effect = my_open path = 'foo' global_vars = ['OpenVAS', 'is', 'awesome'] with self.assertRaises(SystemExit): run_script(path, global_vars) mock_print.assert_called_with( 'Script {path} does not exist'.format(path=path), file=sys.stderr ) class ScriptUtilsTestCase(unittest.TestCase): @patch('builtins.input', lambda *args: 'y') def test_yes(self): yes = yes_or_no('foo?') self.assertTrue(yes) @patch('builtins.input', lambda *args: 'n') def test_no(self): no = yes_or_no('bar?') self.assertFalse(no) def test_error_and_exit(self): with self.assertRaises(SystemExit): error_and_exit('foo') def test_create_xml_tree(self): tree = create_xml_tree(BytesIO(b'glurp')) self.assertIsInstance( tree, etree._Element # pylint: disable=protected-access ) self.assertEqual(tree.tag, 'foo') def test_create_xml_tree_invalid_file(self): target_xml_path = CWD / 'invalid_file.xml' with self.assertRaises(SystemExit): with self.assertRaises(OSError): create_xml_tree(str(target_xml_path)) def test_create_xml_tree_invalid_xml(self): with self.assertRaises(SystemExit): with self.assertRaises(etree.Error): create_xml_tree(BytesIO(b'glurp')) gvm-tools-21.1.0/tests/test_parser.py000066400000000000000000000410451400201773500175740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2019 Greenbone Networks GmbH # # SPDX-License-Identifier: GPL-3.0-or-later # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import sys import unittest from unittest.mock import patch from pathlib import Path from argparse import Namespace from gvm.connections import ( DEFAULT_UNIX_SOCKET_PATH, DEFAULT_TIMEOUT, UnixSocketConnection, TLSConnection, SSHConnection, ) from gvmtools.parser import CliParser, create_parser, create_connection from . import SuppressOutput __here__ = Path(__file__).parent.resolve() class ConfigParserTestCase(unittest.TestCase): def setUp(self): self.test_config_path = __here__ / 'test.cfg' self.assertTrue(self.test_config_path.is_file()) self.parser = CliParser('TestParser', 'test.log') def test_socket_defaults_from_config(self): args = self.parser.parse_args( ['--config', str(self.test_config_path), 'socket'] ) self.assertEqual(args.foo, 'bar') self.assertEqual(args.timeout, 1000) self.assertEqual(args.gmp_password, 'bar') self.assertEqual(args.gmp_username, 'bar') self.assertEqual(args.socketpath, '/foo/bar.sock') def test_ssh_defaults_from_config(self): args = self.parser.parse_args( ['--config', str(self.test_config_path), 'ssh', '--hostname', 'foo'] ) self.assertEqual(args.foo, 'bar') self.assertEqual(args.timeout, 1000) self.assertEqual(args.gmp_password, 'bar') self.assertEqual(args.gmp_username, 'bar') self.assertEqual(args.ssh_password, 'lorem') self.assertEqual(args.ssh_username, 'ipsum') self.assertEqual(args.port, 123) def test_tls_defaults_from_config(self): args = self.parser.parse_args( ['--config', str(self.test_config_path), 'tls', '--hostname', 'foo'] ) self.assertEqual(args.foo, 'bar') self.assertEqual(args.timeout, 1000) self.assertEqual(args.gmp_password, 'bar') self.assertEqual(args.gmp_username, 'bar') self.assertEqual(args.certfile, 'foo.cert') self.assertEqual(args.keyfile, 'foo.key') self.assertEqual(args.cafile, 'foo.ca') self.assertEqual(args.port, 123) @patch('gvmtools.parser.logger') @patch('gvmtools.parser.Path') def test_resolve_file_not_found_error(self, path_mock, logger_mock): # Making sure that resolve raises an error def resolve_raises_error(): raise FileNotFoundError() configpath = unittest.mock.MagicMock() configpath.expanduser().resolve = unittest.mock.MagicMock( side_effect=resolve_raises_error ) path_mock.return_value = configpath logger_mock.debug = unittest.mock.MagicMock() args = self.parser.parse_args(['socket']) self.assertIsInstance(args, Namespace) self.assertEqual(args.connection_type, 'socket') self.assertEqual(args.config, '~/.config/gvm-tools.conf') logger_mock.debug.assert_any_call( 'Ignoring non existing config file %s', '~/.config/gvm-tools.conf' ) @patch('gvmtools.parser.Path') @patch('gvmtools.parser.Config') def test_config_load_raises_error(self, config_mock, path_mock): def config_load_error(): raise Exception config = unittest.mock.MagicMock() config.load = unittest.mock.MagicMock(side_effect=config_load_error) config_mock.return_value = config # Making sure that the function thinks the config file exists configpath_exists = unittest.mock.Mock() configpath_exists.expanduser().resolve().exists = ( unittest.mock.MagicMock(return_value=True) ) path_mock.return_value = configpath_exists self.assertRaises(RuntimeError, self.parser.parse_args, ['socket']) class IgnoreConfigParserTestCase(unittest.TestCase): def test_unkown_config_file(self): test_config_path = __here__ / 'foo.cfg' self.assertFalse(test_config_path.is_file()) self.parser = CliParser('TestParser', 'test.log') args = self.parser.parse_args( ['--config', str(test_config_path), 'socket'] ) self.assertEqual(args.timeout, DEFAULT_TIMEOUT) self.assertEqual(args.gmp_password, '') self.assertEqual(args.gmp_username, '') self.assertEqual(args.socketpath, DEFAULT_UNIX_SOCKET_PATH) def test_unkown_config_file_in_unkown_dir(self): test_config_path = __here__ / 'foo' / 'foo.cfg' self.assertFalse(test_config_path.is_file()) self.parser = CliParser('TestParser', 'test.log') args = self.parser.parse_args( ['--config', str(test_config_path), 'socket'] ) self.assertEqual(args.timeout, DEFAULT_TIMEOUT) self.assertEqual(args.gmp_password, '') self.assertEqual(args.gmp_username, '') self.assertEqual(args.socketpath, DEFAULT_UNIX_SOCKET_PATH) class ParserTestCase(unittest.TestCase): def setUp(self): self.parser = CliParser( 'TestParser', 'test.log', ignore_config=True, prog='gvm-test-cli' ) class RootArgumentsParserTest(ParserTestCase): def test_config(self): args = self.parser.parse_args(['--config', 'foo.cfg', 'socket']) self.assertEqual(args.config, 'foo.cfg') def test_defaults(self): args = self.parser.parse_args(['socket']) self.assertEqual(args.config, '~/.config/gvm-tools.conf') self.assertEqual(args.gmp_password, '') self.assertEqual(args.gmp_username, '') self.assertEqual(args.timeout, 60) self.assertIsNone(args.loglevel) def test_loglevel(self): args = self.parser.parse_args(['--log', 'ERROR', 'socket']) self.assertEqual(args.loglevel, 'ERROR') def test_loglevel_after_subparser(self): with SuppressOutput(suppress_stderr=True): with self.assertRaises(SystemExit): self.parser.parse_args(['socket', '--log', 'ERROR']) def test_timeout(self): args = self.parser.parse_args(['--timeout', '1000', 'socket']) self.assertEqual(args.timeout, 1000) def test_timeout_after_subparser(self): with SuppressOutput(suppress_stderr=True): with self.assertRaises(SystemExit): self.parser.parse_args(['socket', '--timeout', '1000']) def test_gmp_username(self): args = self.parser.parse_args(['--gmp-username', 'foo', 'socket']) self.assertEqual(args.gmp_username, 'foo') def test_gmp_username_after_subparser(self): with SuppressOutput(suppress_stderr=True): with self.assertRaises(SystemExit): self.parser.parse_args(['socket', '--gmp-username', 'foo']) def test_gmp_password(self): args = self.parser.parse_args(['--gmp-password', 'foo', 'socket']) self.assertEqual(args.gmp_password, 'foo') def test_gmp_password_after_subparser(self): with SuppressOutput(suppress_stderr=True): with self.assertRaises(SystemExit): self.parser.parse_args(['socket', '--gmp-password', 'foo']) def test_with_unknown_args(self): args, script_args = self.parser.parse_known_args( ['--gmp-password', 'foo', 'socket', '--bar', '--bar2'] ) self.assertEqual(args.gmp_password, 'foo') self.assertEqual(script_args, ['--bar', '--bar2']) @patch('gvmtools.parser.logging') def test_socket_has_no_timeout(self, _logging_mock): # pylint: disable=protected-access args_mock = unittest.mock.MagicMock() args_mock.timeout = -1 self.parser._parser.parse_known_args = unittest.mock.MagicMock( return_value=(args_mock, unittest.mock.MagicMock()) ) args, _ = self.parser.parse_known_args( ['socket', '--timeout', '--', '-1'] ) self.assertIsNone(args.timeout) @patch('gvmtools.parser.logging') @patch('gvmtools.parser.argparse.ArgumentParser.print_usage') @patch('gvmtools.parser.argparse.ArgumentParser._print_message') def test_no_args_provided( self, _logging_mock, _print_usage_mock, _print_message ): # pylint: disable=protected-access self.parser._set_defaults = unittest.mock.MagicMock() self.assertRaises(SystemExit, self.parser.parse_known_args, None) class SocketParserTestCase(ParserTestCase): def test_defaults(self): args = self.parser.parse_args(['socket']) self.assertEqual(args.socketpath, DEFAULT_UNIX_SOCKET_PATH) def test_connection_type(self): args = self.parser.parse_args(['socket']) self.assertEqual(args.connection_type, 'socket') def test_sockpath(self): args = self.parser.parse_args(['socket', '--sockpath', 'foo.sock']) self.assertEqual(args.socketpath, 'foo.sock') def test_socketpath(self): args = self.parser.parse_args(['socket', '--socketpath', 'foo.sock']) self.assertEqual(args.socketpath, 'foo.sock') class SshParserTestCase(ParserTestCase): def test_defaults(self): args = self.parser.parse_args(['ssh', '--hostname=foo']) self.assertEqual(args.port, 22) self.assertEqual(args.ssh_username, 'gmp') self.assertEqual(args.ssh_password, 'gmp') def test_connection_type(self): args = self.parser.parse_args(['ssh', '--hostname=foo']) self.assertEqual(args.connection_type, 'ssh') def test_hostname(self): args = self.parser.parse_args(['ssh', '--hostname', 'foo']) self.assertEqual(args.hostname, 'foo') def test_port(self): args = self.parser.parse_args( ['ssh', '--hostname', 'foo', '--port', '123'] ) self.assertEqual(args.port, 123) def test_ssh_username(self): args = self.parser.parse_args( ['ssh', '--hostname', 'foo', '--ssh-username', 'foo'] ) self.assertEqual(args.ssh_username, 'foo') def test_ssh_password(self): args = self.parser.parse_args( ['ssh', '--hostname', 'foo', '--ssh-password', 'foo'] ) self.assertEqual(args.ssh_password, 'foo') class TlsParserTestCase(ParserTestCase): def test_defaults(self): args = self.parser.parse_args(['tls', '--hostname=foo']) self.assertIsNone(args.certfile) self.assertIsNone(args.keyfile) self.assertIsNone(args.cafile) self.assertEqual(args.port, 9390) def test_connection_type(self): args = self.parser.parse_args(['tls', '--hostname=foo']) self.assertEqual(args.connection_type, 'tls') def test_hostname(self): args = self.parser.parse_args(['tls', '--hostname', 'foo']) self.assertEqual(args.hostname, 'foo') def test_port(self): args = self.parser.parse_args( ['tls', '--hostname', 'foo', '--port', '123'] ) self.assertEqual(args.port, 123) def test_certfile(self): args = self.parser.parse_args( ['tls', '--hostname', 'foo', '--certfile', 'foo.cert'] ) self.assertEqual(args.certfile, 'foo.cert') def test_keyfile(self): args = self.parser.parse_args( ['tls', '--hostname', 'foo', '--keyfile', 'foo.key'] ) self.assertEqual(args.keyfile, 'foo.key') def test_cafile(self): args = self.parser.parse_args( ['tls', '--hostname', 'foo', '--cafile', 'foo.ca'] ) self.assertEqual(args.cafile, 'foo.ca') def test_no_credentials(self): args = self.parser.parse_args( ['tls', '--hostname', 'foo', '--no-credentials'] ) self.assertTrue(args.no_credentials) class CustomizeParserTestCase(ParserTestCase): def test_add_optional_argument(self): self.parser.add_argument('--foo', type=int) args = self.parser.parse_args(['socket', '--foo', '123']) self.assertEqual(args.foo, 123) args = self.parser.parse_args( ['ssh', '--hostname', 'bar', '--foo', '123'] ) self.assertEqual(args.foo, 123) args = self.parser.parse_args( ['tls', '--hostname', 'bar', '--foo', '123'] ) self.assertEqual(args.foo, 123) def test_add_positional_argument(self): self.parser.add_argument('foo', type=int) args = self.parser.parse_args(['socket', '123']) self.assertEqual(args.foo, 123) def test_add_protocol_argument(self): self.parser.add_protocol_argument() args = self.parser.parse_args(['socket']) self.assertEqual(args.protocol, 'GMP') args = self.parser.parse_args(['--protocol', 'OSP', 'socket']) self.assertEqual(args.protocol, 'OSP') class HelpFormattingParserTestCase(ParserTestCase): # pylint: disable=protected-access maxDiff = None python_version = '.'.join([str(i) for i in sys.version_info[:2]]) def setUp(self): super().setUp() # ensure all tests are using the same terminal width self.columns = os.environ.get('COLUMNS') os.environ['COLUMNS'] = '80' def tearDown(self): super().tearDown() if not self.columns: del os.environ['COLUMNS'] else: os.environ['COLUMNS'] = self.columns def _snapshot_specific_path(self, name): return __here__ / '{}.{}.snap'.format(name, self.python_version) def _snapshot_generic_path(self, name): return __here__ / '{}.snap'.format(name) def _snapshot_failed_path(self, name): return __here__ / '{}.{}-failed.snap'.format(name, self.python_version) def _snapshot_path(self, name): snapshot_specific_path = self._snapshot_specific_path(name) if snapshot_specific_path.exists(): return snapshot_specific_path return self._snapshot_generic_path(name) def assert_snapshot(self, name, output): path = self._snapshot_path(name) if not path.exists(): path.write_text(output) content = path.read_text() try: self.assertEqual(content, output, 'Snapshot differs from output') except AssertionError: # write new output to snapshot file # reraise error afterwards path = self._snapshot_failed_path(name) path.write_text(output) raise def test_root_help(self): help_output = self.parser._parser.format_help() self.assert_snapshot('root_help', help_output) def test_socket_help(self): help_output = self.parser._parser_socket.format_help() self.assert_snapshot('socket_help', help_output) def test_ssh_help(self): self.parser._set_defaults(None) help_output = self.parser._parser_ssh.format_help() self.assert_snapshot('ssh_help', help_output) def test_tls_help(self): self.parser._set_defaults(None) help_output = self.parser._parser_tls.format_help() self.assert_snapshot('tls_help', help_output) class CreateParserFunctionTestCase(unittest.TestCase): # pylint: disable=protected-access def test_create_parser(self): description = 'parser description' logfilename = 'logfilename' parser = create_parser(description, logfilename) self.assertIsInstance(parser, CliParser) self.assertEqual(parser._logfilename, logfilename) self.assertEqual(parser._bootstrap_parser.description, description) class CreateConnectionTestCase(unittest.TestCase): def test_create_unix_socket_connection(self): self.perform_create_connection_test() def test_create_tls_connection(self): self.perform_create_connection_test('tls', TLSConnection) def test_create_ssh_connection(self): self.perform_create_connection_test('ssh', SSHConnection, 22) def perform_create_connection_test( self, connection_type='socket', connection_class=UnixSocketConnection, port=None, ): connection = create_connection(connection_type, port=port) self.assertIsInstance(connection, connection_class) gvm-tools-21.1.0/tests/tls_help.snap000066400000000000000000000014231400201773500173600ustar00rootroot00000000000000usage: gvm-test-cli tls [-h] [--hostname HOSTNAME] [--port PORT] [--certfile CERTFILE] [--keyfile KEYFILE] [--cafile CAFILE] [--no-credentials] optional arguments: -h, --help show this help message and exit --hostname HOSTNAME Hostname or IP address (default: 127.0.0.1) --port PORT GMP/OSP port (default: 9390) --certfile CERTFILE Path to the certificate file for client authentication. (default: None) --keyfile KEYFILE Path to key file for client authentication. (default: None) --cafile CAFILE Path to CA certificate for server authentication. (default: None) --no-credentials Use only certificates for authentication