pax_global_header00006660000000000000000000000064147747053220014525gustar00rootroot0000000000000052 comment=574abc2b8ec6e5d31ebc4d0961de5a160a1a8aff gvm-libs-22.20.0/000077500000000000000000000000001477470532200134105ustar00rootroot00000000000000gvm-libs-22.20.0/.clang-format000066400000000000000000000025331477470532200157660ustar00rootroot00000000000000# clang-format configuration for Greenbone C code # # Minimum required clang-format version: 6.0 --- AlignAfterOpenBracket: Align AlignConsecutiveAssignments: 'false' AlignConsecutiveDeclarations: 'false' AlignEscapedNewlines: Left AlignOperands: 'true' AlignTrailingComments: 'true' AllowAllParametersOfDeclarationOnNextLine: 'false' AllowShortBlocksOnASingleLine: 'false' AllowShortCaseLabelsOnASingleLine: 'false' AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: 'false' AllowShortLoopsOnASingleLine: 'false' AlwaysBreakAfterReturnType: All AlwaysBreakBeforeMultilineStrings: 'false' BinPackArguments: 'true' BinPackParameters: 'true' BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: GNU BreakBeforeTernaryOperators: 'true' BreakStringLiterals: 'true' ColumnLimit: '80' ContinuationIndentWidth: '2' DerivePointerAlignment: 'false' IncludeBlocks: Regroup IndentCaseLabels: 'false' IndentWidth: '2' IndentWrappedFunctionNames: 'false' KeepEmptyLinesAtTheStartOfBlocks: 'false' Language: Cpp MaxEmptyLinesToKeep: '1' PointerAlignment: Right ReflowComments: 'true' SortIncludes: 'true' SpaceAfterCStyleCast: 'true' SpaceBeforeAssignmentOperators: 'true' SpaceBeforeParens: Always SpaceInEmptyParentheses: 'false' SpacesInCStyleCastParentheses: 'false' SpacesInParentheses: 'false' SpacesInSquareBrackets: 'false' UseTab: Never ... gvm-libs-22.20.0/.codecov.yml000066400000000000000000000000151477470532200156270ustar00rootroot00000000000000comment: off gvm-libs-22.20.0/.devcontainer/000077500000000000000000000000001477470532200161475ustar00rootroot00000000000000gvm-libs-22.20.0/.devcontainer/Dockerfile000066400000000000000000000022021477470532200201350ustar00rootroot00000000000000FROM debian:stable-slim ARG DEBIAN_FRONTEND=noninteractive ARG CGREEN_VERSION=1.6.2 ARG CGREEN_HASH=fe6be434cbe280330420106bd5d667f1bc84ae9468960053100dbf17071036b9 ARG USERNAME=dev ARG USER_UID=1000 ARG USER_GID=$USER_UID # install dependencies RUN --mount=type=bind,source=.github,target=/source/ \ sh /source/install-dependencies.sh /source/build-dependencies.list RUN apt-get install -y --no-install-recommends \ clang-format # add non-root user RUN groupadd --gid $USER_GID $USERNAME \ && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME -s /bin/bash \ && apt-get update \ && apt-get install -y --no-install-recommends sudo \ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ && chmod 0440 /etc/sudoers.d/$USERNAME # install cgreen RUN curl -sSL -o cgreen.tar.gz https://github.com/cgreen-devs/cgreen/archive/refs/tags/$CGREEN_VERSION.tar.gz \ && echo "$CGREEN_HASH cgreen.tar.gz" | sha256sum -c - \ && tar -xzf cgreen.tar.gz \ && cd cgreen-* \ && cmake -Bbuild -DCMAKE_BUILD_TYPE=Release \ && cmake --build build -j$(nproc) -- install \ && ldconfig CMD /bin/bash gvm-libs-22.20.0/.devcontainer/devcontainer.json000066400000000000000000000005131477470532200215220ustar00rootroot00000000000000{ "name": "gvm-libs stable", // "image": "gvm-libs:stable", "build": { "dockerfile": "Dockerfile", "context": ".." }, "remoteUser": "dev", "customizations": { "vscode": { "extensions": [ "ms-vscode.cpptools-extension-pack" ] } } } gvm-libs-22.20.0/.docker/000077500000000000000000000000001477470532200147355ustar00rootroot00000000000000gvm-libs-22.20.0/.docker/prod-oldstable.Dockerfile000066400000000000000000000012031477470532200216350ustar00rootroot00000000000000FROM debian:oldstable-slim AS build ARG DEBIAN_FRONTEND=noninteractive # Install COPY . /source RUN sh /source/.github/install-dependencies.sh \ /source/.github/build-dependencies.list \ && rm -rf /var/lib/apt/lists/* RUN cmake -DCMAKE_BUILD_TYPE=Release -DOPENVASD=0 -B/build /source \ && DESTDIR=/install cmake --build /build -j$(nproc) -- install FROM debian:oldstable-slim ARG DEBIAN_FRONTEND=noninteractive RUN --mount=type=bind,source=.github,target=/source/ \ sh /source/install-dependencies.sh \ /source/runtime-dependencies.oldstable.list \ && rm -rf /var/lib/apt/lists/* COPY --from=build /install/ / RUN ldconfig gvm-libs-22.20.0/.docker/prod-testing.Dockerfile000066400000000000000000000011601477470532200213430ustar00rootroot00000000000000FROM debian:testing-slim AS build ARG DEBIAN_FRONTEND=noninteractive # Install COPY . /source RUN sh /source/.github/install-dependencies.sh \ /source/.github/build-dependencies.list \ && rm -rf /var/lib/apt/lists/* RUN cmake -DCMAKE_BUILD_TYPE=Release -B/build /source \ && DESTDIR=/install cmake --build /build -j$(nproc) -- install FROM debian:testing-slim ARG DEBIAN_FRONTEND=noninteractive RUN --mount=type=bind,source=.github,target=/source/ \ sh /source/install-dependencies.sh \ /source/runtime-dependencies.testing.list \ && rm -rf /var/lib/apt/lists/* COPY --from=build /install/ / RUN ldconfig gvm-libs-22.20.0/.docker/prod.Dockerfile000066400000000000000000000011551477470532200176740ustar00rootroot00000000000000FROM debian:stable-slim AS build ARG DEBIAN_FRONTEND=noninteractive # Install COPY . /source RUN sh /source/.github/install-dependencies.sh \ /source/.github/build-dependencies.list \ && rm -rf /var/lib/apt/lists/* RUN cmake -DCMAKE_BUILD_TYPE=Release -B/build /source \ && DESTDIR=/install cmake --build /build -j$(nproc) -- install FROM debian:stable-slim ARG DEBIAN_FRONTEND=noninteractive RUN --mount=type=bind,source=.github,target=/source/ \ sh /source/install-dependencies.sh \ /source/runtime-dependencies.stable.list \ && rm -rf /var/lib/apt/lists/* COPY --from=build /install/ / RUN ldconfig gvm-libs-22.20.0/.dockerignore000066400000000000000000000000461477470532200160640ustar00rootroot00000000000000.docker/ .vscode/ .mergify.yml build/ gvm-libs-22.20.0/.github/000077500000000000000000000000001477470532200147505ustar00rootroot00000000000000gvm-libs-22.20.0/.github/CODEOWNERS000066400000000000000000000004031477470532200163400ustar00rootroot00000000000000# default reviewers * @greenbone/scanner-maintainers @greenbone/gea # dev ops .github/ @greenbone/scanner-maintainers @greenbone/gea @greenbone/devops .docker/ @greenbone/scanner-maintainers @greenbone/gea @greenbone/devops gvm-libs-22.20.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001477470532200171335ustar00rootroot00000000000000gvm-libs-22.20.0/.github/ISSUE_TEMPLATE/bug-report.md000066400000000000000000000036061477470532200215500ustar00rootroot00000000000000--- name: Bug Report about: Report an issue with gvm-libs title: '' labels: bug assignees: '' --- ### Expected behavior ### Actual behavior ### Steps to reproduce 1. 2. 3. ### GVM versions **gsa:** (gsad --version) **gvm:** (gvmd --version) **openvas:** (openvas --version) **gvm-libs:** ### Environment **Operating system:** **Installation method / source:** (packages, source installation) ### Logfiles ``` ``` gvm-libs-22.20.0/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000002571477470532200211270ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: Greenbone Community Forum url: https://community.greenbone.net/c/gse about: Please ask and answer questions here. gvm-libs-22.20.0/.github/build-dependencies.list000066400000000000000000000004311477470532200213660ustar00rootroot00000000000000build-essential ca-certificates cmake curl gcovr git gnupg lcov libcjson-dev libcurl4-gnutls-dev libgcrypt-dev libglib2.0-dev libgnutls28-dev libgpgme-dev libhiredis-dev libldap2-dev libnet1-dev libpaho-mqtt-dev libpcap-dev libradcli-dev libssh-dev libxml2-dev pkg-config uuid-dev gvm-libs-22.20.0/.github/dependabot.yml000066400000000000000000000002721477470532200176010ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" groups: github-actions: patterns: - "*" gvm-libs-22.20.0/.github/install-dependencies.sh000077500000000000000000000006751477470532200214110ustar00rootroot00000000000000#!/bin/bash # This script installs gvm-libs dependencies set -e BASEDIR=$(dirname "$0") DEFAULT_DEPENDENCIES_FILE="$BASEDIR/build-dependencies.list" DEPENDENCIES_FILE=${1:-$DEFAULT_DEPENDENCIES_FILE} if [[ ! -f "$DEPENDENCIES_FILE" ]]; then echo "Dependencies file not found: $DEPENDENCIES_FILE" exit 1 fi apt-get update && \ apt-get install -y --no-install-recommends --no-install-suggests \ $(grep -v '#' "$DEPENDENCIES_FILE") gvm-libs-22.20.0/.github/runtime-dependencies.oldstable.list000066400000000000000000000002401477470532200237200ustar00rootroot00000000000000libcjson1 libgcrypt20 libglib2.0-0 libgnutls30 libgpgme11 libhiredis0.14 libldap-common libnet1 libpaho-mqtt1.3 libpcap0.8 libradcli4 libssh-4 libuuid1 libxml2 gvm-libs-22.20.0/.github/runtime-dependencies.stable.list000066400000000000000000000002601477470532200232230ustar00rootroot00000000000000libcjson1 libcurl3-gnutls libgcrypt20 libglib2.0-0 libgnutls30 libgpgme11 libhiredis0.14 libldap-common libnet1 libpaho-mqtt1.3 libpcap0.8 libradcli4 libssh-4 libuuid1 libxml2 gvm-libs-22.20.0/.github/runtime-dependencies.testing.list000066400000000000000000000002641477470532200234320ustar00rootroot00000000000000libcjson1 libcurl3t64-gnutls libgcrypt20 libglib2.0-0 libgnutls30 libgpgme11 libhiredis1.1.0 libldap-common libnet1 libpaho-mqtt1.3 libpcap0.8 libradcli4 libssh-4 libuuid1 libxml2 gvm-libs-22.20.0/.github/workflows/000077500000000000000000000000001477470532200170055ustar00rootroot00000000000000gvm-libs-22.20.0/.github/workflows/build-docs.yml000066400000000000000000000020571477470532200215610ustar00rootroot00000000000000name: 'Build Documentation' on: push: branches: - main jobs: generate-doc-and-upload-coverage: name: Build XML documentation and upload coverage runs-on: ubuntu-latest container: greenbone/doxygen steps: - name: Run the c lang coverage action uses: greenbone/actions/doc-coverage-clang@v3 generate-xml-doc: name: Generate documentation (XML) runs-on: ubuntu-latest container: greenbone/doxygen steps: - name: Check out gvmd uses: actions/checkout@v4 - name: Generate documentation (XML) run: | mkdir build cd build cmake -DSKIP_SRC=1 .. make doc-xml 2> ~/doxygen-stderr.txt - name: Upload doxygen error output as artifact uses: actions/upload-artifact@v4 with: name: doxygen-stderr.txt path: ~/doxygen-stderr.txt - name: Upload XML documentation as artifact uses: actions/upload-artifact@v4 with: name: xml-doc path: build/doc/generated/xml/ gvm-libs-22.20.0/.github/workflows/changelog.yml000066400000000000000000000014771477470532200214700ustar00rootroot00000000000000name: Show changelog since last release on: workflow_dispatch: jobs: changelog: name: Show changelog since last release runs-on: 'ubuntu-latest' steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # for conventional commits and getting all git tags persist-credentials: false - name: Install git-cliff uses: greenbone/actions/uv@v3 with: install: git-cliff - name: Determine changelog env: GITHUB_REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ github.token }} run: | git-cliff -v --strip header --unreleased -o /tmp/changelog.md - name: Show changelog run: | cat /tmp/changelog.md cat /tmp/changelog.md >> $GITHUB_STEP_SUMMARY gvm-libs-22.20.0/.github/workflows/ci-c.yml000066400000000000000000000044651477470532200203540ustar00rootroot00000000000000name: Build and test C on: push: branches: - main pull_request: branches: - main jobs: c-format-check: name: Check C Source Code Formatting runs-on: 'ubuntu-latest' steps: - uses: actions/checkout@v4 - name: Check Source Format run: | clang-format -i -style=file {base,boreas,gmp,osp,util}/*.{c,h} git diff --exit-code tests: name: Unit Tests runs-on: 'ubuntu-latest' container: debian:stable-slim steps: - name: Install git for Codecov uploader run: | apt-get update apt-get install --no-install-recommends -y ca-certificates git - uses: actions/checkout@v4 - name: Set git safe.directory run: git config --global --add safe.directory '*' - name: Install build dependencies run: sh .github/install-dependencies.sh .github/build-dependencies.list - name: Install cgreen uses: greenbone/actions/install-cgreen@v3 - name: Configure and Compile gvm-libs run: | cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=1 -DENABLE_COVERAGE=1 cmake --build build -- install - name: Test gvm-libs run: | CTEST_OUTPUT_ON_FAILURE=1 cmake --build build -- tests test coverage-xml - name: Upload test coverage to Codecov uses: codecov/codecov-action@v5 with: files: build/coverage/coverage.xml token: ${{ secrets.CODECOV_TOKEN }} flags: unittests scan-build: name: Scan-build gvm-libs with clang runs-on: 'ubuntu-latest' container: debian:stable-slim steps: - uses: actions/checkout@v4 - name: Install build dependencies run: sh .github/install-dependencies.sh .github/build-dependencies.list - name: Install clang tools run: | apt update apt-get install --no-install-recommends -y clang clang-format clang-tools - name: Configure and Scan Build gvm-libs run: | cmake -B build -DCMAKE_BUILD_TYPE=Release scan-build -o ~/scan-build-report cmake --build build - name: Upload scan-build report if: failure() uses: actions/upload-artifact@v4 with: name: scan-build-report path: ~/scan-build-report/ retention-days: 7 gvm-libs-22.20.0/.github/workflows/codeql-analysis-c.yml000066400000000000000000000022211477470532200230350ustar00rootroot00000000000000name: "CodeQL" on: push: branches: - main pull_request: branches: - main paths-ignore: - '**/*.md' - '**/*.txt' schedule: - cron: '30 5 * * 0' # 5:30h on Sundays jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write container: image: registry.community.greenbone.net/community/gvm-libs:edge strategy: fail-fast: false matrix: language: [ 'c' ] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install build dependencies run: sh .github/install-dependencies.sh .github/build-dependencies.list - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # build between init and analyze ... - name: Configure and Compile gvm-libs run: | mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Debug .. make install working-directory: ${{ github.WORKSPACE }} - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 gvm-libs-22.20.0/.github/workflows/container.yml000066400000000000000000000035421477470532200215160ustar00rootroot00000000000000name: Build & Push Container Images on: push: branches: - main tags: - "v*" pull_request: branches: - main workflow_dispatch: inputs: ref-name: type: string description: "The ref to build a container image from. For example a tag v23.0.0." required: true jobs: build-push-debian-stable-container: name: Build and Push debian:stable to Greenbone Registry uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main with: base-image-label: "stable" build-docker-file: .docker/prod.Dockerfile image-url: community/gvm-libs image-labels: | org.opencontainers.image.vendor=Greenbone org.opencontainers.image.base.name=debian:stable-slim ref-name: ${{ inputs.ref-name }} secrets: inherit build-push-debian-oldstable-container: name: Build and Push debian:oldstable to Greenbone Registry uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main with: base-image-label: "oldstable" build-docker-file: .docker/prod-oldstable.Dockerfile image-url: community/gvm-libs image-labels: | org.opencontainers.image.vendor=Greenbone org.opencontainers.image.base.name=debian:oldstable-slim ref-name: ${{ inputs.ref-name }} secrets: inherit build-push-debian-testing-container: name: Build and Push debian:testing to Greenbone Registry uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main with: base-image-label: "testing" build-docker-file: .docker/prod-testing.Dockerfile image-url: community/gvm-libs image-labels: | org.opencontainers.image.vendor=Greenbone org.opencontainers.image.base.name=debian:testing-slim ref-name: ${{ inputs.ref-name }} secrets: inherit gvm-libs-22.20.0/.github/workflows/conventional-commits.yml000066400000000000000000000003751477470532200237050ustar00rootroot00000000000000name: Conventional Commits on: pull_request_target: jobs: conventional-commits: name: Conventional Commits runs-on: ubuntu-latest steps: - name: Report Conventional Commits uses: greenbone/actions/conventional-commits@v3 gvm-libs-22.20.0/.github/workflows/dependency-review.yml000066400000000000000000000003741477470532200231510ustar00rootroot00000000000000name: "Dependency Review" on: [pull_request] permissions: contents: read pull-requests: write jobs: dependency-review: runs-on: ubuntu-latest steps: - name: "Dependency Review" uses: greenbone/actions/dependency-review@v3 gvm-libs-22.20.0/.github/workflows/release.yml000066400000000000000000000063141477470532200211540ustar00rootroot00000000000000name: Release gvm-libs on: pull_request: types: [closed] workflow_dispatch: inputs: release-type: type: choice description: What kind of release do you want to do? options: - patch - minor - major release-version: type: string description: Set an explicit version, that will overwrite release-type. Fails if version is not compliant. jobs: build-and-release: name: Create a new release # If the event is a workflow_dispatch or on of the labels 'pre release', # 'patch release', 'minor release' or 'major release' is set and PR is # closed because of a merge # NOTE: priority of set labels will be alpha > release-candidate > patch > minor > major, # so if 'major' and 'patch' labels are set, it will create a patch release. if: | ( github.event_name == 'workflow_dispatch') || ( ( contains(github.event.pull_request.labels.*.name, 'alpha release') || contains(github.event.pull_request.labels.*.name, 'rc release') || contains(github.event.pull_request.labels.*.name, 'patch release') || contains(github.event.pull_request.labels.*.name, 'minor release') || contains(github.event.pull_request.labels.*.name, 'major release')) && github.event.pull_request.merged == true ) runs-on: "ubuntu-latest" steps: - name: Selecting the Release type id: release-type uses: greenbone/actions/release-type@v3 with: release-type-input: ${{ inputs.release-type }} - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # for conventional commits and getting all git tags persist-credentials: false ref: ${{ steps.release-type.outputs.release-ref }} - name: Determine release version id: release-version uses: greenbone/actions/release-version@v3 with: release-type: ${{ steps.release-type.outputs.release-type }} release-version: ${{ inputs.release-version }} versioning-scheme: "semver" - name: Install git-cliff uses: greenbone/actions/uv@v3 with: install: git-cliff - name: Determine changelog env: GITHUB_REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ github.token }} run: | git-cliff -v --strip header -o /tmp/changelog.md --unreleased --tag ${{ steps.release-version.outputs.release-version }} ${{ steps.release-version.outputs.last-release-version }}..HEAD - name: Release with release action id: release uses: greenbone/actions/release@v3 with: github-user: ${{ secrets.GREENBONE_BOT }} github-user-mail: ${{ secrets.GREENBONE_BOT_MAIL }} github-user-token: ${{ secrets.GREENBONE_BOT_TOKEN }} gpg-key: ${{ secrets.GPG_KEY }} gpg-fingerprint: ${{ secrets.GPG_FINGERPRINT }} gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} release-version: ${{ steps.release-version.outputs.release-version }} changelog: /tmp/changelog.md ref: ${{ steps.release-type.outputs.release-ref }} versioning-scheme: "semver" gvm-libs-22.20.0/.github/workflows/sbom-upload.yml000066400000000000000000000004221477470532200217500ustar00rootroot00000000000000name: SBOM upload on: workflow_dispatch: push: branches: - main jobs: SBOM-upload: runs-on: ubuntu-latest permissions: id-token: write contents: write steps: - name: 'SBOM upload' uses: greenbone/actions/sbom-upload@v3 gvm-libs-22.20.0/.gitignore000066400000000000000000000002111477470532200153720ustar00rootroot00000000000000build/ .ccls # clangd # generated by # cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 compile_commands.json .cache/ # cmake CMakeFiles/ .vscode gvm-libs-22.20.0/.mergify.yml000066400000000000000000000034561477470532200156630ustar00rootroot00000000000000pull_request_rules: # backports from main branch - name: backport main patches to stable branch conditions: - base=main - label=backport-to-stable actions: backport: branches: - stable - name: backport main patches to oldstable branch conditions: - base=main - label=backport-to-oldstable actions: backport: branches: - oldstable - name: port main patches to middleware branch conditions: - base=main - label=backport-to-middleware actions: backport: branches: - middleware # backports from stable release branch - name: port stable patches to main branch conditions: - base=stable - label=backport-to-main actions: backport: branches: - main - name: backport stable patches to oldstable branch conditions: - base=stable - label=backport-to-oldstable actions: backport: branches: - oldstable - name: port stable patches to middleware branch conditions: - base=stable - label=backport-to-middleware actions: backport: branches: - middleware # ports from oldstable release branch - name: port oldstable patches to main branch conditions: - base=oldstable - label=backport-to-main actions: backport: branches: - main - name: port oldstable patches to stable branch conditions: - base=oldstable - label=backport-to-stable actions: backport: branches: - stable - name: port oldstable patches to middleware branch conditions: - base=oldstable - label=backport-to-middleware actions: backport: branches: - middleware gvm-libs-22.20.0/CMakeLists.txt000066400000000000000000000230661477470532200161570ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2011-2023 Greenbone AG # # SPDX-License-Identifier: GPL-2.0-or-later cmake_minimum_required(VERSION 3.0) message ("-- Configuring the Greenbone Vulnerability Management Libraries...") # VERSION: Always include major, minor and patch level. project (gvm-libs VERSION 22.20.0 LANGUAGES C) if (POLICY CMP0005) cmake_policy (SET CMP0005 NEW) endif (POLICY CMP0005) set (C_STANDARD, 11) set (CMAKE_C_STANDARD 11) if (NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE Debug) endif (NOT CMAKE_BUILD_TYPE) OPTION(BUILD_STATIC "Build static versions of the libraries" OFF) OPTION(ENABLE_COVERAGE "Enable support for coverage analysis" OFF) OPTION(BUILD_TESTS "Build tests for the libraries" OFF) OPTION(OPENVASD "Build openvasd library" ON) if (NOT BUILD_STATIC) set (BUILD_SHARED ON) else (NOT BUILD_STATIC) set (BUILD_SHARED OFF) endif (NOT BUILD_STATIC) set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) ## Retrieve git revision (at configure time) find_package (Git) ## make format message (STATUS "Looking for clang-format...") find_program (CLANG_FORMAT clang-format) if (CLANG_FORMAT) message (STATUS "Looking for clang-format... ${CLANG_FORMAT}") add_custom_target(format COMMAND ${CLANG_FORMAT} "-i" "./base/*.c" "./boreas/*.c" "./gmp/*.c" "./openvasd/*.c" "./osp/*.c" "./util/*.c" "./base/*.h" "./boreas/*.h" "./gmp/*.h" "./openvasd/*.h" "./osp/*.h" "./util/*.h" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") else (CLANG_FORMAT) message (STATUS "clang-format not found...") endif (CLANG_FORMAT) macro (Git_GET_REVISION dir variable) execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) string (REPLACE "/" "_" GIT_BRANCH ${GIT_BRANCH}) set (${variable} "${GIT_COMMIT_HASH}-${GIT_BRANCH}") endmacro (Git_GET_REVISION) if (NOT CMAKE_BUILD_TYPE MATCHES "Release") if (EXISTS "${CMAKE_SOURCE_DIR}/.git/") if (GIT_FOUND) Git_GET_REVISION(${CMAKE_SOURCE_DIR} ProjectRevision) set (GIT_REVISION "~git-${ProjectRevision}") else (GIT_FOUND) set (GIT_REVISION "~git") endif (GIT_FOUND) endif (EXISTS "${CMAKE_SOURCE_DIR}/.git/") endif (NOT CMAKE_BUILD_TYPE MATCHES "Release") # Set dev version if this is a development version and not a full release, # unset (put value 0 or delete line) before a full release and reset after. set (PROJECT_DEV_VERSION 0) # If PROJECT_DEV_VERSION is set, the version string will be set to: # "major.minor.patch~dev${PROJECT_DEV_VERSION}${GIT_REVISION}" # If PROJECT_DEV_VERSION is NOT set, the version string will be set to: # "major.minor.patch${GIT_REVISION}" # For CMAKE_BUILD_TYPE "Release" the git revision will be empty. if (PROJECT_DEV_VERSION) set (PROJECT_VERSION_SUFFIX "~dev${PROJECT_DEV_VERSION}") endif (PROJECT_DEV_VERSION) set (PROJECT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${PROJECT_VERSION_SUFFIX}${GIT_REVISION}") ## CPack configuration set (CPACK_CMAKE_GENERATOR "Unix Makefiles") set (CPACK_GENERATOR "TGZ") set (CPACK_INSTALL_CMAKE_PROJECTS ".;gvm-libs;ALL;/") set (CPACK_MODULE_PATH "") set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING") set (CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md") set (CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/README.md") set (CPACK_SOURCE_GENERATOR "TGZ") set (CPACK_SOURCE_TOPLEVEL_TAG "") set (CPACK_SYSTEM_NAME "") set (CPACK_TOPLEVEL_TAG "") set (CPACK_PACKAGE_VERSION "${PROJECT_VERSION_STRING}${PROJECT_VERSION_GIT}") set (CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}") set (CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}") set (CPACK_PACKAGE_VENDOR "Greenbone Networks") set (CPACK_SOURCE_IGNORE_FILES "${CMAKE_BINARY_DIR}" "/.git/" "swp$" ) include (CPack) ## Variables if (SYSCONF_INSTALL_DIR) set (SYSCONFDIR "${SYSCONF_INSTALL_DIR}") endif (SYSCONF_INSTALL_DIR) if (NOT SYSCONFDIR) set (SYSCONFDIR "/etc") endif (NOT SYSCONFDIR) if (NOT EXEC_PREFIX) set (EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") endif (NOT EXEC_PREFIX) if (NOT BINDIR) set (BINDIR "${EXEC_PREFIX}/bin") endif (NOT BINDIR) if (NOT SBINDIR) set (SBINDIR "${EXEC_PREFIX}/sbin") endif (NOT SBINDIR) if (NOT LIBDIR) set (_DEFAULT_LIBRARY_INSTALL_DIR lib) if (EXISTS "${EXEC_PREFIX}/lib32/" AND CMAKE_SIZEOF_VOID_P EQUAL 4) set (_DEFAULT_LIBRARY_INSTALL_DIR lib32) endif (EXISTS "${EXEC_PREFIX}/lib32/" AND CMAKE_SIZEOF_VOID_P EQUAL 4) if (EXISTS "${CMAKE_INSTALL_PREFIX}/lib64/" AND CMAKE_SIZEOF_VOID_P EQUAL 8) set (_DEFAULT_LIBRARY_INSTALL_DIR lib64) endif (EXISTS "${CMAKE_INSTALL_PREFIX}/lib64/" AND CMAKE_SIZEOF_VOID_P EQUAL 8) set( LIBRARY_INSTALL_DIR "${_DEFAULT_LIBRARY_INSTALL_DIR}") set (LIBDIR "${EXEC_PREFIX}/${LIBRARY_INSTALL_DIR}") endif (NOT LIBDIR) if (NOT LOCALSTATEDIR) set (LOCALSTATEDIR "/var") endif (NOT LOCALSTATEDIR) if (NOT INCLUDEDIR) set (INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") endif (NOT INCLUDEDIR) if (NOT DATADIR) set (DATADIR "${CMAKE_INSTALL_PREFIX}/share") endif (NOT DATADIR) if (NOT GVM_RUN_DIR) set (GVM_RUN_DIR "/run/gvm") endif (NOT GVM_RUN_DIR) if (NOT GVM_SYSCONF_DIR) set (GVM_SYSCONF_DIR "${SYSCONFDIR}/gvm") endif (NOT GVM_SYSCONF_DIR) if (NOT REDIS_SOCKET_PATH) set (REDIS_SOCKET_PATH "/run/redis/redis.sock") endif () add_definitions (-DREDIS_SOCKET_PATH="${REDIS_SOCKET_PATH}") message ("-- Using redis socket ${REDIS_SOCKET_PATH}") message ("-- Install prefix: ${CMAKE_INSTALL_PREFIX}") if (ENABLE_COVERAGE) set (COVERAGE_FLAGS "--coverage -ftest-coverage -fprofile-arcs") set (COVERAGE_DIR "${CMAKE_BINARY_DIR}/coverage") file (MAKE_DIRECTORY ${COVERAGE_DIR}) message ("-- Code Coverage enabled") endif (ENABLE_COVERAGE) set (HARDENING_FLAGS "-Wformat -Wformat-security -D_FORTIFY_SOURCE=2 -fstack-protector") set (LINKER_HARDENING_FLAGS "-Wl,-z,relro -Wl,-z,now") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COVERAGE_FLAGS}") set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${HARDENING_FLAGS} ${COVERAGE_FLAGS}") set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GPGME_C_FLAGS} \ -std=c11 \ -Wall \ -Wextra \ -Werror \ -Wpedantic \ -Wmissing-prototypes \ -Wshadow \ -Wsequence-point \ -D_ISOC11_SOURCE \ -D_DEFAULT_SOURCE" ) ## Version set (LIBGVMCONFIG_VERSION "${PROJECT_VERSION_STRING}") add_definitions(-DGVM_LIBS_VERSION="${LIBGVMCONFIG_VERSION}") # Configure Doxyfile with version number configure_file (doc/Doxyfile.in ${CMAKE_BINARY_DIR}/doc/Doxyfile @ONLY) configure_file (doc/Doxyfile_full.in ${CMAKE_BINARY_DIR}/doc/Doxyfile_full @ONLY) configure_file (doc/Doxyfile_xml.in ${CMAKE_BINARY_DIR}/doc/Doxyfile_xml @ONLY) configure_file (VERSION.in ${CMAKE_BINARY_DIR}/VERSION @ONLY) ## Testing if (BUILD_TESTS AND NOT SKIP_SRC) message ("-- Tests enabled.") enable_testing () include (MacroAddUnitTest) find_package (cgreen REQUIRED) add_custom_target (tests DEPENDS array-test boreas-alivedetection-test boreas-cli-test boreas-error-test boreas-io-test boreas-ping-test boreas-sniffer-test compressutils-test cpeutils-test cvss-test hosts-test httputils-test json-test jsonpull-test logging-test logging-domain-test networking-test nvti-test openvasd-test osp-test passwordbasedauthentication-test test-hosts util-test version-test versionutils-test vtparser-test xmlutils-test) # Code coverage if (ENABLE_COVERAGE) find_program (GCOVR gcovr) if (NOT GCOVR) message (FATAL_ERROR "gcovr coverage reporting tool not found") endif () message ("-- Code Coverage Reporting enabled") add_custom_target (coverage-html COMMAND ${GCOVR} --html-details ${COVERAGE_DIR}/coverage.html -r ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} DEPENDS tests) add_custom_target (coverage-xml COMMAND ${GCOVR} --xml ${COVERAGE_DIR}/coverage.xml -r ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} DEPENDS tests) add_custom_target (coverage DEPENDS coverage-xml coverage-html) endif (ENABLE_COVERAGE) endif (BUILD_TESTS AND NOT SKIP_SRC) add_custom_target (clean-coverage COMMAND find . -name *.gcda -delete -or -name *.gcno -delete COMMAND rm -f ${COVERAGE_DIR}/*) ## Program if (NOT SKIP_SRC) add_subdirectory (base) add_subdirectory (boreas) add_subdirectory (util) add_subdirectory (osp) add_subdirectory (gmp) if (OPENVASD) add_subdirectory (http) add_subdirectory (openvasd) endif (OPENVASD) endif (NOT SKIP_SRC) ## Documentation add_subdirectory (doc) if (BUILD_TESTS AND NOT SKIP_SRC) add_subdirectory (tests) add_test (NAME testhosts COMMAND test-hosts localhost) endif (BUILD_TESTS AND NOT SKIP_SRC) ## End gvm-libs-22.20.0/COPYING000066400000000000000000000431221477470532200144450ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. gvm-libs-22.20.0/INSTALL.md000066400000000000000000000140611477470532200150420ustar00rootroot00000000000000# Installation Instructions for gvm-libs Please note: The reference system used by most of the developers is Debian stable. The build might fail on any other system. Also, it is necessary to install dependent development packages. ## Prerequisites for gvm-libs See at the end of this section how to easily install these prerequisites on some supported platforms. General build environment: * a C compiler (e.g. gcc) * cmake >= 3.0 * pkg-config Specific development libraries: * libcjson >= 1.7.14 (util) * libcurl >= 7.83.0 (openvasd) * libgcrypt * libgio >= 2.42 (util) * libglib >= 2.42 (all) * libgnutls >= 3.2.15 (util) * libgpgme >= 1.7.0 (util) * libhiredis >= 0.10.1 (util) * libnet1 >= 1.1.2.1 (boreas) * libpaho-mqtt >= 1.3.0 (utils) * libpcap * libssh >= 0.6.0 (util) * libuuid >= 2.25.0 (util) * libxml2 >= 2.0 (util) * zlib >= 1.2.8 (util) Prerequisites for building documentation: * doxygen * xmltoman (optional, for building man page) Prerequisites for building tests: * [Cgreen](https://cgreen-devs.github.io/cgreen/cgreen-guide-en.html#_installing_cgreen) (optional, for building tests) Install prerequisites on Debian stable: apt-get install \ cmake \ libcjson-dev \ libcurl4-gnutls-dev \ libgcrypt-dev \ libglib2.0-dev \ libgnutls28-dev \ libgpgme-dev \ libhiredis-dev \ libnet1-dev \ libpaho-mqtt-dev \ libpcap-dev \ libssh-dev \ libxml2-dev \ pkg-config \ uuid-dev ## Prerequisites for Optional Features Certain features of gvm-libs are optional and require the following: Prerequisites for LDAP authentication: * libldap2 library >= 2.4.44 (util) (Debian package: libldap2-dev) Prerequisites for RADIUS authentication: * libradcli4 library >= 1.2.6 (util) (Debian package: libradcli-dev) * Alternative: libfreeradius3 library (util) (Debian package: libfreeradius-dev) Install prerequisites for optional features on Debian GNU/Linux 'Buster' 10: apt-get install \ libldap2-dev \ libradcli-dev ## Compiling gvm-libs If you have installed required libraries to a non-standard location, remember to set the `PKG_CONFIG_PATH` environment variable to the location of your pkg-config files before configuring: export PKG_CONFIG_PATH=/your/location/lib/pkgconfig:$PKG_CONFIG_PATH Create a build directory and change working directory into it with mkdir build && cd build Afterwards you can run `cmake` with different options: * Configure `gvm-libs` build with a custom installation path: cmake -DCMAKE_INSTALL_PREFIX=/path/to/your/installation .. * or (if you want to use the default installation path `/usr/local`): cmake .. * Configure `gvm-libs` build with tests, you need to run `cmake` with `BUILD_TESTS`: cmake -DBUILD_TESTS=ON .. The `cmake` command only needs to be executed once. Further information regarding cmake can be found [here](https://cmake.org/cmake/help/latest/manual/cmake.1.html#) or with the command `cmake --help-full`. You can list all project options and settable variables with `cmake -LA`. Thereafter, you need to compile and install the project with `make`. The following command options are available: make # build the libraries make help # list possible make commands make doc # build the documentation make doc-full # build more developer-oriented documentation make tests # build tests (requires BUILD_TESTS activated) make install # install the build make rebuild_cache # rebuild the cmake cache make format # code style and formatting Please note that you may have to execute `make install` as root, especially if you have specified a prefix for which your user does not have full permissions. You can also install specific components with make. See `make help` for more details. You can remove the compiled binaries with `make clean`. To clean up the full build environment, simply remove the contents of the `build` directory you created above. cd .. && rm -rf build ## Configurable Options During compilation, the build process uses a set of compiler options which enable very strict error checking and asks the compiler to abort should it detect any errors in the code. This is to ensure a maximum of code quality and security. Some (especially newer) compilers can be stricter than others when it comes to error checking. While this is a good thing and the developers aim to address all compiler warnings, it may lead the build process to abort on your system. Should you notice error messages causing your build process to abort, do not hesitate to contact the developers using the [Greenbone Community Portal](https://community.greenbone.net/c/gse). Don't forget to include the name and version of your compiler and distribution in your message. ## Building GVM Libraries statically linked If you want to build a statically linked version -- for example to subsequently build a statically linked program using this library -- you need statically linked versions of the prerequisite libraries as well. This can be a problem with current versions of the GnuTLS library. In most distributions GnuTLS is built with `p11-kit` support, which makes linking statically against the GnuTLS library impossible. To work around this, you can build the GnuTLS yourself after configuring it without support for `p11-kit`. This can be done with the following parameters: ./configure --disable-shared --enable-static --without-p11-kit Note that you will most likely want to add additional parameters to configure the GnuTLS library based on your distributions policy and/or your personal needs, e.g. the correct prefix so the statically linked version will be found. The `make install` command will then build the GnuTLS library and install it into the path you configured. Once you have built and installed the GnuTLS library, configure this module with the following parameters to request statically linked versions of the single library modules: cmake -DBUILD_STATIC=1 -DBUILD_SHARED=0 .. Once again, the `make install` command will build and install the requested modules. gvm-libs-22.20.0/README.md000066400000000000000000000073271477470532200147000ustar00rootroot00000000000000![Greenbone Logo](https://www.greenbone.net/wp-content/uploads/gb_new-logo_horizontal_rgb_small.png) # gvm-libs [![GitHub releases](https://img.shields.io/github/release/greenbone/gvm-libs.svg)](https://github.com/greenbone/gvm-libs/releases) [![Build and test C](https://github.com/greenbone/gvm-libs/actions/workflows/ci-c.yml/badge.svg)](https://github.com/greenbone/gvm-libs/actions/workflows/ci-c.yml) [![codecov](https://codecov.io/gh/greenbone/gvm-libs/graph/badge.svg?token=OUojGTMBgP)](https://codecov.io/gh/greenbone/gvm-libs) This is the libraries module for the Greenbone Community Edition. It is used for the Greenbone Enterprise appliances and provides various functionalities to support the integrated service daemons. ## Releases  All [release files](https://github.com/greenbone/gvm-libs/releases) are signed with the [Greenbone Community Feed integrity key](https://community.greenbone.net/t/gcf-managing-the-digital-signatures/101). This gpg key can be downloaded at https://www.greenbone.net/GBCommunitySigningKey.asc and the fingerprint is `8AE4 BE42 9B60 A59B 311C 2E73 9823 FAA6 0ED1 E580`. ## Installation This module can be configured, built and installed with following commands: cmake . make install For detailed installation requirements and instructions, please see the file [INSTALL.md](INSTALL.md). If you are not familiar or comfortable building from source code, we recommend that you use the Greenbone Security Manager TRIAL (GSM TRIAL), a prepared virtual machine with a readily available setup. Information regarding the virtual machine is available at . ## Usage The `gvm-libs` module consists of the following libraries: - `base`: All basic modules which require only the `glib` library as a dependency. - `util`: All modules that require more than the `glib` library as dependency. - `gmp`: API support for the Greenbone Management Protocol (GMP). - `osp`: API support for the Open Scanner Protocol (OSP). For more information on using the functionality provided by the `gvm-libs` module please refer to the source code documentation. ## Support For any question on the usage of `gvm-libs` please use the [Greenbone Community Portal](https://community.greenbone.net/). If you found a problem with the software, please [create an issue](https://github.com/greenbone/gvm-libs/issues) on GitHub. If you are a Greenbone customer you may alternatively or additionally forward your issue to the Greenbone Support Portal. ## Maintainer This project is maintained by [Greenbone AG](https://www.greenbone.net/). ## Contributing Your contributions are highly appreciated. Please [create a pull request](https://github.com/greenbone/gvm-libs/pulls) on GitHub. Bigger changes need to be discussed with the development team via the [issues section at github](https://github.com/greenbone/gvm-libs/issues) first. ### Code style and formatting Before creating a pull request, it is recommended to run the following command: make format This reformats the new code to ensure that it follows the code style and formatting guidelines. ### Static code analysis with the Clang Static Analyzer If you want to use the Clang Static Analyzer (http://clang-analyzer.llvm.org/) to do a static code analysis, you can do so by prefixing the configuration and build commands with `scan-build`: scan-build cmake .. scan-build make The tool will provide a hint on how to launch a web browser with the results. It is recommended to do this analysis in a separate, empty build directory and to empty the build directory before `scan-build` call. ## License Copyright (C) 2009-2022 [Greenbone AG](https://www.greenbone.net/) Licensed under the [GNU General Public License v2.0 or later](COPYING). gvm-libs-22.20.0/VERSION.in000066400000000000000000000000271477470532200150640ustar00rootroot00000000000000@CPACK_PACKAGE_VERSION@gvm-libs-22.20.0/base/000077500000000000000000000000001477470532200143225ustar00rootroot00000000000000gvm-libs-22.20.0/base/CMakeLists.txt000066400000000000000000000110431477470532200170610ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2009-2023 Greenbone AG # # SPDX-License-Identifier: GPL-2.0-or-later include (FindPkgConfig) if (NOT PKG_CONFIG_FOUND) message(FATAL_ERROR "pkg-config executable not found. Aborting.") endif (NOT PKG_CONFIG_FOUND) ## Dependency checks pkg_check_modules (GLIB REQUIRED glib-2.0>=2.42) if ($ENV{BUILD_SENTRY}) find_package (SENTRY REQUIRED) if (${SENTRY_FOUND}) message ("Building with Sentry integration") set (SENTRY_LDFLAGS "-lsentry") set (SENTRY_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include") set (SENTRY_CFLAGS "-I${SENTRY_INCLUDE_DIR}") add_definitions (-DHAVE_SENTRY=1) endif (${SENTRY_FOUND}) endif ($ENV{BUILD_SENTRY}) include_directories (${GLIB_INCLUDE_DIRS} ${SENTRY_INCLUDE_DIR}) set (FILES array.c credentials.c cvss.c drop_privileges.c hosts.c logging.c logging_domain.c networking.c nvti.c pidfile.c prefs.c proctitle.c pwpolicy.c gvm_sentry.c settings.c strings.c version.c) set (HEADERS array.h credentials.h cvss.h drop_privileges.h hosts.h logging.h logging_domain.h networking.h nvti.h pidfile.h prefs.h proctitle.h pwpolicy.h gvm_sentry.h settings.h strings.h version.h) if (BUILD_STATIC) set (LIBGVM_BASE_NAME gvm_base_static) add_library (gvm_base_static STATIC ${FILES}) target_link_libraries(gvm_base_static m) set_target_properties (gvm_base_static PROPERTIES OUTPUT_NAME "gvm_base") set_target_properties (gvm_base_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties (gvm_base_static PROPERTIES PUBLIC_HEADER "${HEADERS}") endif (BUILD_STATIC) if (BUILD_SHARED) set (LIBGVM_BASE_NAME gvm_base_shared) add_library (gvm_base_shared SHARED ${FILES}) set_target_properties (gvm_base_shared PROPERTIES OUTPUT_NAME "gvm_base") set_target_properties (gvm_base_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties (gvm_base_shared PROPERTIES SOVERSION "${PROJECT_VERSION_MAJOR}") set_target_properties (gvm_base_shared PROPERTIES VERSION "${CPACK_PACKAGE_VERSION}") set_target_properties (gvm_base_shared PROPERTIES PUBLIC_HEADER "${HEADERS}") target_link_libraries (gvm_base_shared LINK_PRIVATE ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${SENTRY_LDFLAGS} m) endif (BUILD_SHARED) set (LIBGVM_BASE_NAME ${LIBGVM_BASE_NAME} PARENT_SCOPE) if (GVM_SYSCONF_DIR) add_definitions (-DGVM_SYSCONF_DIR="${GVM_SYSCONF_DIR}") endif (GVM_SYSCONF_DIR) ## Tests if (BUILD_TESTS) add_link_options (-g -lgcov --coverage) add_compile_options (-g -ftest-coverage -fprofile-arcs) add_unit_test (array-test array_tests.c ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_unit_test (cvss-test cvss_tests.c -lm ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) set (NETWORKING_TEST_LINKER_WRAP_OPTIONS "-Wl,-wrap,g_io_channel_new_file,-wrap,g_io_channel_shutdown") add_unit_test (networking-test networking_tests.c gvm_base_shared ${CGREEN_LIBRARIES} ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${NETWORKING_TEST_LINKER_WRAP_OPTIONS}) add_unit_test (pwpolicy-test pwpolicy_tests.c ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_unit_test (version-test version_tests.c ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_unit_test (nvti-test nvti_tests.c ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_unit_test (hosts-test hosts_tests.c gvm_base_shared gvm_util_shared ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_unit_test (logging-domain-test logging_domain_tests.c gvm_base_shared ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_unit_test (logging-test logging_tests.c gvm_base_shared ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS}) endif (BUILD_TESTS) ## Install configure_file (libgvm_base.pc.in ${CMAKE_BINARY_DIR}/libgvm_base.pc @ONLY) install (DIRECTORY DESTINATION ${GVM_RUN_DIR}) install (FILES ${CMAKE_BINARY_DIR}/libgvm_base.pc DESTINATION ${LIBDIR}/pkgconfig) if (BUILD_STATIC) install (TARGETS gvm_base_static RUNTIME DESTINATION ${BINDIR} ARCHIVE DESTINATION ${LIBDIR} PUBLIC_HEADER DESTINATION "${INCLUDEDIR}/gvm/base") endif (BUILD_STATIC) if (BUILD_SHARED) install (TARGETS gvm_base_shared RUNTIME DESTINATION ${BINDIR} LIBRARY DESTINATION ${LIBDIR} ARCHIVE DESTINATION ${LIBDIR} PUBLIC_HEADER DESTINATION "${INCLUDEDIR}/gvm/base") endif (BUILD_SHARED) ## End gvm-libs-22.20.0/base/array.c000066400000000000000000000023661477470532200156130ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Array utilities. */ #include "array.h" #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Make a global array. * * @return New array. */ GPtrArray * make_array (void) { return g_ptr_array_new (); } /** * @brief Reset an array. * * @param[in] array Pointer to array. */ void array_reset (array_t **array) { array_free (*array); *array = make_array (); } /** * @brief Free global array value. * * Also g_free any elements. * * @param[in] array Pointer to array. */ void array_free (GPtrArray *array) { if (array) { guint index = array->len; while (index--) g_free (g_ptr_array_index (array, index)); g_ptr_array_free (array, TRUE); } } /** * @brief Push a generic pointer onto an array. * * @param[in] array Array. * @param[in] pointer Pointer. */ void array_add (array_t *array, gpointer pointer) { if (array) g_ptr_array_add (array, pointer); } /** * @brief Terminate an array. * * @param[in] array Array. */ void array_terminate (array_t *array) { if (array) g_ptr_array_add (array, NULL); } gvm-libs-22.20.0/base/array.h000066400000000000000000000007221477470532200156120ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Array utilities. */ #ifndef _GVM_ARRAY_H #define _GVM_ARRAY_H #include typedef GPtrArray array_t; GPtrArray * make_array (void); void array_reset (array_t **array); void array_free (GPtrArray *array); void array_add (array_t *array, gpointer pointer); void array_terminate (array_t *array); #endif /* not _GVM_ARRAY_H */ gvm-libs-22.20.0/base/array_tests.c000066400000000000000000000012511477470532200170250ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "array.c" #include #include Describe (array); BeforeEach (array) { } AfterEach (array) { } /* make_array */ Ensure (array, make_array_never_returns_null) { assert_that (make_array (), is_not_null); } /* Test suite. */ int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, array, make_array_never_returns_null); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/credentials.c000066400000000000000000000030761477470532200167710ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Credential pairs and triples. */ #include "credentials.h" #include "strings.h" /* for gvm_append_text */ #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Free credentials. * * Free the members of a credentials pair. * * @param[in] credentials Pointer to the credentials. */ void free_credentials (credentials_t *credentials) { g_free (credentials->username); g_free (credentials->password); g_free (credentials->uuid); g_free (credentials->timezone); g_free (credentials->role); g_free (credentials->severity_class); memset (credentials, '\0', sizeof (*credentials)); } /** * @brief Append text to the username of a credential pair. * * @param[in] credentials Credentials. * @param[in] text The text to append. * @param[in] length Length of the text. */ void append_to_credentials_username (credentials_t *credentials, const char *text, gsize length) { gvm_append_text (&credentials->username, text, length); } /** * @brief Append text to the password of a credential pair. * * @param[in] credentials Credentials. * @param[in] text The text to append. * @param[in] length Length of the text. */ void append_to_credentials_password (credentials_t *credentials, const char *text, gsize length) { gvm_append_text (&credentials->password, text, length); } gvm-libs-22.20.0/base/credentials.h000066400000000000000000000023331477470532200167710ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Credential pairs and triples. */ #ifndef _GVM_CREDENTIALS_H #define _GVM_CREDENTIALS_H #include /** * @brief A username password pair. */ typedef struct { /*@null@ */ gchar *username; ///< Login name of user. /*@null@ */ gchar *password; ///< Password of user. /*@null@ */ gchar *uuid; ///< UUID of user. /*@null@ */ gchar *timezone; ///< Timezone of user. /*@null@ */ double default_severity; ///< Default Severity setting of user. /*@null@ */ gchar *severity_class; ///< Severity Class setting of user. /*@null@ */ int dynamic_severity; ///< Dynamic Severity setting of user. /*@null@ */ gchar *role; ///< Role of user. /*@null@ */ int excerpt_size; ///< Note/Override Excerpt Size setting of user. } credentials_t; void free_credentials (credentials_t *credentials); void append_to_credentials_username (credentials_t *credentials, const char *text, gsize length); void append_to_credentials_password (credentials_t *credentials, const char *text, gsize length); #endif /* _GVM_CREDENTIALS_H */ gvm-libs-22.20.0/base/cvss.c000066400000000000000000001610351477470532200154520ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief CVSS utility functions * * This file contains utility functions for handling CVSS v2, v3 and v4. * get_cvss_score_from_base_metrics calculates the CVSS base score from a CVSS * base vector. * * CVSS v4.0: * * See the CVSS v4 calculator reference implementation at * https://github.com/FIRSTdotorg/cvss-v4-calculator and the CVSS 4.0 * specification document at * https://www.first.org/cvss/v4.0/specification-document * (especially sections 7., 8.2 and 8.3). * * CVSS v3.1: * * See equations at https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator and * constants at https://www.first.org/cvss/v3.1/specification-document (section * 7.4. Metric Values). * * CVSS v3.0: * * See equations at https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator and * constants at https://www.first.org/cvss/v3.0/specification-document (section * 8.4. Metric Levels). * * CVSS v2: * * The base equation is the foundation of CVSS scoring. The base equation is: * BaseScore6 * = round_to_1_decimal(((0.6*Impact)+(0.4*Exploitability)–1.5)*f(Impact)) * * Impact * = 10.41*(1-(1-ConfImpact)*(1-IntegImpact)*(1-AvailImpact)) * * Exploitability * = 20* AccessVector*AccessComplexity*Authentication * * f(impact)= 0 if Impact=0, 1.176 otherwise * AccessVector = case AccessVector of * requires local access: 0.395 * adjacent network accessible: 0.646 * network accessible: 1.0 * AccessComplexity = case AccessComplexity of * high: 0.35 * medium: 0.61 * low: 0.71 * Authentication = case Authentication of * requires multiple instances of authentication: 0.45 * requires single instance of authentication: 0.56 * requires no authentication: 0.704 * ConfImpact = case ConfidentialityImpact of * none: 0.0 * partial: 0.275 * complete: 0.660 * IntegImpact = case IntegrityImpact of * none: 0.0 * partial: 0.275 * complete: 0.660 * AvailImpact = case AvailabilityImpact of * none: 0.0 * partial: 0.275 * complete: 0.660 */ #include "cvss.h" #include #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /* Static Headers. */ static double get_cvss_score_from_base_metrics_v3 (const char *); static double get_cvss_score_from_metrics_v4 (const char *); /* CVSS v2. */ // clang-format off /** * @brief AccessVector (AV) Constants. */ #define AV_NETWORK 1.0 /**< Access Vector Network. */ #define AV_ADJACENT_NETWORK 0.646 /**< Access Vector Adjacent Network. */ #define AV_LOCAL 0.395 /**< Access Vector Local. */ /** * @brief AccessComplexity (AC) Constants. */ #define AC_LOW 0.71 /**< Access Complexity Low. */ #define AC_MEDIUM 0.61 /**< Access Complexity Medium. */ #define AC_HIGH 0.35 /**< Access Complexity High. */ /** * @brief Authentication (Au) Constants. */ #define Au_MULTIPLE_INSTANCES 0.45 /**< Authentication multiple instances. */ #define Au_SINGLE_INSTANCE 0.56 /**< Authentication single instances. */ #define Au_NONE 0.704 /**< No Authentication. */ /** * @brief ConfidentialityImpact (C) Constants. */ #define C_NONE 0.0 /**< No Confidentiality Impact. */ #define C_PARTIAL 0.275 /**< Partial Confidentiality Impact. */ #define C_COMPLETE 0.660 /**< Complete Confidentiality Impact. */ /** * @brief IntegrityImpact (I) Constants. */ #define I_NONE 0.0 /**< No Integrity Impact. */ #define I_PARTIAL 0.275 /**< Partial Integrity Impact. */ #define I_COMPLETE 0.660 /**< Complete Integrity Impact. */ /** * @brief AvailabilityImpact (A) Constants. */ #define A_NONE 0.0 /**< No Availability Impact. */ #define A_PARTIAL 0.275 /**< Partial Availability Impact. */ #define A_COMPLETE 0.660 /**< Complete Availability Impact. */ // clang-format on /** * @brief CVSS v2 Base metrics. */ enum base_metrics { A, /**< Availability Impact. */ I, /**< Integrity Impact. */ C, /**< Confidentiality Impact. */ Au, /**< Authentication. */ AC, /**< Access Complexity. */ AV /**< Access Vector. */ }; /** * @brief Describe a CVSS impact element. */ struct impact_item { const char *name; /**< Impact element name */ double nvalue; /**< Numerical value */ }; /** * @brief Describe a CVSS metrics. */ struct cvss { double conf_impact; /**< Confidentiality impact. */ double integ_impact; /**< Integrity impact. */ double avail_impact; /**< Availability impact. */ double access_vector; /**< Access vector. */ double access_complexity; /**< Access complexity. */ double authentication; /**< Authentication. */ }; static const struct impact_item impact_map[][3] = { [A] = { {"N", A_NONE}, {"P", A_PARTIAL}, {"C", A_COMPLETE}, }, [I] = { {"N", I_NONE}, {"P", I_PARTIAL}, {"C", I_COMPLETE}, }, [C] = { {"N", C_NONE}, {"P", C_PARTIAL}, {"C", C_COMPLETE}, }, [Au] = { {"N", Au_NONE}, {"M", Au_MULTIPLE_INSTANCES}, {"S", Au_SINGLE_INSTANCE}, }, [AV] = { {"N", AV_NETWORK}, {"A", AV_ADJACENT_NETWORK}, {"L", AV_LOCAL}, }, [AC] = { {"L", AC_LOW}, {"M", AC_MEDIUM}, {"H", AC_HIGH}, }, }; // CVSS 4.0 /** * @brief CVSS 4.0 metrics. */ typedef enum { // Base (11 metrics) CVSS4_AV, /**< Attack Vector */ CVSS4_AC, /**< Attack Complexity */ CVSS4_AT, /**< Attack Requirements */ CVSS4_PR, /**< Privileges Required */ CVSS4_UI, /**< User Interaction */ CVSS4_VC, /**< Confidentiality Impact to the Vulnerable System */ CVSS4_VI, /**< Integrity Impact to the Vulnerable System */ CVSS4_VA, /**< Availability Impact to the Vulnerable System */ CVSS4_SC, /**< Confidentiality Impact to the Subsequent System */ CVSS4_SI, /**< Integrity Impact to the Subsequent System */ CVSS4_SA, /**< Availability Impact to the Subsequent System */ // Threat (1 metric) CVSS4_E, /**< Exploit Maturity */ // Environmental (14 metrics) CVSS4_CR, /**< Confidentiality Requirement */ CVSS4_IR, /**< Integrity Requirement */ CVSS4_AR, /**< Availability Requirement */ CVSS4_MAV, /**< Modified Attack Vector */ CVSS4_MAC, /**< Modified Attack Complexity */ CVSS4_MAT, /**< Modified Attack Requirements */ CVSS4_MPR, /**< Modified Privileges Required */ CVSS4_MUI, /**< Modified User Interaction */ CVSS4_MVC, /**< Modified Confidentiality Impact to the Vulnerable System */ CVSS4_MVI, /**< Modified Integrity Impact to the Vulnerable System */ CVSS4_MVA, /**< Modified Availability Impact to the Vulnerable System */ CVSS4_MSC, /**< Modified Confidentiality Impact to the Subsequent System */ CVSS4_MSI, /**< Modified Integrity Impact to the Subsequent System */ CVSS4_MSA, /**< Modified Availability Impact to the Subsequent System */ // Supplemental (6 metrics) CVSS4_S, /**< Safety */ CVSS4_AU, /**< Automatable */ CVSS4_R, /**< Recovery */ CVSS4_V, /**< Value Density */ CVSS4_RE, /**< Vulnerability Response Effort */ CVSS4_U, /**< Provider Urgency */ // Maximum number CVSS4_METRICS_MAX, /**< Maximum number of metrics */ } cvss4_metric_t; /** * @brief Blank simplified CVSS 4.0 metrics string */ #define CVSS_METRICS_STR_BLANK "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /** * @brief Blank simplified CVSS 4.0 macrovector string */ #define CVSS_MACROVECTOR_BLANK "XXXXXX" /** * @brief String to enum mapping and allowed values for a CVSS 4.0 metric. * * This assumes all allowed values are single characters. * The Provider Urgency metric can be longer, so it needs special handling * only using the first letter. */ typedef struct { const char *metric_str; /**< The metric abbreviation string */ const cvss4_metric_t metric; /**< The metric enum value */ const char *values; /**< String of characters allowed as values */ } cvss4_metric_def_t; /** * @brief String to enum mappings and allowed values for CVSS 4.0 metrics. * * Notes: * - The Provider Urgency metric can be longer than one character, * so it needs special handling. * - The orginal specification only lists the value S (Safety) for the * modified metrics MSI and MSA, but the calculator reference implementation * also uses it for the unmodified ones, SI and SA. */ static cvss4_metric_def_t cvss4_metric_defs[] = { // Base (11 metrics) {"AV", CVSS4_AV, "NALP"}, {"AC", CVSS4_AC, "LH"}, {"AT", CVSS4_AT, "NP"}, {"PR", CVSS4_PR, "NLH"}, {"UI", CVSS4_UI, "NPA"}, {"VC", CVSS4_VC, "HLN"}, {"VI", CVSS4_VI, "HLN"}, {"VA", CVSS4_VA, "HLN"}, {"SC", CVSS4_SC, "HLN"}, {"SI", CVSS4_SI, "HLNS"}, {"SA", CVSS4_SA, "HLNS"}, // Threat (1 metric) {"E", CVSS4_E, "XAPU"}, // Environmental (14 metrics) {"CR", CVSS4_CR, "XHML"}, {"IR", CVSS4_IR, "XHML"}, {"AR", CVSS4_AR, "XHML"}, {"MAV", CVSS4_MAV, "XNALP"}, {"MAC", CVSS4_MAC, "XLH"}, {"MAT", CVSS4_MAT, "XNP"}, {"MPR", CVSS4_MPR, "XNLH"}, {"MUI", CVSS4_MUI, "XNPA"}, {"MVC", CVSS4_MVC, "XHLN"}, {"MVI", CVSS4_MVI, "XHLN"}, {"MVA", CVSS4_MVA, "XHLN"}, {"MSC", CVSS4_MSC, "XHLN"}, {"MSI", CVSS4_MSI, "XHLNS"}, {"MSA", CVSS4_MSA, "XHLNS"}, // Supplemental (6 metrics) {"S", CVSS4_S, "XNP"}, {"AU", CVSS4_AU, "XNY"}, {"R", CVSS4_R, "XAUI"}, {"V", CVSS4_V, "XDC"}, {"RE", CVSS4_RE, "XLMH"}, {"U", CVSS4_U, "XCGAR"}, // Abbreviated to first letters // Max number / array terminator {NULL, CVSS4_METRICS_MAX, NULL}}; /** * @brief Key-Value mappings of CVSS 4.0 macrovectors to scores. */ typedef struct { const char *vector; double score; } cvss4_macrovector_mapping_t; /** * @brief CVSS 4.0 macrovector mappings * * This list has been generated from the lookup table in the * FIRST CVSS calculator reference implementation at * https://github.com/FIRSTdotorg/cvss-v4-calculator/blob/main/cvss_lookup.js */ static const cvss4_macrovector_mapping_t cvss4_macrovector_mappings[] = { {"000000", 10}, {"000001", 9.9}, {"000010", 9.8}, {"000011", 9.5}, {"000020", 9.5}, {"000021", 9.2}, {"000100", 10}, {"000101", 9.6}, {"000110", 9.3}, {"000111", 8.7}, {"000120", 9.1}, {"000121", 8.1}, {"000200", 9.3}, {"000201", 9}, {"000210", 8.9}, {"000211", 8}, {"000220", 8.1}, {"000221", 6.8}, {"001000", 9.8}, {"001001", 9.5}, {"001010", 9.5}, {"001011", 9.2}, {"001020", 9}, {"001021", 8.4}, {"001100", 9.3}, {"001101", 9.2}, {"001110", 8.9}, {"001111", 8.1}, {"001120", 8.1}, {"001121", 6.5}, {"001200", 8.8}, {"001201", 8}, {"001210", 7.8}, {"001211", 7}, {"001220", 6.9}, {"001221", 4.8}, {"002001", 9.2}, {"002011", 8.2}, {"002021", 7.2}, {"002101", 7.9}, {"002111", 6.9}, {"002121", 5}, {"002201", 6.9}, {"002211", 5.5}, {"002221", 2.7}, {"010000", 9.9}, {"010001", 9.7}, {"010010", 9.5}, {"010011", 9.2}, {"010020", 9.2}, {"010021", 8.5}, {"010100", 9.5}, {"010101", 9.1}, {"010110", 9}, {"010111", 8.3}, {"010120", 8.4}, {"010121", 7.1}, {"010200", 9.2}, {"010201", 8.1}, {"010210", 8.2}, {"010211", 7.1}, {"010220", 7.2}, {"010221", 5.3}, {"011000", 9.5}, {"011001", 9.3}, {"011010", 9.2}, {"011011", 8.5}, {"011020", 8.5}, {"011021", 7.3}, {"011100", 9.2}, {"011101", 8.2}, {"011110", 8}, {"011111", 7.2}, {"011120", 7}, {"011121", 5.9}, {"011200", 8.4}, {"011201", 7}, {"011210", 7.1}, {"011211", 5.2}, {"011220", 5}, {"011221", 3}, {"012001", 8.6}, {"012011", 7.5}, {"012021", 5.2}, {"012101", 7.1}, {"012111", 5.2}, {"012121", 2.9}, {"012201", 6.3}, {"012211", 2.9}, {"012221", 1.7}, {"100000", 9.8}, {"100001", 9.5}, {"100010", 9.4}, {"100011", 8.7}, {"100020", 9.1}, {"100021", 8.1}, {"100100", 9.4}, {"100101", 8.9}, {"100110", 8.6}, {"100111", 7.4}, {"100120", 7.7}, {"100121", 6.4}, {"100200", 8.7}, {"100201", 7.5}, {"100210", 7.4}, {"100211", 6.3}, {"100220", 6.3}, {"100221", 4.9}, {"101000", 9.4}, {"101001", 8.9}, {"101010", 8.8}, {"101011", 7.7}, {"101020", 7.6}, {"101021", 6.7}, {"101100", 8.6}, {"101101", 7.6}, {"101110", 7.4}, {"101111", 5.8}, {"101120", 5.9}, {"101121", 5}, {"101200", 7.2}, {"101201", 5.7}, {"101210", 5.7}, {"101211", 5.2}, {"101220", 5.2}, {"101221", 2.5}, {"102001", 8.3}, {"102011", 7}, {"102021", 5.4}, {"102101", 6.5}, {"102111", 5.8}, {"102121", 2.6}, {"102201", 5.3}, {"102211", 2.1}, {"102221", 1.3}, {"110000", 9.5}, {"110001", 9}, {"110010", 8.8}, {"110011", 7.6}, {"110020", 7.6}, {"110021", 7}, {"110100", 9}, {"110101", 7.7}, {"110110", 7.5}, {"110111", 6.2}, {"110120", 6.1}, {"110121", 5.3}, {"110200", 7.7}, {"110201", 6.6}, {"110210", 6.8}, {"110211", 5.9}, {"110220", 5.2}, {"110221", 3}, {"111000", 8.9}, {"111001", 7.8}, {"111010", 7.6}, {"111011", 6.7}, {"111020", 6.2}, {"111021", 5.8}, {"111100", 7.4}, {"111101", 5.9}, {"111110", 5.7}, {"111111", 5.7}, {"111120", 4.7}, {"111121", 2.3}, {"111200", 6.1}, {"111201", 5.2}, {"111210", 5.7}, {"111211", 2.9}, {"111220", 2.4}, {"111221", 1.6}, {"112001", 7.1}, {"112011", 5.9}, {"112021", 3}, {"112101", 5.8}, {"112111", 2.6}, {"112121", 1.5}, {"112201", 2.3}, {"112211", 1.3}, {"112221", 0.6}, {"200000", 9.3}, {"200001", 8.7}, {"200010", 8.6}, {"200011", 7.2}, {"200020", 7.5}, {"200021", 5.8}, {"200100", 8.6}, {"200101", 7.4}, {"200110", 7.4}, {"200111", 6.1}, {"200120", 5.6}, {"200121", 3.4}, {"200200", 7}, {"200201", 5.4}, {"200210", 5.2}, {"200211", 4}, {"200220", 4}, {"200221", 2.2}, {"201000", 8.5}, {"201001", 7.5}, {"201010", 7.4}, {"201011", 5.5}, {"201020", 6.2}, {"201021", 5.1}, {"201100", 7.2}, {"201101", 5.7}, {"201110", 5.5}, {"201111", 4.1}, {"201120", 4.6}, {"201121", 1.9}, {"201200", 5.3}, {"201201", 3.6}, {"201210", 3.4}, {"201211", 1.9}, {"201220", 1.9}, {"201221", 0.8}, {"202001", 6.4}, {"202011", 5.1}, {"202021", 2}, {"202101", 4.7}, {"202111", 2.1}, {"202121", 1.1}, {"202201", 2.4}, {"202211", 0.9}, {"202221", 0.4}, {"210000", 8.8}, {"210001", 7.5}, {"210010", 7.3}, {"210011", 5.3}, {"210020", 6}, {"210021", 5}, {"210100", 7.3}, {"210101", 5.5}, {"210110", 5.9}, {"210111", 4}, {"210120", 4.1}, {"210121", 2}, {"210200", 5.4}, {"210201", 4.3}, {"210210", 4.5}, {"210211", 2.2}, {"210220", 2}, {"210221", 1.1}, {"211000", 7.5}, {"211001", 5.5}, {"211010", 5.8}, {"211011", 4.5}, {"211020", 4}, {"211021", 2.1}, {"211100", 6.1}, {"211101", 5.1}, {"211110", 4.8}, {"211111", 1.8}, {"211120", 2}, {"211121", 0.9}, {"211200", 4.6}, {"211201", 1.8}, {"211210", 1.7}, {"211211", 0.7}, {"211220", 0.8}, {"211221", 0.2}, {"212001", 5.3}, {"212011", 2.4}, {"212021", 1.4}, {"212101", 2.4}, {"212111", 1.2}, {"212121", 0.5}, {"212201", 1}, {"212211", 0.3}, {"212221", 0.1}, {NULL, 0.0}}; /** * @brief Hashtable for quick lookup of CVSS macrovector scores. * * Macrovector scores should be looked up with cvss4_macrovector_score * which ensures the table is initialized and returns the scores as * double values instead of pointers. */ static GHashTable *cvss4_macrovector_table = NULL; /** * @brief Determine base metric enumeration from a string. * * @param[in] str Base metric in string form, for example "A". * @param[out] res Where to write the desired value. * * @return 0 on success, -1 on error. */ static int toenum (const char *str, enum base_metrics *res) { int rc = 0; /* let's be optimistic */ if (g_strcmp0 (str, "A") == 0) *res = A; else if (g_strcmp0 (str, "I") == 0) *res = I; else if (g_strcmp0 (str, "C") == 0) *res = C; else if (g_strcmp0 (str, "Au") == 0) *res = Au; else if (g_strcmp0 (str, "AU") == 0) *res = Au; else if (g_strcmp0 (str, "AV") == 0) *res = AV; else if (g_strcmp0 (str, "AC") == 0) *res = AC; else rc = -1; return rc; } /** * @brief Calculate Impact Sub Score. * * @param[in] cvss Contains the subscores associated * to the metrics. * * @return The resulting subscore. */ static double get_impact_subscore (const struct cvss *cvss) { return 10.41 * (1 - (1 - cvss->conf_impact) * (1 - cvss->integ_impact) * (1 - cvss->avail_impact)); } /** * @brief Calculate Exploitability Sub Score. * * @param[in] cvss Contains the subscores associated * to the metrics. * * @return The resulting subscore. */ static double get_exploitability_subscore (const struct cvss *cvss) { return 20 * cvss->access_vector * cvss->access_complexity * cvss->authentication; } /** * @brief Set impact score from string representation. * * @param[in] value The literal value associated to the metric. * @param[in] metric The enumeration constant identifying the metric. * @param[out] cvss The structure to update with the score. * * @return 0 on success, -1 on error. */ static inline int set_impact_from_str (const char *value, enum base_metrics metric, struct cvss *cvss) { int i; for (i = 0; i < 3; i++) { const struct impact_item *impact; impact = &impact_map[metric][i]; if (g_strcmp0 (impact->name, value) == 0) { switch (metric) { case A: cvss->avail_impact = impact->nvalue; break; case I: cvss->integ_impact = impact->nvalue; break; case C: cvss->conf_impact = impact->nvalue; break; case Au: cvss->authentication = impact->nvalue; break; case AV: cvss->access_vector = impact->nvalue; break; case AC: cvss->access_complexity = impact->nvalue; break; default: return -1; } return 0; } } return -1; } /** * @brief Final CVSS score computation helper. * * @param[in] cvss The CVSS structure that contains the * different metrics and associated scores. * * @return the CVSS score, as a double. */ static double __get_cvss_score (struct cvss *cvss) { double impact = 1.176; double impact_sub; double exploitability_sub; impact_sub = get_impact_subscore (cvss); exploitability_sub = get_exploitability_subscore (cvss); if (impact_sub < 0.1) impact = 0.0; return (((0.6 * impact_sub) + (0.4 * exploitability_sub) - 1.5) * impact) + 0.0; } /** * @brief Calculate CVSS Score. * * @param cvss_str Base vector string from which to compute score. * * @return The resulting score. -1 upon error during parsing. */ double get_cvss_score_from_base_metrics (const char *cvss_str) { struct cvss cvss; char *token, *base_str, *base_metrics; if (cvss_str == NULL) return -1.0; if (g_str_has_prefix (cvss_str, "CVSS:3.1/") || g_str_has_prefix (cvss_str, "CVSS:3.0/")) return get_cvss_score_from_base_metrics_v3 (cvss_str + strlen ("CVSS:3.X/")); if (g_str_has_prefix (cvss_str, "CVSS:4.0/")) return get_cvss_score_from_metrics_v4 (cvss_str + strlen ("CVSS:4.X/")); memset (&cvss, 0x00, sizeof (struct cvss)); base_str = base_metrics = g_strdup_printf ("%s/", cvss_str); while ((token = strchr (base_metrics, '/')) != NULL) { char *token2 = strtok (base_metrics, ":"); char *metric_name = token2; char *metric_value; enum base_metrics mval; int rc; *token++ = '\0'; if (metric_name == NULL) goto ret_err; metric_value = strtok (NULL, ":"); if (metric_value == NULL) goto ret_err; rc = toenum (metric_name, &mval); if (rc) goto ret_err; if (set_impact_from_str (metric_value, mval, &cvss)) goto ret_err; base_metrics = token; } g_free (base_str); return __get_cvss_score (&cvss); ret_err: g_free (base_str); return (double) -1; } /* CVSS v3. */ /** * @brief Round final score as in spec. * * @param cvss CVSS score. * * @return Rounded score. */ static double roundup (double cvss) { int trim; /* "Roundup returns the smallest number, specified to 1 decimal place, * that is equal to or higher than its input. For example, Roundup (4.02) * returns 4.1; and Roundup (4.00) returns 4.0." */ /* 3.020000000 => 3.1 */ /* 3.000000001 => 3.0 */ /* 5.299996 => 5.3 */ /* 5.500320 => 5.6 */ trim = round (cvss * 100000); if ((trim % 10000) == 0) return ((double) trim) / 100000; return (floor (trim / 10000) + 1) / 10.0; } /** * @brief Get impact. * * @param value Metric value. * * @return Impact. */ static double v3_impact (const char *value) { if (strcasecmp (value, "N") == 0) return 0.0; if (strcasecmp (value, "L") == 0) return 0.22; if (strcasecmp (value, "H") == 0) return 0.56; return -1.0; } /** * @brief Calculate CVSS Score. * * @param cvss_str Vector from which to compute score, without prefix. * * @return CVSS score, or -1 on error. */ static double get_cvss_score_from_base_metrics_v3 (const char *cvss_str) { gchar **split, **point; int scope_changed; double impact_conf, impact_integ, impact_avail; double vector, complexity, privilege, user; double isc_base, impact, exploitability, base; /* https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator * https://www.first.org/cvss/v3.1/specification-document * https://www.first.org/cvss/v3.0/specification-document */ scope_changed = -1; impact_conf = -1.0; impact_integ = -1.0; impact_avail = -1.0; vector = -1.0; complexity = -1.0; privilege = -1.0; user = -1.0; /* AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N */ split = g_strsplit (cvss_str, "/", 0); point = split; while (*point) { /* Scope. */ if (strncasecmp ("S:", *point, 2) == 0) { if (strcasecmp (*point + 2, "U") == 0) scope_changed = 0; else if (strcasecmp (*point + 2, "C") == 0) scope_changed = 1; } /* Confidentiality. */ if (strncasecmp ("C:", *point, 2) == 0) impact_conf = v3_impact (*point + 2); /* Integrity. */ if (strncasecmp ("I:", *point, 2) == 0) impact_integ = v3_impact (*point + 2); /* Availability. */ if (strncasecmp ("A:", *point, 2) == 0) impact_avail = v3_impact (*point + 2); /* Attack Vector. */ if (strncasecmp ("AV:", *point, 3) == 0) { if (strcasecmp (*point + 3, "N") == 0) vector = 0.85; else if (strcasecmp (*point + 3, "A") == 0) vector = 0.62; else if (strcasecmp (*point + 3, "L") == 0) vector = 0.55; else if (strcasecmp (*point + 3, "P") == 0) vector = 0.2; } /* Attack Complexity. */ if (strncasecmp ("AC:", *point, 3) == 0) { if (strcasecmp (*point + 3, "L") == 0) complexity = 0.77; else if (strcasecmp (*point + 3, "H") == 0) complexity = 0.44; } /* Privileges Required. */ if (strncasecmp ("PR:", *point, 3) == 0) { if (strcasecmp (*point + 3, "N") == 0) privilege = 0.85; else if (strcasecmp (*point + 3, "L") == 0) privilege = 0.62; else if (strcasecmp (*point + 3, "H") == 0) privilege = 0.27; else privilege = -1.0; } /* User Interaction. */ if (strncasecmp ("UI:", *point, 3) == 0) { if (strcasecmp (*point + 3, "N") == 0) user = 0.85; else if (strcasecmp (*point + 3, "R") == 0) user = 0.62; } point++; } g_strfreev (split); /* All of the base metrics are required. */ if (scope_changed == -1 || impact_conf == -1.0 || impact_integ == -1.0 || impact_avail == -1.0 || vector == -1.0 || complexity == -1.0 || privilege == -1.0 || user == -1.0) return -1.0; /* Privileges Required has a special case for S:C. */ if (scope_changed && privilege == 0.62) privilege = 0.68; else if (scope_changed && privilege == 0.27) privilege = 0.5; /* Impact. */ isc_base = 1 - ((1 - impact_conf) * (1 - impact_integ) * (1 - impact_avail)); if (scope_changed) impact = 7.52 * (isc_base - 0.029) - 3.25 * pow ((isc_base - 0.02), 15); else impact = 6.42 * isc_base; if (impact <= 0) return 0.0; /* Exploitability. */ exploitability = 8.22 * vector * complexity * privilege * user; /* Final. */ if (scope_changed) base = 1.08 * (impact + exploitability); else base = impact + exploitability; if (base > 10.0) return 10.0; return roundup (base); } /** * @brief Initialize the CVSS 4.0 macrovector lookup table. */ static void cvss4_init_macrovector_table () { if (cvss4_macrovector_table) return; int index = 0; cvss4_macrovector_table = g_hash_table_new (g_str_hash, g_str_equal); while (cvss4_macrovector_mappings[index].vector != NULL) { g_hash_table_insert (cvss4_macrovector_table, (gpointer) cvss4_macrovector_mappings[index].vector, (gpointer) &cvss4_macrovector_mappings[index].score); index++; } } /** * @brief Get the CVSS 4.0 score for a given macrovector string. * * @param[in] vector The macrovector to look up. * * @return The score of the given vector or -1.0 if the macrovector is invalid. */ static inline double cvss4_macrovector_score (const char *vector) { double *score_ptr; cvss4_init_macrovector_table (); score_ptr = g_hash_table_lookup (cvss4_macrovector_table, vector); if (score_ptr) return *score_ptr; return -1.0; } /** * @brief Get the effective value of a metric in a simplified CVSS4 vector. * * As this only returns the first character, the Provider Urgency metric * (CVSS4_U) needs special handling to get the full string. * * @param[in] simplified_vec The simplified vector string to get value from. * @param[in] metric The metric to get the value of. * * @return The metric value as a single character. */ static char cvss4_m (const char *simplified_vec, cvss4_metric_t metric) { char selected = simplified_vec[metric]; // If E=X it will default to the worst case i.e. E=A if (metric == CVSS4_E && selected == 'X') return 'A'; // If CR=X, IR=X or AR=X they will default to the worst case // i.e. CR=H, IR=H and AR=H if ((metric == CVSS4_CR || metric == CVSS4_IR || metric == CVSS4_AR) && selected == 'X') return 'H'; // All other environmental metrics just overwrite base score values, // so if they’re not defined just use the base score value. if (metric >= CVSS4_AV && metric <= CVSS4_SA) { char modified_selected = simplified_vec[metric - CVSS4_AV + CVSS4_MAV]; if (modified_selected != 'X') return modified_selected; } return selected; } /** * @brief Simplify CVSS 4.0 base vector so metrics can be indexed by enum. * * The vector is simplified to a strictly ordered character array with * each character index corresponding to the cvss4_base_metrics enum value * and using 'X' for undefined metric values. * * This relies on all allowed values being single characters, or having * unique first characters in case of the Provider Urgency metric. * * @param[in] cvss_str The original vector without the prefix "CVSS:4.0/". * * @return A simplified vector string as described above or NULL on error. */ static gchar * simplify_cvss4_vector (const char *cvss_str) { gchar **split_cvss_str, **split_cvss_point; gboolean valid = TRUE; gchar *vec = NULL; cvss4_metric_t metric; if (cvss_str == NULL || strcmp (cvss_str, "") == 0) return NULL; vec = g_strdup (CVSS_METRICS_STR_BLANK); split_cvss_str = g_strsplit (cvss_str, "/", -1); split_cvss_point = split_cvss_str; while (valid && *split_cvss_point) { if (strcmp (*split_cvss_point, "") == 0) { split_cvss_point++; continue; } gchar **split_component = g_strsplit (*split_cvss_point, ":", 2); const gchar *metric_str = split_component[0], *value = split_component[1]; valid = FALSE; if (value == NULL) { g_debug ("%s: value for metric %s missing", __func__, metric_str); break; } else if (strcasecmp (metric_str, "U") == 0) { // Special case for the Provider Urgency metric if (strcasecmp (value, "Red") && strcasecmp (value, "Amber") && strcasecmp (value, "Green") && strcasecmp (value, "Clear") && strcasecmp (value, "X")) { g_debug ("%s: value for metric %s must be one of" " 'Red', 'Amber', 'Green', 'Clear', 'X'", __func__, metric_str); break; } else valid = TRUE; } else if (strlen (value) != 1) { g_debug ("%s: value for metric %s must be 1 character", __func__, metric_str); break; } cvss4_metric_def_t *metric_def = &cvss4_metric_defs[0]; while (metric_def->metric_str) { if (strcasecmp (metric_str, metric_def->metric_str) == 0) { char value_char = g_ascii_toupper (value[0]); // Reject duplicate metrics if (vec[metric_def->metric] != 'X') { g_debug ("%s: duplicate metric %s", __func__, metric_str); break; } // Set the metric in the simplified vector if (strchr (metric_def->values, value_char)) { valid = TRUE; vec[metric_def->metric] = value_char; } else { g_debug ("%s: invalid metric: %s:%c", __func__, metric_str, value_char); } break; } metric_def++; } split_cvss_point++; g_strfreev (split_component); } g_strfreev (split_cvss_str); for (metric = CVSS4_AV; valid && metric <= CVSS4_SA; metric++) { if (vec[metric] == 'X') { g_debug ("%s: mandatory metric %s is undefined", __func__, cvss4_metric_defs[metric].metric_str); valid = FALSE; } } if (!valid) { g_debug ("%s: vector %s is invalid", __func__, cvss_str); g_free (vec); return NULL; } return vec; } /** * @brief Expands a simplified CVSS 4.0 vector into its full string form * * @param[in] vec The simplified vector to expand * * @return The full vector, including the "CVSS:4.0/" prefix */ static gchar * cvss4_vector_expand (const char *vec) { cvss4_metric_t metric; GString *str = g_string_new ("CVSS:4.0"); for (metric = 0; metric < CVSS4_METRICS_MAX; metric++) { const char *expanded_value; if (vec[metric] == 'X') continue; cvss4_metric_def_t def = cvss4_metric_defs[metric]; if (metric == CVSS4_U) { switch (vec[metric]) { case 'R': expanded_value = "Red"; break; case 'A': expanded_value = "Amber"; break; case 'G': expanded_value = "Green"; break; case 'C': expanded_value = "Clear"; break; default: expanded_value = NULL; } } else expanded_value = NULL; if (expanded_value) g_string_append_printf (str, "/%s:%s", def.metric_str, expanded_value); else g_string_append_printf (str, "/%s:%c", def.metric_str, vec[metric]); } return g_string_free (str, FALSE); } /** * @brief Calculate CVSS 4.0 macrovector from a simplified vector. * * @param[in] vec The simplified vector to get the macrovector of * * @return The macrovector. */ static inline gchar * cvss4_macrovector (const char *vec) { gchar *macrovector; if (vec == NULL) return NULL; macrovector = g_strdup (CVSS_MACROVECTOR_BLANK); // EQ1: 0-AV:N and PR:N and UI:N // 1-(AV:N or PR:N or UI:N) and not (AV:N and PR:N and UI:N) and not AV:P // 2-AV:P or not(AV:N or PR:N or UI:N) char av = cvss4_m (vec, CVSS4_AV); char pr = cvss4_m (vec, CVSS4_PR); char ui = cvss4_m (vec, CVSS4_UI); if (av == 'N' && pr == 'N' && ui == 'N') macrovector[0] = '0'; else if ((av == 'N' || pr == 'N' || ui == 'N') && !(av == 'P')) macrovector[0] = '1'; else macrovector[0] = '2'; // EQ2: 0-(AC:L and AT:N) // 1-(not(AC:L and AT:N)) char ac = cvss4_m (vec, CVSS4_AC); char at = cvss4_m (vec, CVSS4_AT); if (ac == 'L' && at == 'N') macrovector[1] = '0'; else macrovector[1] = '1'; // EQ3: 0-(VC:H and VI:H) // 1-(not(VC:H and VI:H) and (VC:H or VI:H or VA:H)) // 2-not (VC:H or VI:H or VA:H) char vc = cvss4_m (vec, CVSS4_VC); char vi = cvss4_m (vec, CVSS4_VI); char va = cvss4_m (vec, CVSS4_VA); if (vc == 'H' && vi == 'H') macrovector[2] = '0'; else if (vc == 'H' || vi == 'H' || va == 'H') macrovector[2] = '1'; else macrovector[2] = '2'; // EQ4: 0-(MSI:S or MSA:S) // 1-not (MSI:S or MSA:S) and (SC:H or SI:H or SA:H) // 2-not (MSI:S or MSA:S) and not (SC:H or SI:H or SA:H) // // "Effective" SI and SA are the same as MSI and MSA for the purposes of // checking for the "Safety" value. char sc = cvss4_m (vec, CVSS4_SC); char si = cvss4_m (vec, CVSS4_SI); char sa = cvss4_m (vec, CVSS4_SA); if (si == 'S' || sa == 'S') macrovector[3] = '0'; else if (sc == 'H' || si == 'H' || sa == 'H') macrovector[3] = '1'; else macrovector[3] = '2'; // EQ5: 0-E:A // 1-E:P // 2-E:U char e = cvss4_m (vec, CVSS4_E); if (e == 'A') macrovector[4] = '0'; else if (e == 'P') macrovector[4] = '1'; else macrovector[4] = '2'; // EQ6: 0-(CR:H and VC:H) or (IR:H and VI:H) or (AR:H and VA:H) // 1-not[(CR:H and VC:H) or (IR:H and VI:H) or (AR:H and VA:H)] char cr = cvss4_m (vec, CVSS4_CR); char ir = cvss4_m (vec, CVSS4_IR); char ar = cvss4_m (vec, CVSS4_AR); if ((cr == 'H' && vc == 'H') || (ir == 'H' && vi == 'H') || (ar == 'H' && va == 'H')) macrovector[5] = '0'; else macrovector[5] = '1'; return macrovector; } /** * @brief Calulate the maximal scoring differences from a CVSS 4.0 macrovector. * * @param[in] macrovector * @param[out] available_distance_eq1 Maximal scoring diff. for EQ1 * @param[out] available_distance_eq2 Maximal scoring diff. for EQ2 * @param[out] available_distance_eq3eq6 Maximal scoring diff. for EQ3 and EQ6 * @param[out] available_distance_eq4 Maximal scoring diff. for EQ4 * @param[out] available_distance_eq5 Maximal scoring diff. for EQ5 */ static void cvss4_maximal_scoring_differences (const char *macrovector, double *available_distance_eq1, double *available_distance_eq2, double *available_distance_eq3eq6, double *available_distance_eq4, double *available_distance_eq5) { double value = cvss4_macrovector_score (macrovector); double score_eq1_next_lower_macro, score_eq2_next_lower_macro; double score_eq3eq6_next_lower_macro; double score_eq4_next_lower_macro, score_eq5_next_lower_macro; // Next lower macrovector for EQ1 only exists if EQ1 is 0 or 1. if (macrovector[0] <= '1') { gchar *eq1_next_lower_macro = g_strdup (macrovector); eq1_next_lower_macro[0]++; score_eq1_next_lower_macro = cvss4_macrovector_score (eq1_next_lower_macro); g_free (eq1_next_lower_macro); } else score_eq1_next_lower_macro = -1.0; // Next lower macrovector for EQ2 only exists if EQ2 is 0. if (macrovector[1] == '0') { gchar *eq2_next_lower_macro = g_strdup (macrovector); eq2_next_lower_macro[1]++; score_eq2_next_lower_macro = cvss4_macrovector_score (eq2_next_lower_macro); } else score_eq2_next_lower_macro = -1.0; // Next lower macrovector for EQ3. if ((macrovector[2] == '0' || macrovector[2] == '1') && macrovector[5] == '1') { gchar *eq3eq6_next_lower_macro = g_strdup (macrovector); eq3eq6_next_lower_macro[2]++; score_eq3eq6_next_lower_macro = cvss4_macrovector_score (eq3eq6_next_lower_macro); g_free (eq3eq6_next_lower_macro); } else if (macrovector[2] == '1' && macrovector[5] == '0') { gchar *eq3eq6_next_lower_macro = g_strdup (macrovector); eq3eq6_next_lower_macro[5]++; score_eq3eq6_next_lower_macro = cvss4_macrovector_score (eq3eq6_next_lower_macro); g_free (eq3eq6_next_lower_macro); } else if (macrovector[2] == '0' && macrovector[5] == '0') { gchar *eq3eq6_next_lower_macro_left = g_strdup (macrovector); eq3eq6_next_lower_macro_left[5]++; gchar *eq3eq6_next_lower_macro_right = g_strdup (macrovector); eq3eq6_next_lower_macro_right[2]++; double score_eq3eq6_next_lower_macro_left = cvss4_macrovector_score (eq3eq6_next_lower_macro_left); double score_eq3eq6_next_lower_macro_right = cvss4_macrovector_score (eq3eq6_next_lower_macro_right); if (score_eq3eq6_next_lower_macro_left > score_eq3eq6_next_lower_macro_right) score_eq3eq6_next_lower_macro = score_eq3eq6_next_lower_macro_left; else score_eq3eq6_next_lower_macro = score_eq3eq6_next_lower_macro_right; g_free (eq3eq6_next_lower_macro_left); g_free (eq3eq6_next_lower_macro_right); } else score_eq3eq6_next_lower_macro = -1.0; // Next lower macrovector for EQ4 only exists if EQ4 is 0 or 1. if (macrovector[3] <= '1') { gchar *eq4_next_lower_macro = g_strdup (macrovector); eq4_next_lower_macro[3]++; score_eq4_next_lower_macro = cvss4_macrovector_score (eq4_next_lower_macro); g_free (eq4_next_lower_macro); } else score_eq4_next_lower_macro = -1.0; // Next lower macrovector for EQ5 only exists if EQ5 is 0 or 1. if (macrovector[4] <= '1') { gchar *eq5_next_lower_macro = g_strdup (macrovector); eq5_next_lower_macro[4]++; score_eq5_next_lower_macro = cvss4_macrovector_score (eq5_next_lower_macro); g_free (eq5_next_lower_macro); } else score_eq5_next_lower_macro = -1.0; if (value != -1.0) { *available_distance_eq1 = score_eq1_next_lower_macro != -1.0 ? value - score_eq1_next_lower_macro : -1.0; *available_distance_eq2 = score_eq2_next_lower_macro != -1.0 ? value - score_eq2_next_lower_macro : -1.0; *available_distance_eq3eq6 = score_eq3eq6_next_lower_macro != -1.0 ? value - score_eq3eq6_next_lower_macro : -1.0; *available_distance_eq4 = score_eq4_next_lower_macro != -1.0 ? value - score_eq4_next_lower_macro : -1.0; *available_distance_eq5 = score_eq5_next_lower_macro != -1.0 ? value - score_eq5_next_lower_macro : -1.0; } else { *available_distance_eq1 = -1.0; *available_distance_eq2 = -1.0; *available_distance_eq3eq6 = -1.0; *available_distance_eq4 = -1.0; *available_distance_eq5 = -1.0; } } /** * @brief Composes a list of max vectors for the given CVSS 4.0 macrovector. * * @param[in] macrovector The macrovector to get the max vectors of. * * @return NULL-terminated array of vectors in simplified form. */ static gchar ** cvss4_max_vectors (const char *macrovector) { const char **eq1_maxes, **eq2_maxes, **eq3eq6_maxes; const char *eq4_max, *eq5_max; gchar **ret; // EQ1 static const char *eq1_maxes_0[] = {"AV:N/PR:N/UI:N/", NULL}; static const char *eq1_maxes_1[] = {"AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/", "AV:N/PR:N/UI:P/", NULL}; static const char *eq1_maxes_2[] = {"AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/", NULL}; if (macrovector[0] == '0') eq1_maxes = eq1_maxes_0; else if (macrovector[0] == '1') eq1_maxes = eq1_maxes_1; else eq1_maxes = eq1_maxes_2; // EQ2 static const char *eq2_maxes_0[] = {"AC:L/AT:N/", NULL}; static const char *eq2_maxes_1[] = {"AC:H/AT:N/", "AC:L/AT:P/", NULL}; if (macrovector[1] == '0') eq2_maxes = eq2_maxes_0; else eq2_maxes = eq2_maxes_1; // EQ3+EQ6 static const char *eq3eq6_maxes_00[] = {"VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/", NULL}; static const char *eq3eq6_maxes_01[] = { "VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/", "VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/", NULL}; static const char *eq3eq6_maxes_10[] = { "VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/", "VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/", NULL}; static const char *eq3eq6_maxes_11[] = { "VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/", "VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/", "VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/", "VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/", "VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/", NULL}; static const char *eq3eq6_maxes_21[] = {"VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/", NULL}; if ((macrovector[2] == '0')) { if (macrovector[5] == '0') eq3eq6_maxes = eq3eq6_maxes_00; else eq3eq6_maxes = eq3eq6_maxes_01; } else if ((macrovector[2] == '1')) { if (macrovector[5] == '0') eq3eq6_maxes = eq3eq6_maxes_10; else eq3eq6_maxes = eq3eq6_maxes_11; } else eq3eq6_maxes = eq3eq6_maxes_21; // EQ4 if (macrovector[3] == '0') eq4_max = "SC:H/SI:S/SA:S/"; else if (macrovector[3] == '1') eq4_max = "SC:H/SI:H/SA:H/"; else eq4_max = "SC:L/SI:L/SA:L/"; // EQ5 if (macrovector[4] == '0') eq5_max = "E:A/"; else if (macrovector[4] == '1') eq5_max = "E:P/"; else eq5_max = "E:U/"; GPtrArray *max_vectors = g_ptr_array_new (); const char **eq1_max, **eq2_max, **eq3eq6_max; for (eq1_max = eq1_maxes; *eq1_max != NULL; eq1_max++) { for (eq2_max = eq2_maxes; *eq2_max != NULL; eq2_max++) { for (eq3eq6_max = eq3eq6_maxes; *eq3eq6_max != NULL; eq3eq6_max++) { gchar *full_vector = g_strdup_printf ("%s%s%s%s%s", *eq1_max, *eq2_max, *eq3eq6_max, eq4_max, eq5_max); gchar *vector = simplify_cvss4_vector (full_vector); if (vector == NULL) g_warning ("%s: generated vector %s is invalid", __func__, full_vector); else g_ptr_array_add (max_vectors, vector); g_free (full_vector); } } } g_ptr_array_add (max_vectors, NULL); ret = (gchar **) max_vectors->pdata; g_ptr_array_free (max_vectors, FALSE); return ret; } /** * @brief Get the index of a CVSS 4.0 metric value for severity distances. * * @param[in] metric The metric to check. * @param[in] value The value of the given metric. * * @return The index value */ static double cvss4_metric_level (cvss4_metric_t metric, char value) { switch (metric) { case CVSS4_AV: switch (value) { case 'N': return 0.0; case 'A': return 0.1; case 'L': return 0.2; case 'P': return 0.3; default: return -99.0; } break; case CVSS4_PR: switch (value) { case 'N': return 0.0; case 'L': return 0.1; case 'H': return 0.2; default: return -99.0; } break; case CVSS4_UI: switch (value) { case 'N': return 0.0; case 'P': return 0.1; case 'A': return 0.2; default: return -99.0; } break; case CVSS4_AC: switch (value) { case 'L': return 0.0; case 'H': return 0.1; default: return -99.0; } break; case CVSS4_AT: switch (value) { case 'N': return 0.0; case 'P': return 0.1; default: return -99.0; } break; case CVSS4_VC: case CVSS4_VI: case CVSS4_VA: switch (value) { case 'H': return 0.0; case 'L': return 0.1; case 'N': return 0.2; default: return -99.0; } break; case CVSS4_SC: case CVSS4_SI: case CVSS4_SA: switch (value) { case 'S': return 0.0; case 'H': return 0.1; case 'L': return 0.2; case 'N': return 0.3; default: return -99.0; } break; case CVSS4_CR: case CVSS4_IR: case CVSS4_AR: switch (value) { case 'H': return 0.0; case 'M': return 0.1; case 'L': return 0.2; default: return -99.0; } break; // The Exploit Maturity metric is included in the reference implementation // but never used /* case CVSS4_E: switch (value) { case 'A': return 0.0; case 'P': return 0.1; case 'U': return 0.2; } break; */ default: return -99.0; } } /** * @brief Calculate severity distance for a metric in two CVSS 4.0 vectors. * * @param[in] metric The metric to calculate severity distance for. * @param[in] vec The vector to be scored in simplified form. * @param[in] max_vec The max vector to subtract in simplified form. * * @return The severity distance. */ static inline double cvss4_severity_distance (cvss4_metric_t metric, const char *vec, const char *max_vec) { return cvss4_metric_level (metric, cvss4_m (vec, metric)) - cvss4_metric_level (metric, max_vec[metric]); } /** * @brief Calculate current severity distances for given CVSS 4.0 vector * * @param[in] vec The vector in simplified form * @param[in] macrovector Corresponding macrovector * @param[out] current_severity_distance_eq1 Distance for EQ1 * @param[out] current_severity_distance_eq2 Distance for EQ2 * @param[out] current_severity_distance_eq3eq6 Distance for EQ3 and EQ6 * @param[out] current_severity_distance_eq4 Distance for EQ4 * @param[out] current_severity_distance_eq5 Distance for EQ5 */ static void cvss4_current_severity_distances (const char *vec, const char *macrovector, double *current_severity_distance_eq1, double *current_severity_distance_eq2, double *current_severity_distance_eq3eq6, double *current_severity_distance_eq4, double *current_severity_distance_eq5) { double severity_distance_AV, severity_distance_PR, severity_distance_UI; double severity_distance_AC, severity_distance_AT; double severity_distance_VC, severity_distance_VI, severity_distance_VA; double severity_distance_SC, severity_distance_SI, severity_distance_SA; double severity_distance_CR, severity_distance_IR, severity_distance_AR; severity_distance_AV = severity_distance_PR = severity_distance_UI = -99.0; severity_distance_AC = severity_distance_AT = -99.0; severity_distance_VC = severity_distance_VI = severity_distance_VA = -99.0; severity_distance_SC = severity_distance_SI = severity_distance_SA = -99.0; severity_distance_CR = severity_distance_IR = severity_distance_AR = -99.0; char **max_vectors, **max_vec; max_vectors = cvss4_max_vectors (macrovector); for (max_vec = max_vectors; *max_vec != NULL; max_vec++) { severity_distance_AV = cvss4_severity_distance (CVSS4_AV, vec, *max_vec); severity_distance_PR = cvss4_severity_distance (CVSS4_PR, vec, *max_vec); severity_distance_UI = cvss4_severity_distance (CVSS4_UI, vec, *max_vec); severity_distance_AC = cvss4_severity_distance (CVSS4_AC, vec, *max_vec); severity_distance_AT = cvss4_severity_distance (CVSS4_AT, vec, *max_vec); severity_distance_VC = cvss4_severity_distance (CVSS4_VC, vec, *max_vec); severity_distance_VI = cvss4_severity_distance (CVSS4_VI, vec, *max_vec); severity_distance_VA = cvss4_severity_distance (CVSS4_VA, vec, *max_vec); severity_distance_SC = cvss4_severity_distance (CVSS4_SC, vec, *max_vec); severity_distance_SI = cvss4_severity_distance (CVSS4_SI, vec, *max_vec); severity_distance_SA = cvss4_severity_distance (CVSS4_SA, vec, *max_vec); severity_distance_CR = cvss4_severity_distance (CVSS4_CR, vec, *max_vec); severity_distance_IR = cvss4_severity_distance (CVSS4_IR, vec, *max_vec); severity_distance_AR = cvss4_severity_distance (CVSS4_AR, vec, *max_vec); if (severity_distance_AV < 0.0 || severity_distance_PR < 0.0 || severity_distance_UI < 0.0 || severity_distance_AC < 0.0 || severity_distance_AT < 0.0 || severity_distance_VC < 0.0 || severity_distance_VI < 0.0 || severity_distance_VA < 0.0 || severity_distance_SC < 0.0 || severity_distance_SI < 0.0 || severity_distance_SA < 0.0 || severity_distance_CR < 0.0 || severity_distance_IR < 0.0 || severity_distance_AR < 0.0) continue; g_debug ("%s AV:%0.1f PR:%0.1f UI:%0.1f |" " AC:%0.1f AT:%0.1f |" " VC:%0.1f VI:%0.1f VA:%0.1f |" " SC:%0.1f SI:%0.1f SA:%0.1f |" " CR:%0.1f IR:%0.1f AR:%0.1f", __func__, severity_distance_AV, severity_distance_PR, severity_distance_UI, severity_distance_AC, severity_distance_AT, severity_distance_VC, severity_distance_VI, severity_distance_VA, severity_distance_SC, severity_distance_SI, severity_distance_SA, severity_distance_CR, severity_distance_IR, severity_distance_AR); break; } gchar *max_vec_expanded = cvss4_vector_expand (*max_vec); g_debug ("%s: max_vec: %s", __func__, max_vec_expanded); g_free (max_vec_expanded); g_strfreev (max_vectors); *current_severity_distance_eq1 = severity_distance_AV + severity_distance_PR + severity_distance_UI; *current_severity_distance_eq2 = severity_distance_AC + severity_distance_AT; *current_severity_distance_eq3eq6 = severity_distance_VC + severity_distance_VI + severity_distance_VA + severity_distance_CR + severity_distance_IR + severity_distance_AR; *current_severity_distance_eq4 = severity_distance_SC + severity_distance_SI + severity_distance_SA; *current_severity_distance_eq5 = 0.0; } /** * @brief Get the max severity values for a CVSS 4.0 macrovector * * The values are the MaxSeverity values already multiplied by 0.1 * * @param[in] macrovector The macrovector to get the max severity values for * @param[out] max_severity_eq1 Max severity for EQ1 * @param[out] max_severity_eq2 Max severity for EQ2 * @param[out] max_severity_eq3eq6 Max severity for EQ3 and EQ6 * @param[out] max_severity_eq4 Max severity for EQ4 */ static void cvss4_max_severities (const char *macrovector, double *max_severity_eq1, double *max_severity_eq2, double *max_severity_eq3eq6, double *max_severity_eq4) { switch (macrovector[0]) { case '0': *max_severity_eq1 = 0.1; break; case '1': *max_severity_eq1 = 0.4; break; case '2': *max_severity_eq1 = 0.5; break; default: *max_severity_eq1 = -99.0; } switch (macrovector[1]) { case '0': *max_severity_eq2 = 0.1; break; case '1': *max_severity_eq2 = 0.2; break; default: *max_severity_eq2 = -99.0; } switch (macrovector[2]) { case '0': if (macrovector[5] == '0') *max_severity_eq3eq6 = 0.7; else *max_severity_eq3eq6 = 0.6; break; case '1': *max_severity_eq3eq6 = 0.8; break; case '2': *max_severity_eq3eq6 = 1.0; break; default: *max_severity_eq3eq6 = -99.0; } switch (macrovector[3]) { case '0': *max_severity_eq4 = 0.6; break; case '1': *max_severity_eq4 = 0.5; break; case '2': *max_severity_eq4 = 0.4; break; default: *max_severity_eq4 = -99.0; } } /** * @brief Calculate CVSS 4.0 Score. * * @param cvss_str Vector from which to compute score, without prefix. * * @return CVSS score, or -1 on error. */ static double get_cvss_score_from_metrics_v4 (const char *cvss_str) { char *vec = NULL; char *macrovector = NULL; double available_distance_eq1, available_distance_eq2; double available_distance_eq3eq6; double available_distance_eq4, available_distance_eq5; double current_severity_distance_eq1, current_severity_distance_eq2; double current_severity_distance_eq3eq6; double current_severity_distance_eq4, current_severity_distance_eq5; double max_severity_eq1, max_severity_eq2, max_severity_eq3eq6; double max_severity_eq4; double mean_distance, value; int n_existing_lower = 0; // Convert vector to simplified, enum-indexed string g_debug ("%s: CVSS string: %s", __func__, cvss_str); vec = simplify_cvss4_vector (cvss_str); g_debug ("%s: simplified vector: %s", __func__, vec); if (vec == NULL) return -1.0; // Calculate macrovector macrovector = cvss4_macrovector (vec); value = cvss4_macrovector_score (macrovector); g_debug ("%s: macrovector: %s, value: %0.1f", __func__, macrovector, value); if (macrovector == NULL || value == -1.0) { g_free (vec); return -1.0; } // Calculate maximum distances cvss4_maximal_scoring_differences ( macrovector, &available_distance_eq1, &available_distance_eq2, &available_distance_eq3eq6, &available_distance_eq4, &available_distance_eq5); g_debug ("%s: maximal scoring diffs:" " EQ1:%0.1f EQ2:%0.1f EQ3+EQ6:%0.1f EQ5:%0.1f EQ6:%0.1f", __func__, available_distance_eq1, available_distance_eq2, available_distance_eq3eq6, available_distance_eq4, available_distance_eq5); // Calculate current severity distances cvss4_current_severity_distances ( vec, macrovector, ¤t_severity_distance_eq1, ¤t_severity_distance_eq2, ¤t_severity_distance_eq3eq6, ¤t_severity_distance_eq4, ¤t_severity_distance_eq5); g_debug ("%s: current severity distances:" "EQ1:%0.1f EQ2:%0.1f EQ3+EQ6:%0.1f EQ4:%0.1f EQ5:%0.1f", __func__, current_severity_distance_eq1, current_severity_distance_eq2, current_severity_distance_eq3eq6, current_severity_distance_eq4, current_severity_distance_eq5); // Get MaxSeverity cvss4_max_severities (macrovector, &max_severity_eq1, &max_severity_eq2, &max_severity_eq3eq6, &max_severity_eq4); g_free (vec); g_free (macrovector); // Calculate mean distances mean_distance = 0.0; if (available_distance_eq1 >= 0.0) { n_existing_lower++; double percent_to_next_severity = (current_severity_distance_eq1) / max_severity_eq1; mean_distance += (available_distance_eq1 * percent_to_next_severity); } if (available_distance_eq2 >= 0.0) { n_existing_lower++; double percent_to_next_severity = (current_severity_distance_eq2) / max_severity_eq2; mean_distance += (available_distance_eq2 * percent_to_next_severity); } if (available_distance_eq3eq6 >= 0.0) { n_existing_lower++; double percent_to_next_severity = (current_severity_distance_eq3eq6) / max_severity_eq3eq6; mean_distance += (available_distance_eq3eq6 * percent_to_next_severity); } if (available_distance_eq4 >= 0.0) { n_existing_lower++; double percent_to_next_severity = (current_severity_distance_eq4) / max_severity_eq4; mean_distance += (available_distance_eq4 * percent_to_next_severity); } if (available_distance_eq5 >= 0.0) { // For EQ5 the percentage is always 0 n_existing_lower++; } mean_distance = mean_distance / n_existing_lower; // Get and adjust macrovector score value = value - mean_distance; if (value < 0.0) value = 0.0; else if (value > 10.0) value = 10.0; return round (value * 10.0) / 10.0; } gvm-libs-22.20.0/base/cvss.h000066400000000000000000000005541477470532200154550ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2012-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Protos for CVSS utility functions. * * This file contains the protos for \ref cvss.c */ #ifndef _GVM_CVSS_H #define _GVM_CVSS_H #include double get_cvss_score_from_base_metrics (const char *); #endif /* not _GVM_CVSS_H */ gvm-libs-22.20.0/base/cvss_tests.c000066400000000000000000003132211477470532200166700ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "cvss.c" #include #include #include Describe (cvss); BeforeEach (cvss) { } AfterEach (cvss) { } Ensure (cvss, roundup_succeeds) { assert_that_double (roundup (0.0), is_equal_to_double (0.0)); assert_that_double (roundup (1.0), is_equal_to_double (1.0)); assert_that_double (roundup (1.01), is_equal_to_double (1.1)); assert_that_double (roundup (0.99), is_equal_to_double (1.0)); assert_that_double (roundup (1.000001), is_equal_to_double (1.0)); assert_that_double (roundup (5.299996), is_equal_to_double (5.3)); assert_that_double (roundup (5.500320), is_equal_to_double (5.6)); } /* get_cvss_score_from_base_metrics */ #define CHECK(vector, score) \ assert_that_double (nearest (get_cvss_score_from_base_metrics (vector)), \ is_equal_to_double (score)) Ensure (cvss, get_cvss_score_from_base_metrics_null) { assert_that (get_cvss_score_from_base_metrics (NULL), is_equal_to (-1.0)); } static double nearest (double cvss) { return round (cvss * 10) / 10; } Ensure (cvss, get_cvss_score_from_base_metrics_succeeds) { CHECK ("AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8); CHECK ("AV:N/AC:L/Au:N/C:N/I:N/A:P", 5.0); CHECK ("AV:N/AC:M/Au:N/C:N/I:N/A:P", 4.3); CHECK ("AV:N/AC:L/Au:N/C:N/I:N/A:N", 0.0); } Ensure (cvss, get_cvss_score_from_base_metrics_succeeds_v3) { CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N", 10.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:L", 3.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:L/A:N", 2.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:N", 0.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 7.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", 2.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:N", 0.0); /* Trailing separator. */ CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:N/", 0.0); /* We support any case in metrics. */ CHECK ("CVSS:3.1/av:n/ac:l/pr:n/ui:n/s:u/c:h/i:l/a:n", 8.2); } Ensure (cvss, get_cvss_score_from_base_metrics_succeeds_v4) { CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", 10.0); /* Trailing separator. */ CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/", 10.0); /* We support any case in metrics. */ CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", 10.0); /* Test various base vectors */ CHECK ("CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:A/VC:H/VI:L/VA:N/SC:N/SI:L/SA:H", 6.9); CHECK ("CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:L/VA:L/SC:H/SI:H/SA:H", 5.8); CHECK ("CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:L/VI:L/VA:L/SC:H/SI:H/SA:H/" "MSI:S", 7.0); CHECK ("CVSS:4.0/AV:P/AC:H/AT:P/PR:H/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N", 1.0); CHECK ("CVSS:4.0/AV:L/AC:H/AT:N/PR:L/UI:A/VC:L/VI:L/VA:H/SC:N/SI:N/SA:N", 4.4); /* Test cases for picking one of two macrovector scores * when EQ3 and EQ6 of the macrovector are 0*/ CHECK ("CVSS:4.0/AV:N/AC:H/AT:P/PR:H/UI:A/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N", 7.1); CHECK ("CVSS:4.0/AV:A/AC:H/AT:P/PR:H/UI:A/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N", 5.3); /* Test vectors with Requirements metric */ CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:L/SI:L/SA:L/" "CR:M", 8.0); CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:L/SI:L/SA:L/" "IR:L", 8.7); CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N/" "CR:M/IR:L/AR:L", 8.9); /* Test vectors with Exploit Maturity metric */ CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:L/SI:L/SA:L/E:P", 7.8); CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:L/SI:L/SA:L/E:U", 6.7); /* Provider Urgency is a special case with longer values */ CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/" "U:Amber", 10.0); CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/" "U:X", 10.0); } Ensure (cvss, get_cvss_score_from_base_metrics_fails) { CHECK ("", -1.0); CHECK ("xxx", -1.0); CHECK ("//////", -1.0); /* Unsupported version. */ CHECK ("CVSS:3.2/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", -1.0); /* Metric name errors. */ CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/X:N", -1.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/X:L/A:N", -1.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/X:N/I:L/A:N", -1.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/X:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UX:N/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.1/AV:L/AC:H/PX:L/UI:N/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.1/AV:L/XC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.1/AXV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", -1.0); /* Leading separator. */ CHECK ("/CVSS:3.1/AXV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", -1.0); /* Garbage at end of metric value. */ CHECK ("CVSS:3.0/AV:LX/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:HX/PR:L/UI:N/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:LX/UI:N/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:NX/S:U/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:UX/C:N/I:L/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:NX/I:L/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:LX/A:N", -1.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:NX", -1.0); /* Version must be uppercase. */ CHECK ("cvss:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", -1.0); } Ensure (cvss, get_cvss_score_from_base_metrics_fails_v4) { /* No metrics given */ CHECK ("CVSS:4.0", -1.0); /* Metric name is invalid */ CHECK ("CVSS:4.0/AXXXX:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Metric name is missing */ CHECK ("CVSS:4.0/:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Metric value is invalid */ CHECK ("CVSS:4.0/AV:Y/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Metric value is too long */ CHECK ("CVSS:4.0/AV:XYZ/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Metric value is missing */ CHECK ("CVSS:4.0/AV:/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); CHECK ("CVSS:4.0/AV/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Duplicate Metric */ CHECK ("CVSS:4.0/AV:N/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Missing mandatory metrics */ CHECK ("CVSS:4.0/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); CHECK ("CVSS:4.0/AV:N/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H", -1.0); /* Version must be uppercase. */ CHECK ("cvss:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H", -1.0); /* Invalid Provider Urgency */ CHECK ("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/U:R", -1.0); } Ensure (cvss, get_cvss_score_from_base_metrics_all_in_feed_match) { /* Every distinct CVSSv2 vector and score shipped in the feed nvdcve files. */ CHECK ("AV:A/AC:H/Au:M/C:N/I:P/A:P", 2.7); CHECK ("AV:A/AC:H/Au:N/C:C/I:C/A:C", 6.8); CHECK ("AV:A/AC:H/Au:N/C:C/I:N/A:C", 6.2); CHECK ("AV:A/AC:H/Au:N/C:C/I:P/A:N", 5.3); CHECK ("AV:A/AC:H/Au:N/C:N/I:N/A:C", 4.6); CHECK ("AV:A/AC:H/Au:N/C:N/I:N/A:P", 1.8); CHECK ("AV:A/AC:H/Au:N/C:N/I:P/A:N", 1.8); CHECK ("AV:A/AC:H/Au:N/C:P/I:N/A:N", 1.8); CHECK ("AV:A/AC:H/Au:N/C:P/I:N/A:P", 3.2); CHECK ("AV:A/AC:H/Au:N/C:P/I:P/A:C", 5.8); CHECK ("AV:A/AC:H/Au:N/C:P/I:P/A:N", 3.2); CHECK ("AV:A/AC:H/Au:N/C:P/I:P/A:P", 4.3); CHECK ("AV:A/AC:H/Au:S/C:C/I:C/A:C", 6.5); CHECK ("AV:A/AC:H/Au:S/C:C/I:N/A:N", 4.3); CHECK ("AV:A/AC:H/Au:S/C:N/I:N/A:C", 4.3); CHECK ("AV:A/AC:H/Au:S/C:N/I:N/A:P", 1.4); CHECK ("AV:A/AC:H/Au:S/C:P/I:N/A:P", 2.9); CHECK ("AV:A/AC:H/Au:S/C:P/I:P/A:C", 5.5); CHECK ("AV:A/AC:H/Au:S/C:P/I:P/A:P", 4.0); CHECK ("AV:A/AC:L/Au:M/C:C/I:C/A:C", 7.2); CHECK ("AV:A/AC:L/Au:M/C:P/I:P/A:P", 4.7); CHECK ("AV:A/AC:L/Au:N/C:C/I:C/A:C", 8.3); CHECK ("AV:A/AC:L/Au:N/C:C/I:C/A:N", 7.8); CHECK ("AV:A/AC:L/Au:N/C:C/I:N/A:N", 6.1); CHECK ("AV:A/AC:L/Au:N/C:C/I:P/A:C", 8.0); CHECK ("AV:A/AC:L/Au:N/C:N/I:C/A:C", 7.8); CHECK ("AV:A/AC:L/Au:N/C:N/I:C/A:N", 6.1); CHECK ("AV:A/AC:L/Au:N/C:N/I:N/A:C", 6.1); CHECK ("AV:A/AC:L/Au:N/C:N/I:N/A:P", 3.3); CHECK ("AV:A/AC:L/Au:N/C:N/I:P/A:C", 6.8); CHECK ("AV:A/AC:L/Au:N/C:N/I:P/A:N", 3.3); CHECK ("AV:A/AC:L/Au:N/C:N/I:P/A:P", 4.8); CHECK ("AV:A/AC:L/Au:N/C:P/I:C/A:C", 8.0); CHECK ("AV:A/AC:L/Au:N/C:P/I:N/A:N", 3.3); CHECK ("AV:A/AC:L/Au:N/C:P/I:N/A:P", 4.8); CHECK ("AV:A/AC:L/Au:N/C:P/I:P/A:C", 7.3); CHECK ("AV:A/AC:L/Au:N/C:P/I:P/A:N", 4.8); CHECK ("AV:A/AC:L/Au:N/C:P/I:P/A:P", 5.8); CHECK ("AV:A/AC:L/Au:S/C:C/I:C/A:C", 7.7); CHECK ("AV:A/AC:L/Au:S/C:C/I:C/A:N", 7.1); CHECK ("AV:A/AC:L/Au:S/C:C/I:C/A:P", 7.4); CHECK ("AV:A/AC:L/Au:S/C:C/I:N/A:N", 5.5); CHECK ("AV:A/AC:L/Au:S/C:C/I:P/A:P", 6.7); CHECK ("AV:A/AC:L/Au:S/C:N/I:N/A:C", 5.5); CHECK ("AV:A/AC:L/Au:S/C:N/I:N/A:P", 2.7); CHECK ("AV:A/AC:L/Au:S/C:N/I:P/A:C", 6.2); CHECK ("AV:A/AC:L/Au:S/C:N/I:P/A:N", 2.7); CHECK ("AV:A/AC:L/Au:S/C:N/I:P/A:P", 4.1); CHECK ("AV:A/AC:L/Au:S/C:P/I:N/A:N", 2.7); CHECK ("AV:A/AC:L/Au:S/C:P/I:N/A:P", 4.1); CHECK ("AV:A/AC:L/Au:S/C:P/I:P/A:C", 6.7); CHECK ("AV:A/AC:L/Au:S/C:P/I:P/A:N", 4.1); CHECK ("AV:A/AC:L/Au:S/C:P/I:P/A:P", 5.2); CHECK ("AV:A/AC:M/Au:N/C:C/I:C/A:C", 7.9); CHECK ("AV:A/AC:M/Au:N/C:C/I:C/A:N", 7.3); CHECK ("AV:A/AC:M/Au:N/C:C/I:C/A:P", 7.6); CHECK ("AV:A/AC:M/Au:N/C:C/I:N/A:C", 7.3); CHECK ("AV:A/AC:M/Au:N/C:C/I:N/A:N", 5.7); CHECK ("AV:A/AC:M/Au:N/C:C/I:P/A:C", 7.6); CHECK ("AV:A/AC:M/Au:N/C:C/I:P/A:P", 6.9); CHECK ("AV:A/AC:M/Au:N/C:N/I:C/A:C", 7.3); CHECK ("AV:A/AC:M/Au:N/C:N/I:C/A:N", 5.7); CHECK ("AV:A/AC:M/Au:N/C:N/I:N/A:C", 5.7); CHECK ("AV:A/AC:M/Au:N/C:N/I:N/A:P", 2.9); CHECK ("AV:A/AC:M/Au:N/C:N/I:P/A:C", 6.4); CHECK ("AV:A/AC:M/Au:N/C:N/I:P/A:N", 2.9); CHECK ("AV:A/AC:M/Au:N/C:N/I:P/A:P", 4.3); CHECK ("AV:A/AC:M/Au:N/C:P/I:C/A:C", 7.6); CHECK ("AV:A/AC:M/Au:N/C:P/I:N/A:N", 2.9); CHECK ("AV:A/AC:M/Au:N/C:P/I:N/A:P", 4.3); CHECK ("AV:A/AC:M/Au:N/C:P/I:P/A:N", 4.3); CHECK ("AV:A/AC:M/Au:N/C:P/I:P/A:P", 5.4); CHECK ("AV:A/AC:M/Au:S/C:C/I:C/A:C", 7.4); CHECK ("AV:A/AC:M/Au:S/C:C/I:N/A:N", 5.2); CHECK ("AV:A/AC:M/Au:S/C:N/I:N/A:C", 5.2); CHECK ("AV:A/AC:M/Au:S/C:N/I:N/A:P", 2.3); CHECK ("AV:A/AC:M/Au:S/C:N/I:P/A:C", 5.8); CHECK ("AV:A/AC:M/Au:S/C:N/I:P/A:N", 2.3); CHECK ("AV:A/AC:M/Au:S/C:N/I:P/A:P", 3.8); CHECK ("AV:A/AC:M/Au:S/C:P/I:N/A:C", 5.8); CHECK ("AV:A/AC:M/Au:S/C:P/I:N/A:N", 2.3); CHECK ("AV:A/AC:M/Au:S/C:P/I:N/A:P", 3.8); CHECK ("AV:A/AC:M/Au:S/C:P/I:P/A:C", 6.3); CHECK ("AV:A/AC:M/Au:S/C:P/I:P/A:N", 3.8); CHECK ("AV:A/AC:M/Au:S/C:P/I:P/A:P", 4.9); CHECK ("AV:L/AC:H/Au:M/C:C/I:C/A:C", 5.9); CHECK ("AV:L/AC:H/Au:M/C:N/I:N/A:C", 3.7); CHECK ("AV:L/AC:H/Au:M/C:P/I:P/A:C", 4.9); CHECK ("AV:L/AC:H/Au:M/C:P/I:P/A:P", 3.4); CHECK ("AV:L/AC:H/Au:N/C:C/I:C/A:C", 6.2); CHECK ("AV:L/AC:H/Au:N/C:C/I:C/A:N", 5.6); CHECK ("AV:L/AC:H/Au:N/C:C/I:C/A:P", 5.9); CHECK ("AV:L/AC:H/Au:N/C:C/I:N/A:C", 5.6); CHECK ("AV:L/AC:H/Au:N/C:C/I:N/A:N", 4.0); CHECK ("AV:L/AC:H/Au:N/C:N/I:C/A:C", 5.6); CHECK ("AV:L/AC:H/Au:N/C:N/I:C/A:N", 4.0); CHECK ("AV:L/AC:H/Au:N/C:N/I:N/A:C", 4.0); CHECK ("AV:L/AC:H/Au:N/C:N/I:N/A:P", 1.2); CHECK ("AV:L/AC:H/Au:N/C:N/I:P/A:N", 1.2); CHECK ("AV:L/AC:H/Au:N/C:N/I:P/A:P", 2.6); CHECK ("AV:L/AC:H/Au:N/C:P/I:N/A:C", 4.7); CHECK ("AV:L/AC:H/Au:N/C:P/I:N/A:N", 1.2); CHECK ("AV:L/AC:H/Au:N/C:P/I:N/A:P", 2.6); CHECK ("AV:L/AC:H/Au:N/C:P/I:P/A:C", 5.2); CHECK ("AV:L/AC:H/Au:N/C:P/I:P/A:N", 2.6); CHECK ("AV:L/AC:H/Au:N/C:P/I:P/A:P", 3.7); CHECK ("AV:L/AC:H/Au:S/C:C/I:C/A:C", 6.0); CHECK ("AV:L/AC:H/Au:S/C:C/I:C/A:N", 5.5); CHECK ("AV:L/AC:H/Au:S/C:C/I:N/A:N", 3.8); CHECK ("AV:L/AC:H/Au:S/C:N/I:C/A:C", 5.5); CHECK ("AV:L/AC:H/Au:S/C:N/I:C/A:N", 3.8); CHECK ("AV:L/AC:H/Au:S/C:N/I:N/A:C", 3.8); CHECK ("AV:L/AC:H/Au:S/C:N/I:N/A:P", 1.0); CHECK ("AV:L/AC:H/Au:S/C:N/I:P/A:N", 1.0); CHECK ("AV:L/AC:H/Au:S/C:N/I:P/A:P", 2.4); CHECK ("AV:L/AC:H/Au:S/C:P/I:N/A:N", 1.0); CHECK ("AV:L/AC:H/Au:S/C:P/I:N/A:P", 2.4); CHECK ("AV:L/AC:H/Au:S/C:P/I:P/A:N", 2.4); CHECK ("AV:L/AC:H/Au:S/C:P/I:P/A:P", 3.5); CHECK ("AV:L/AC:L/Au:M/C:C/I:C/A:C", 6.5); CHECK ("AV:L/AC:L/Au:M/C:N/I:N/A:C", 4.3); CHECK ("AV:L/AC:L/Au:M/C:P/I:N/A:N", 1.4); CHECK ("AV:L/AC:L/Au:N/C:C/I:C/A:C", 7.2); CHECK ("AV:L/AC:L/Au:N/C:C/I:C/A:N", 6.6); CHECK ("AV:L/AC:L/Au:N/C:C/I:C/A:P", 6.8); CHECK ("AV:L/AC:L/Au:N/C:C/I:N/A:C", 6.6); CHECK ("AV:L/AC:L/Au:N/C:C/I:N/A:N", 4.9); CHECK ("AV:L/AC:L/Au:N/C:C/I:P/A:P", 6.1); CHECK ("AV:L/AC:L/Au:N/C:N/I:C/A:C", 6.6); CHECK ("AV:L/AC:L/Au:N/C:N/I:C/A:N", 4.9); CHECK ("AV:L/AC:L/Au:N/C:N/I:N/A:C", 4.9); CHECK ("AV:L/AC:L/Au:N/C:N/I:N/A:N", 0.0); CHECK ("AV:L/AC:L/Au:N/C:N/I:N/A:P", 2.1); CHECK ("AV:L/AC:L/Au:N/C:N/I:P/A:C", 5.6); CHECK ("AV:L/AC:L/Au:N/C:N/I:P/A:N", 2.1); CHECK ("AV:L/AC:L/Au:N/C:N/I:P/A:P", 3.6); CHECK ("AV:L/AC:L/Au:N/C:P/I:C/A:C", 6.8); CHECK ("AV:L/AC:L/Au:N/C:P/I:C/A:N", 5.6); CHECK ("AV:L/AC:L/Au:N/C:P/I:C/A:P", 6.1); CHECK ("AV:L/AC:L/Au:N/C:P/I:N/A:C", 5.6); CHECK ("AV:L/AC:L/Au:N/C:P/I:N/A:N", 2.1); CHECK ("AV:L/AC:L/Au:N/C:P/I:N/A:P", 3.6); CHECK ("AV:L/AC:L/Au:N/C:P/I:P/A:C", 6.1); CHECK ("AV:L/AC:L/Au:N/C:P/I:P/A:N", 3.6); CHECK ("AV:L/AC:L/Au:N/C:P/I:P/A:P", 4.6); CHECK ("AV:L/AC:L/Au:S/C:C/I:C/A:C", 6.8); CHECK ("AV:L/AC:L/Au:S/C:C/I:C/A:N", 6.2); CHECK ("AV:L/AC:L/Au:S/C:C/I:N/A:N", 4.6); CHECK ("AV:L/AC:L/Au:S/C:C/I:N/A:P", 5.2); CHECK ("AV:L/AC:L/Au:S/C:N/I:C/A:C", 6.2); CHECK ("AV:L/AC:L/Au:S/C:N/I:C/A:N", 4.6); CHECK ("AV:L/AC:L/Au:S/C:N/I:N/A:C", 4.6); CHECK ("AV:L/AC:L/Au:S/C:N/I:N/A:P", 1.7); CHECK ("AV:L/AC:L/Au:S/C:N/I:P/A:C", 5.2); CHECK ("AV:L/AC:L/Au:S/C:N/I:P/A:N", 1.7); CHECK ("AV:L/AC:L/Au:S/C:N/I:P/A:P", 3.2); CHECK ("AV:L/AC:L/Au:S/C:P/I:N/A:N", 1.7); CHECK ("AV:L/AC:L/Au:S/C:P/I:N/A:P", 3.2); CHECK ("AV:L/AC:L/Au:S/C:P/I:P/A:C", 5.7); CHECK ("AV:L/AC:L/Au:S/C:P/I:P/A:N", 3.2); CHECK ("AV:L/AC:L/Au:S/C:P/I:P/A:P", 4.3); CHECK ("AV:L/AC:M/Au:M/C:C/I:C/A:C", 6.3); CHECK ("AV:L/AC:M/Au:M/C:N/I:N/A:C", 4.1); CHECK ("AV:L/AC:M/Au:M/C:N/I:P/A:P", 2.7); CHECK ("AV:L/AC:M/Au:M/C:P/I:N/A:N", 1.3); CHECK ("AV:L/AC:M/Au:N/C:C/I:C/A:C", 6.9); CHECK ("AV:L/AC:M/Au:N/C:C/I:C/A:N", 6.3); CHECK ("AV:L/AC:M/Au:N/C:C/I:C/A:P", 6.6); CHECK ("AV:L/AC:M/Au:N/C:C/I:N/A:C", 6.3); CHECK ("AV:L/AC:M/Au:N/C:C/I:N/A:N", 4.7); CHECK ("AV:L/AC:M/Au:N/C:C/I:N/A:P", 5.4); CHECK ("AV:L/AC:M/Au:N/C:C/I:P/A:C", 6.6); CHECK ("AV:L/AC:M/Au:N/C:C/I:P/A:N", 5.4); CHECK ("AV:L/AC:M/Au:N/C:C/I:P/A:P", 5.9); CHECK ("AV:L/AC:M/Au:N/C:N/I:C/A:C", 6.3); CHECK ("AV:L/AC:M/Au:N/C:N/I:C/A:N", 4.7); CHECK ("AV:L/AC:M/Au:N/C:N/I:N/A:C", 4.7); CHECK ("AV:L/AC:M/Au:N/C:N/I:N/A:P", 1.9); CHECK ("AV:L/AC:M/Au:N/C:N/I:P/A:C", 5.4); CHECK ("AV:L/AC:M/Au:N/C:N/I:P/A:N", 1.9); CHECK ("AV:L/AC:M/Au:N/C:N/I:P/A:P", 3.3); CHECK ("AV:L/AC:M/Au:N/C:P/I:C/A:C", 6.6); CHECK ("AV:L/AC:M/Au:N/C:P/I:C/A:N", 5.4); CHECK ("AV:L/AC:M/Au:N/C:P/I:N/A:C", 5.4); CHECK ("AV:L/AC:M/Au:N/C:P/I:N/A:N", 1.9); CHECK ("AV:L/AC:M/Au:N/C:P/I:N/A:P", 3.3); CHECK ("AV:L/AC:M/Au:N/C:P/I:P/A:C", 5.9); CHECK ("AV:L/AC:M/Au:N/C:P/I:P/A:N", 3.3); CHECK ("AV:L/AC:M/Au:N/C:P/I:P/A:P", 4.4); CHECK ("AV:L/AC:M/Au:S/C:C/I:C/A:C", 6.6); CHECK ("AV:L/AC:M/Au:S/C:C/I:C/A:N", 6.0); CHECK ("AV:L/AC:M/Au:S/C:C/I:N/A:N", 4.4); CHECK ("AV:L/AC:M/Au:S/C:N/I:C/A:C", 6.0); CHECK ("AV:L/AC:M/Au:S/C:N/I:N/A:C", 4.4); CHECK ("AV:L/AC:M/Au:S/C:N/I:N/A:P", 1.5); CHECK ("AV:L/AC:M/Au:S/C:N/I:P/A:N", 1.5); CHECK ("AV:L/AC:M/Au:S/C:N/I:P/A:P", 3.0); CHECK ("AV:L/AC:M/Au:S/C:P/I:N/A:N", 1.5); CHECK ("AV:L/AC:M/Au:S/C:P/I:P/A:C", 5.5); CHECK ("AV:L/AC:M/Au:S/C:P/I:P/A:N", 3.0); CHECK ("AV:L/AC:M/Au:S/C:P/I:P/A:P", 4.1); CHECK ("AV:N/AC:H/Au:M/C:C/I:C/A:C", 6.8); CHECK ("AV:N/AC:H/Au:M/C:N/I:N/A:P", 1.7); CHECK ("AV:N/AC:H/Au:M/C:N/I:P/A:N", 1.7); CHECK ("AV:N/AC:H/Au:M/C:P/I:N/A:N", 1.7); CHECK ("AV:N/AC:H/Au:M/C:P/I:P/A:N", 3.2); CHECK ("AV:N/AC:H/Au:M/C:P/I:P/A:P", 4.3); CHECK ("AV:N/AC:H/Au:N/C:C/I:C/A:C", 7.6); CHECK ("AV:N/AC:H/Au:N/C:C/I:C/A:N", 7.1); CHECK ("AV:N/AC:H/Au:N/C:C/I:C/A:P", 7.3); CHECK ("AV:N/AC:H/Au:N/C:C/I:N/A:C", 7.1); CHECK ("AV:N/AC:H/Au:N/C:C/I:N/A:N", 5.4); CHECK ("AV:N/AC:H/Au:N/C:C/I:P/A:C", 7.3); CHECK ("AV:N/AC:H/Au:N/C:C/I:P/A:N", 6.1); CHECK ("AV:N/AC:H/Au:N/C:N/I:C/A:C", 7.1); CHECK ("AV:N/AC:H/Au:N/C:N/I:C/A:N", 5.4); CHECK ("AV:N/AC:H/Au:N/C:N/I:N/A:C", 5.4); CHECK ("AV:N/AC:H/Au:N/C:N/I:N/A:P", 2.6); CHECK ("AV:N/AC:H/Au:N/C:N/I:P/A:C", 6.1); CHECK ("AV:N/AC:H/Au:N/C:N/I:P/A:N", 2.6); CHECK ("AV:N/AC:H/Au:N/C:N/I:P/A:P", 4.0); CHECK ("AV:N/AC:H/Au:N/C:P/I:N/A:N", 2.6); CHECK ("AV:N/AC:H/Au:N/C:P/I:N/A:P", 4.0); CHECK ("AV:N/AC:H/Au:N/C:P/I:P/A:C", 6.6); CHECK ("AV:N/AC:H/Au:N/C:P/I:P/A:N", 4.0); CHECK ("AV:N/AC:H/Au:N/C:P/I:P/A:P", 5.1); CHECK ("AV:N/AC:H/Au:S/C:C/I:C/A:C", 7.1); CHECK ("AV:N/AC:H/Au:S/C:C/I:C/A:N", 6.6); CHECK ("AV:N/AC:H/Au:S/C:C/I:C/A:P", 6.8); CHECK ("AV:N/AC:H/Au:S/C:C/I:N/A:C", 6.6); CHECK ("AV:N/AC:H/Au:S/C:C/I:N/A:N", 4.9); CHECK ("AV:N/AC:H/Au:S/C:C/I:P/A:P", 6.1); CHECK ("AV:N/AC:H/Au:S/C:N/I:C/A:C", 6.6); CHECK ("AV:N/AC:H/Au:S/C:N/I:N/A:C", 4.9); CHECK ("AV:N/AC:H/Au:S/C:N/I:N/A:P", 2.1); CHECK ("AV:N/AC:H/Au:S/C:N/I:P/A:C", 5.6); CHECK ("AV:N/AC:H/Au:S/C:N/I:P/A:N", 2.1); CHECK ("AV:N/AC:H/Au:S/C:N/I:P/A:P", 3.6); CHECK ("AV:N/AC:H/Au:S/C:P/I:N/A:N", 2.1); CHECK ("AV:N/AC:H/Au:S/C:P/I:N/A:P", 3.6); CHECK ("AV:N/AC:H/Au:S/C:P/I:P/A:C", 6.1); CHECK ("AV:N/AC:H/Au:S/C:P/I:P/A:N", 3.6); CHECK ("AV:N/AC:H/Au:S/C:P/I:P/A:P", 4.6); CHECK ("AV:N/AC:L/Au:M/C:C/I:C/A:C", 8.3); CHECK ("AV:N/AC:L/Au:M/C:C/I:C/A:N", 7.7); CHECK ("AV:N/AC:L/Au:M/C:N/I:N/A:C", 6.1); CHECK ("AV:N/AC:L/Au:M/C:N/I:N/A:P", 3.3); CHECK ("AV:N/AC:L/Au:M/C:N/I:P/A:N", 3.3); CHECK ("AV:N/AC:L/Au:M/C:P/I:P/A:N", 4.7); CHECK ("AV:N/AC:L/Au:M/C:P/I:P/A:P", 5.8); CHECK ("AV:N/AC:L/Au:N/C:C/I:C/A:C", 10.0); CHECK ("AV:N/AC:L/Au:N/C:C/I:C/A:N", 9.4); CHECK ("AV:N/AC:L/Au:N/C:C/I:C/A:P", 9.7); CHECK ("AV:N/AC:L/Au:N/C:C/I:N/A:C", 9.4); CHECK ("AV:N/AC:L/Au:N/C:C/I:N/A:N", 7.8); CHECK ("AV:N/AC:L/Au:N/C:C/I:N/A:P", 8.5); CHECK ("AV:N/AC:L/Au:N/C:C/I:P/A:N", 8.5); CHECK ("AV:N/AC:L/Au:N/C:C/I:P/A:P", 9.0); CHECK ("AV:N/AC:L/Au:N/C:N/I:C/A:C", 9.4); CHECK ("AV:N/AC:L/Au:N/C:N/I:C/A:N", 7.8); CHECK ("AV:N/AC:L/Au:N/C:N/I:C/A:P", 8.5); CHECK ("AV:N/AC:L/Au:N/C:N/I:N/A:C", 7.8); CHECK ("AV:N/AC:L/Au:N/C:N/I:N/A:N", 0.0); CHECK ("AV:N/AC:L/Au:N/C:N/I:N/A:P", 5.0); CHECK ("AV:N/AC:L/Au:N/C:N/I:P/A:C", 8.5); CHECK ("AV:N/AC:L/Au:N/C:N/I:P/A:N", 5.0); CHECK ("AV:N/AC:L/Au:N/C:N/I:P/A:P", 6.4); CHECK ("AV:N/AC:L/Au:N/C:P/I:C/A:C", 9.7); CHECK ("AV:N/AC:L/Au:N/C:P/I:C/A:N", 8.5); CHECK ("AV:N/AC:L/Au:N/C:P/I:C/A:P", 9.0); CHECK ("AV:N/AC:L/Au:N/C:P/I:N/A:C", 8.5); CHECK ("AV:N/AC:L/Au:N/C:P/I:N/A:N", 5.0); CHECK ("AV:N/AC:L/Au:N/C:P/I:N/A:P", 6.4); CHECK ("AV:N/AC:L/Au:N/C:P/I:P/A:C", 9.0); CHECK ("AV:N/AC:L/Au:N/C:P/I:P/A:N", 6.4); CHECK ("AV:N/AC:L/Au:N/C:P/I:P/A:P", 7.5); CHECK ("AV:N/AC:L/Au:S/C:C/I:C/A:C", 9.0); CHECK ("AV:N/AC:L/Au:S/C:C/I:C/A:N", 8.5); CHECK ("AV:N/AC:L/Au:S/C:C/I:C/A:P", 8.7); CHECK ("AV:N/AC:L/Au:S/C:C/I:N/A:C", 8.5); CHECK ("AV:N/AC:L/Au:S/C:C/I:N/A:N", 6.8); CHECK ("AV:N/AC:L/Au:S/C:C/I:N/A:P", 7.5); CHECK ("AV:N/AC:L/Au:S/C:C/I:P/A:C", 8.7); CHECK ("AV:N/AC:L/Au:S/C:C/I:P/A:N", 7.5); CHECK ("AV:N/AC:L/Au:S/C:C/I:P/A:P", 8.0); CHECK ("AV:N/AC:L/Au:S/C:N/I:C/A:C", 8.5); CHECK ("AV:N/AC:L/Au:S/C:N/I:C/A:N", 6.8); CHECK ("AV:N/AC:L/Au:S/C:N/I:C/A:P", 7.5); CHECK ("AV:N/AC:L/Au:S/C:N/I:N/A:C", 6.8); CHECK ("AV:N/AC:L/Au:S/C:N/I:N/A:P", 4.0); CHECK ("AV:N/AC:L/Au:S/C:N/I:P/A:C", 7.5); CHECK ("AV:N/AC:L/Au:S/C:N/I:P/A:N", 4.0); CHECK ("AV:N/AC:L/Au:S/C:N/I:P/A:P", 5.5); CHECK ("AV:N/AC:L/Au:S/C:P/I:C/A:C", 8.7); CHECK ("AV:N/AC:L/Au:S/C:P/I:C/A:N", 7.5); CHECK ("AV:N/AC:L/Au:S/C:P/I:C/A:P", 8.0); CHECK ("AV:N/AC:L/Au:S/C:P/I:N/A:C", 7.5); CHECK ("AV:N/AC:L/Au:S/C:P/I:N/A:N", 4.0); CHECK ("AV:N/AC:L/Au:S/C:P/I:N/A:P", 5.5); CHECK ("AV:N/AC:L/Au:S/C:P/I:P/A:C", 8.0); CHECK ("AV:N/AC:L/Au:S/C:P/I:P/A:N", 5.5); CHECK ("AV:N/AC:L/Au:S/C:P/I:P/A:P", 6.5); CHECK ("AV:N/AC:M/Au:M/C:C/I:C/A:C", 7.9); CHECK ("AV:N/AC:M/Au:M/C:N/I:N/A:C", 5.7); CHECK ("AV:N/AC:M/Au:M/C:N/I:N/A:P", 2.8); CHECK ("AV:N/AC:M/Au:M/C:N/I:P/A:N", 2.8); CHECK ("AV:N/AC:M/Au:M/C:N/I:P/A:P", 4.3); CHECK ("AV:N/AC:M/Au:M/C:P/I:N/A:N", 2.8); CHECK ("AV:N/AC:M/Au:M/C:P/I:P/A:N", 4.3); CHECK ("AV:N/AC:M/Au:M/C:P/I:P/A:P", 5.4); CHECK ("AV:N/AC:M/Au:N/C:C/I:C/A:C", 9.3); CHECK ("AV:N/AC:M/Au:N/C:C/I:C/A:N", 8.8); CHECK ("AV:N/AC:M/Au:N/C:C/I:N/A:N", 7.1); CHECK ("AV:N/AC:M/Au:N/C:C/I:P/A:C", 9.0); CHECK ("AV:N/AC:M/Au:N/C:C/I:P/A:N", 7.8); CHECK ("AV:N/AC:M/Au:N/C:C/I:P/A:P", 8.3); CHECK ("AV:N/AC:M/Au:N/C:N/I:C/A:C", 8.8); CHECK ("AV:N/AC:M/Au:N/C:N/I:C/A:N", 7.1); CHECK ("AV:N/AC:M/Au:N/C:N/I:N/A:C", 7.1); CHECK ("AV:N/AC:M/Au:N/C:N/I:N/A:P", 4.3); CHECK ("AV:N/AC:M/Au:N/C:N/I:P/A:C", 7.8); CHECK ("AV:N/AC:M/Au:N/C:N/I:P/A:N", 4.3); CHECK ("AV:N/AC:M/Au:N/C:N/I:P/A:P", 5.8); CHECK ("AV:N/AC:M/Au:N/C:P/I:C/A:C", 9.0); CHECK ("AV:N/AC:M/Au:N/C:P/I:C/A:N", 7.8); CHECK ("AV:N/AC:M/Au:N/C:P/I:C/A:P", 8.3); CHECK ("AV:N/AC:M/Au:N/C:P/I:N/A:C", 7.8); CHECK ("AV:N/AC:M/Au:N/C:P/I:N/A:N", 4.3); CHECK ("AV:N/AC:M/Au:N/C:P/I:N/A:P", 5.8); CHECK ("AV:N/AC:M/Au:N/C:P/I:P/A:C", 8.3); CHECK ("AV:N/AC:M/Au:N/C:P/I:P/A:N", 5.8); CHECK ("AV:N/AC:M/Au:N/C:P/I:P/A:P", 6.8); CHECK ("AV:N/AC:M/Au:S/C:C/I:C/A:C", 8.5); CHECK ("AV:N/AC:M/Au:S/C:C/I:C/A:N", 7.9); CHECK ("AV:N/AC:M/Au:S/C:C/I:C/A:P", 8.2); CHECK ("AV:N/AC:M/Au:S/C:C/I:N/A:C", 7.9); CHECK ("AV:N/AC:M/Au:S/C:C/I:N/A:N", 6.3); CHECK ("AV:N/AC:M/Au:S/C:C/I:P/A:N", 7.0); CHECK ("AV:N/AC:M/Au:S/C:C/I:P/A:P", 7.5); CHECK ("AV:N/AC:M/Au:S/C:N/I:C/A:C", 7.9); CHECK ("AV:N/AC:M/Au:S/C:N/I:C/A:N", 6.3); CHECK ("AV:N/AC:M/Au:S/C:N/I:N/A:C", 6.3); CHECK ("AV:N/AC:M/Au:S/C:N/I:N/A:N", 0.0); CHECK ("AV:N/AC:M/Au:S/C:N/I:N/A:P", 3.5); CHECK ("AV:N/AC:M/Au:S/C:N/I:P/A:C", 7.0); CHECK ("AV:N/AC:M/Au:S/C:N/I:P/A:N", 3.5); CHECK ("AV:N/AC:M/Au:S/C:N/I:P/A:P", 4.9); CHECK ("AV:N/AC:M/Au:S/C:P/I:C/A:C", 8.2); CHECK ("AV:N/AC:M/Au:S/C:P/I:C/A:N", 7.0); CHECK ("AV:N/AC:M/Au:S/C:P/I:N/A:C", 7.0); CHECK ("AV:N/AC:M/Au:S/C:P/I:N/A:N", 3.5); CHECK ("AV:N/AC:M/Au:S/C:P/I:N/A:P", 4.9); CHECK ("AV:N/AC:M/Au:S/C:P/I:P/A:C", 7.5); CHECK ("AV:N/AC:M/Au:S/C:P/I:P/A:N", 4.9); CHECK ("AV:N/AC:M/Au:S/C:P/I:P/A:P", 6.0); /* Every distinct CVSSv3 vector and score shipped in the feed nvdcve files. */ CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H", 7.6); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:C/C:H/I:L/A:L", 6.8); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:C/C:H/I:N/A:N", 5.4); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:C/C:L/I:N/A:N", 2.6); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:C/C:N/I:N/A:H", 5.4); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:L", 3.1); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.2); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.2); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:H/A:H", 5.6); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H", 6.4); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.8); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H", 7.6); CHECK ("CVSS:3.0/AV:A/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 8.3); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N", 8.0); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N", 6.1); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:C/C:L/I:H/A:H", 8.2); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H", 6.1); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N", 6.8); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:L", 6.4); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", 4.2); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", 3.1); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L", 3.1); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N", 4.8); CHECK ("CVSS:3.0/AV:A/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N", 3.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 8.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N", 6.2); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H", 6.2); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N", 2.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 9.0); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N", 4.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", 6.8); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N", 4.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 7.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L", 6.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 5.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", 5.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 5.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 3.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N", 4.8); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N", 6.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H", 5.2); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 9.6); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N", 9.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H", 9.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", 7.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N", 6.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N", 7.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 4.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H", 7.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L", 4.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 8.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N", 7.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H", 7.6); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L", 5.4); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H", 7.1); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 4.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 5.2); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 5.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 5.7); CHECK ("CVSS:3.0/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:L/A:L", 6.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:L/A:N", 6.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:L/I:N/A:N", 2.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:C/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:L", 3.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:N", 1.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:H", 5.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:H", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:L", 3.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:N", 1.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H", 7.2); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:C/C:H/I:N/A:N", 5.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:L", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:H", 5.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:N", 5.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:H/I:N/A:H", 5.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:H/I:N/A:N", 4.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:H", 5.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:H/A:H", 5.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N", 1.8); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:H", 4.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L", 1.8); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H", 7.8); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N", 7.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N", 6.4); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N", 5.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:N", 5.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:N/I:L/A:H", 6.4); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:N/I:N/A:H", 5.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N", 6.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H", 6.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:H/A:H", 6.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:H/A:L", 5.8); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L", 4.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N", 3.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N", 2.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H", 6.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H", 5.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", 2.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L", 2.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:H", 6.6); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:N/A:N", 2.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", 6.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N", 6.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:L/I:H/A:N", 5.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L", 4.2); CHECK ("CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:L/I:N/A:N", 2.2); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 8.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N", 5.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 7.4); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 5.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H", 6.2); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", 4.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", 4.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N", 2.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 5.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", 2.9); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 5.1); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H", 7.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:C/C:H/I:N/A:N", 5.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.0); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:L", 6.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N", 6.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:H", 5.8); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:L", 4.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 2.5); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:H", 6.3); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N", 4.7); CHECK ("CVSS:3.0/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H", 4.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 8.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N", 7.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N", 6.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:H", 7.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L", 5.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H", 7.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:L/A:H", 6.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:L/A:L", 4.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H", 6.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N", 6.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:N", 5.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H", 6.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:N", 5.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 4.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N", 3.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:H", 5.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N", 2.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H", 6.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:H", 5.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N", 2.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:H", 7.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:R/S:C/C:L/I:H/A:N", 6.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:N", 3.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:H/UI:R/S:U/C:N/I:N/A:H", 4.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L", 8.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N", 8.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:H", 8.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:H", 8.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:H", 7.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:H", 7.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:L", 5.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N", 3.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H", 8.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:H", 7.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:L", 5.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 5.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", 5.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 3.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", 5.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", 3.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 5.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 3.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H", 8.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N", 7.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N", 5.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L", 5.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:H", 6.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:N/I:N/A:H", 5.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H", 7.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:H", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N", 5.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:L/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L", 4.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N", 2.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:H", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N", 5.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:L", 3.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N", 2.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H", 5.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:L", 2.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 9.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H", 8.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L", 6.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 8.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 7.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", 7.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 6.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H", 7.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 5.9); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 5.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H", 6.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 4.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 7.7); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 6.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L", 5.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 4.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 6.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 4.0); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H", 8.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:H", 8.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N", 6.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:H", 8.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:H", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:H", 8.2); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:N", 6.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:H", 6.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.8); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L", 7.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 5.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:N", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:H", 6.6); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L", 5.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H", 6.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H", 7.1); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 5.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L", 4.4); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N", 3.3); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.5); CHECK ("CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L", 3.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:L", 7.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:C/C:H/I:N/A:N", 5.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:C/C:N/I:N/A:H", 5.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:L", 6.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:N", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:H/A:L", 5.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N", 3.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:H", 5.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:N", 2.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H", 7.6); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:N/A:N", 2.6); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:L/A:N", 4.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:N/A:N", 4.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:N", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:L/I:N/A:N", 2.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:H/A:N", 4.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:L", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N", 2.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H", 8.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N", 8.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:L", 7.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N", 6.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:H/A:N", 7.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:L", 6.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N", 4.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:L", 4.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:N/A:H", 6.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:L", 6.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H", 6.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N", 4.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:H", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L", 4.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N", 7.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:N/A:N", 3.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:C/C:N/I:H/A:N", 5.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:H", 6.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:L", 5.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 9.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:H/A:H", 8.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:L", 6.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N", 4.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:H", 8.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:L/A:N", 4.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:L", 4.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 8.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L", 7.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N", 7.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:L", 7.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H", 7.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:L", 7.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H", 7.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", 5.6); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", 4.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:H", 6.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N", 3.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H", 7.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L", 6.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H", 6.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L", 4.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", 3.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L", 3.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H", 8.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:L/A:N", 6.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:N/A:N", 6.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:N", 6.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N", 4.7); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N", 3.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:N/I:H/A:N", 6.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:N/I:L/A:N", 3.4); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:N/I:N/A:H", 6.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:L/A:H", 7.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:L/A:N", 5.9); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N", 4.2); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N", 3.1); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L", 3.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 9.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:L", 9.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N", 8.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:H", 8.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L", 6.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N", 5.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N", 4.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H", 8.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 7.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:L", 6.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:N", 5.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:H", 6.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:N", 5.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 4.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N", 3.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N", 2.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:H", 5.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:L", 3.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N", 2.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L", 2.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:H", 8.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:L", 8.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:L/A:N", 6.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:H/A:N", 6.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:N/A:N", 3.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N", 6.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N", 4.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:L", 4.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:N", 3.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:N/A:N", 2.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:H", 6.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:N", 4.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:N/A:H", 4.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 9.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L", 9.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N", 9.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:L", 9.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:H", 9.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:L", 8.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N", 7.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:H", 9.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:N", 8.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:H", 9.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L", 7.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 6.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:H", 8.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:L", 6.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N", 5.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", 7.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:H", 8.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:L", 6.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N", 5.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H", 7.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:L", 5.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L", 8.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 8.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:H", 8.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H", 8.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H", 8.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L", 5.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L", 5.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", 4.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H", 9.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N", 8.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:L", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:H/A:L", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:H", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:N/A:N", 4.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:H", 8.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:N", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:H", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:N", 4.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N", 7.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:L/A:H", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:L/A:L", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:L/A:N", 6.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:H", 7.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N", 5.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:H/A:N", 6.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:H", 6.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L", 5.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:L", 4.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:H", 7.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N", 5.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:L", 4.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N", 3.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H", 5.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:L", 3.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 10.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L", 10.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N", 10.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:L", 9.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N", 9.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H", 10.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", 8.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:H/A:H", 10.0); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H", 9.9); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L", 8.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N", 7.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:L", 7.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N", 5.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N", 8.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:H", 9.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:L", 7.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 5.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H", 8.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L", 5.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 9.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", 9.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 9.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H", 9.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L", 8.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", 9.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:L", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 7.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H", 9.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L", 8.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H", 8.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 7.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 5.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 9.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 7.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 5.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 7.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 5.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H", 9.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N", 9.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N", 7.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:N", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:H", 8.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 6.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N", 4.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:N", 7.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:H", 8.2); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N", 4.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:H", 7.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:N/A:L", 4.7); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L", 8.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", 8.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H", 8.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:N", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:H", 7.6); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:H", 7.1); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L", 5.4); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N", 4.3); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.0/AV:P/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H", 6.9); CHECK ("CVSS:3.0/AV:P/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:L", 6.7); CHECK ("CVSS:3.0/AV:P/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.0); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:L", 7.0); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N", 6.7); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N", 5.6); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:L", 4.6); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.0); CHECK ("CVSS:3.0/AV:P/AC:H/PR:L/UI:R/S:U/C:H/I:L/A:N", 4.5); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:C/C:H/I:L/A:N", 5.7); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N", 4.9); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 4.2); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:H", 6.0); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", 3.1); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:L", 4.8); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 4.2); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 4.2); CHECK ("CVSS:3.0/AV:P/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.2); CHECK ("CVSS:3.0/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 3.9); CHECK ("CVSS:3.0/AV:P/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 3.7); CHECK ("CVSS:3.0/AV:P/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N", 3.9); CHECK ("CVSS:3.0/AV:P/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 3.9); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 7.4); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L", 7.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 5.9); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L", 5.4); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 2.1); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", 4.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", 2.1); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 4.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L", 3.9); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 7.6); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N", 7.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 6.1); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 4.6); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 4.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 3.5); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 2.4); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 6.1); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 4.6); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 2.4); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 4.6); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 2.4); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 4.3); CHECK ("CVSS:3.0/AV:P/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 2.1); CHECK ("CVSS:3.1/AV:A/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.1/AV:A/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.1/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.1/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.8); CHECK ("CVSS:3.1/AV:A/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L", 4.3); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 8.3); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:C/C:H/I:L/A:H", 8.2); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N", 6.8); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N", 3.1); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H", 7.9); CHECK ("CVSS:3.1/AV:A/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 8.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N", 4.8); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H", 6.2); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:L", 6.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N", 6.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H", 6.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L", 2.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 9.0); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L", 7.6); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 5.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", 3.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 5.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 3.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H", 7.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N", 4.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 9.6); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H", 9.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", 7.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L", 7.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N", 4.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:L", 8.2); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:H", 8.2); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 4.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H", 7.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L", 4.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 8.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", 8.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H", 7.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H", 7.1); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L", 5.4); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 4.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 5.2); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", 7.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N", 6.3); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 5.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 5.7); CHECK ("CVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:N/I:L/A:L", 3.9); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:N/I:N/A:L", 2.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:L/A:N", 4.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.1); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.1); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.1); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:L", 4.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:N/I:H/A:H", 6.9); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L", 1.8); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H", 7.8); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N", 5.6); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:L/I:H/A:N", 6.4); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:L", 5.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N", 6.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:H", 6.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H", 5.8); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:L", 3.6); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N", 2.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H", 6.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N", 4.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H", 5.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L", 3.6); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", 2.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", 4.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:L", 7.4); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N", 7.2); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:L/I:N/A:N", 2.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:L", 3.9); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:N", 2.5); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", 6.7); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:N", 4.4); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L", 4.2); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:H/A:H", 6.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:H/A:L", 5.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:H/A:N", 4.4); CHECK ("CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 7.4); CHECK ("CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 5.1); CHECK ("CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.0); CHECK ("CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N", 6.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 8.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:L", 7.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N", 6.7); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N", 6.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:H/A:L", 7.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:H", 7.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N", 3.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H", 6.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:L", 3.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.7); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:L", 6.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N", 6.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:L", 5.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:N", 5.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H", 6.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:H", 6.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:H", 5.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 4.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N", 3.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N", 2.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H", 6.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:H", 5.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N", 2.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L", 2.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:H", 7.7); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:C/C:N/I:N/A:H", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:N", 4.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:N/I:L/A:L", 3.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:N/I:N/A:H", 4.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N", 8.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:H", 8.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:H", 7.9); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 5.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H", 8.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:H", 7.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:L", 5.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:L", 3.8); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.8); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", 5.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 3.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", 3.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 3.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H", 8.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N", 5.9); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:H/A:L", 7.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:N", 5.9); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H", 7.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:L", 5.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N", 5.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N", 3.9); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N", 2.8); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:H", 6.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N", 5.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:L", 3.9); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H", 5.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:L", 2.8); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 9.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N", 9.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 8.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 6.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 7.7); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 6.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 4.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 6.2); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 4.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H", 8.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N", 6.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 5.0); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N", 3.6); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.8); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:L", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L", 5.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H", 7.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:H", 6.1); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N", 3.3); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.5); CHECK ("CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L", 3.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:N/I:H/A:N", 5.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:N/I:L/A:N", 3.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:N", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:H", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:H/A:H", 6.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:L", 3.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:N", 2.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:H/A:H", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:L", 3.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:L", 2.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H", 7.6); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:N", 7.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:L", 5.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:L/I:N/A:N", 2.6); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:N/A:N", 4.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:L/I:N/A:N", 2.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:H/A:N", 4.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N", 2.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H", 8.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N", 8.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N", 6.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:L", 6.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:N", 6.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:N/A:H", 6.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N", 4.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N", 3.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H", 6.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N", 3.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L", 3.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:N", 4.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:N", 3.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:L", 6.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:N", 4.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:H/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:N", 3.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:N/I:N/A:H", 4.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 9.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N", 8.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:L/A:L", 8.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:H", 7.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:H", 8.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:L", 7.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:N/A:L", 4.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L", 7.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N", 7.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:H", 7.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:L", 7.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H", 7.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:L", 7.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H", 7.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", 5.6); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", 4.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:H", 6.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:L", 4.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N", 3.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H", 7.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H", 6.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L", 4.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", 3.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L", 3.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H", 8.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N", 8.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:L/A:L", 7.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:H", 7.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:L", 5.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N", 4.7); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N", 3.4); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 7.5); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:L/A:N", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N", 5.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:L", 5.0); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N", 4.2); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N", 3.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:H", 5.9); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N", 3.1); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H", 5.3); CHECK ("CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L", 3.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 9.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:L", 7.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:H/A:H", 9.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N", 5.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N", 4.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:L/A:N", 4.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 7.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:L", 6.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:H", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:L", 5.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 4.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:H", 6.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:H", 6.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L", 4.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N", 3.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N", 2.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N", 4.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:H", 5.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:L", 3.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N", 2.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 4.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:L", 2.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:H", 8.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:L/A:N", 6.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:N/A:N", 6.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:H", 7.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N", 4.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:N/I:N/A:H", 6.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N", 6.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N", 4.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:H", 5.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:L", 4.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:L/A:N", 3.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:L/I:N/A:N", 2.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:H", 6.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:N", 4.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:L/A:N", 2.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H", 9.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L", 9.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N", 9.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N", 8.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:H", 9.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N", 7.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:N", 8.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L", 7.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N", 6.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N", 5.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H", 9.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", 7.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:L", 6.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H", 7.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:L", 5.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L", 8.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L", 7.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:H", 8.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L", 7.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H", 7.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:H", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:L", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", 4.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H", 9.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:L", 8.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N", 8.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:L", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N", 7.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:N/A:N", 4.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:H/A:N", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:L", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:N", 4.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H", 8.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:L", 7.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N", 7.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:L/A:N", 6.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N", 5.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:H/A:L", 6.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L", 5.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N", 4.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:N/A:N", 3.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N", 5.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:H", 6.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:L", 4.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N", 3.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H", 5.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:L", 3.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 10.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N", 10.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N", 9.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H", 10.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:L", 9.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", 8.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H", 9.9); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L", 8.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N", 7.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:L", 7.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N", 5.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H", 10.0); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N", 8.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N", 5.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H", 8.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:L", 5.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 9.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", 9.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 9.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H", 9.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L", 8.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", 9.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:L", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 7.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H", 9.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L", 8.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H", 8.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 7.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 5.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 9.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 7.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 5.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 7.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 5.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H", 9.6); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N", 9.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L", 8.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N", 7.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:N", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", 6.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N", 4.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:H", 9.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:N", 7.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:H", 8.2); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N", 4.7); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 8.8); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L", 8.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:N", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L", 6.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:L", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N", 4.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H", 8.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:H", 7.1); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L", 5.4); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N", 4.3); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", 6.5); CHECK ("CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L", 4.3); CHECK ("CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:L", 5.6); CHECK ("CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:N", 2.7); CHECK ("CVSS:3.1/AV:P/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H", 7.1); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", 6.4); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", 4.2); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", 4.2); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", 4.2); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:L", 6.9); CHECK ("CVSS:3.1/AV:P/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H", 6.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H", 7.2); CHECK ("CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", 6.2); CHECK ("CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N", 3.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N", 3.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", 3.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N", 7.1); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L", 6.2); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N", 5.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N", 4.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H", 5.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", 4.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L", 4.9); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", 4.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", 4.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", 2.1); CHECK ("CVSS:3.1/AV:P/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N", 5.7); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 7.6); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N", 5.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", 6.8); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L", 6.4); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", 6.1); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H", 6.4); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", 6.1); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:L", 5.2); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 4.6); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L", 4.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", 3.5); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", 2.4); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", 6.1); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", 4.6); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", 2.4); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", 4.6); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", 2.4); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", 6.6); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", 4.3); CHECK ("CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", 4.3); } /* Test suite. */ int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, cvss, roundup_succeeds); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_null); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_succeeds); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_fails); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_succeeds_v3); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_succeeds_v4); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_fails_v4); add_test_with_context (suite, cvss, get_cvss_score_from_base_metrics_all_in_feed_match); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/drop_privileges.c000066400000000000000000000060101477470532200176600ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Basic support to drop privileges. */ #include "drop_privileges.h" #include /* for initgroups */ #include /* for passwd, getpwnam */ #include #include /* for geteuid, setgid, setuid */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Sets an error and return \p errorcode * * @param error Error to set. * @param errorcode Errorcode (possible values defined in drop_privileges.h), * will be returned. * @param message Message to attach to the error. * * @return \p errorcode */ static gint drop_privileges_error (GError **error, gint errorcode, const gchar *message) { g_set_error (error, GVM_DROP_PRIVILEGES, errorcode, "%s", message); return errorcode; } /** * @brief Drop privileges. * * We try to drop our (root) privileges and setuid to \p username to * minimize the risk of privilege escalation. * The current implementation is linux-specific and may not work on other * platforms. * * @param[in] username The user to become. Its safe to pass "NULL", in which * case it will default to "nobody". * @param[out] error Return location for errors or NULL if not interested * in errors. * * @return GVM_DROP_PRIVILEGES_OK in case of success. Sets \p error * otherwise and returns the error code. */ int drop_privileges (gchar *username, GError **error) { g_return_val_if_fail (*error == NULL, GVM_DROP_PRIVILEGES_ERROR_ALREADY_SET); if (username == NULL) username = "nobody"; if (geteuid () == 0) { struct passwd *user_pw; user_pw = getpwnam (username); if (user_pw) { if (initgroups (username, user_pw->pw_gid) != 0) return drop_privileges_error ( error, GVM_DROP_PRIVILEGES_FAIL_SUPPLEMENTARY, "Failed to drop supplementary groups privileges!\n"); if (setgid (user_pw->pw_gid) != 0) return drop_privileges_error (error, GVM_DROP_PRIVILEGES_FAIL_DROP_GID, "Failed to drop group privileges!\n"); if (setuid (user_pw->pw_uid) != 0) return drop_privileges_error (error, GVM_DROP_PRIVILEGES_FAIL_DROP_UID, "Failed to drop user privileges!\n"); } else { g_set_error (error, GVM_DROP_PRIVILEGES, GVM_DROP_PRIVILEGES_FAIL_UNKNOWN_USER, "Failed to get gid and uid for user %s.", username); return GVM_DROP_PRIVILEGES_FAIL_UNKNOWN_USER; } return GVM_DROP_PRIVILEGES_OK; } else { return drop_privileges_error (error, GVM_DROP_PRIVILEGES_FAIL_NOT_ROOT, "Only root can drop its privileges."); } } gvm-libs-22.20.0/base/drop_privileges.h000066400000000000000000000023111477470532200176650ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Privilege dropping header file. */ #ifndef _GVM_DROP_PRIVILEGES_H #define _GVM_DROP_PRIVILEGES_H #include /** * @brief The GQuark for privilege dropping errors. */ #define GVM_DROP_PRIVILEGES \ g_quark_from_static_string ("gvm-drop-privileges-error-quark") /** * @brief Definition of the return code ERROR_ALREADY_SET. */ #define GVM_DROP_PRIVILEGES_ERROR_ALREADY_SET -1 /** * @brief Definition of the return code OK. */ #define GVM_DROP_PRIVILEGES_OK 0 /** * @brief Definition of the return code FAIL_NOT_ROOT. */ #define GVM_DROP_PRIVILEGES_FAIL_NOT_ROOT 1 /** * @brief Definition of the return code FAIL_UNKNOWN_USER. */ #define GVM_DROP_PRIVILEGES_FAIL_UNKNOWN_USER 2 /** * @brief Definition of the return code FAIL_DROP_GID. */ #define GVM_DROP_PRIVILEGES_FAIL_DROP_GID 3 /** * @brief Definition of the return code FAIL_DROP_UID. */ #define GVM_DROP_PRIVILEGES_FAIL_DROP_UID 4 /** * @brief Definition of the return code FAIL_SUPPLEMENTARY. */ #define GVM_DROP_PRIVILEGES_FAIL_SUPPLEMENTARY 5 int drop_privileges (gchar *username, GError **error); #endif gvm-libs-22.20.0/base/gvm_sentry.c000066400000000000000000000046441477470532200166730ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2017-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of sentry methods. * * This file contains all methods needed for sentry. To enable sentry and log * log in the sentry server, methods in this file are called. * */ #include "gvm_sentry.h" #include /** * @brief Check for sentry support * * @return 1 if gvm-libs has been built with sentry support, 0 otherwise. * */ int gvm_has_sentry_support () { #ifdef HAVE_SENTRY return 1; #endif /* HAVE_SENTRY */ return 0; } #ifdef HAVE_SENTRY int global_init_sentry = 0; /** * @brief Set global_init_sentry */ static void set_init_sentry () { global_init_sentry = 1; } /** * @brief Reset global_init_sentry */ static void reset_init_sentry () { global_init_sentry = 0; } /** * @brief Return if sentry was initialized or not */ static int is_sentry_initialized () { return global_init_sentry; } #endif /* HAVE_SENTRY */ /** * @brief Initialize Sentry * * The function does nothing if HAVE_SENTRY is not defined * * @param[in] dsn Sentry DSN * @param[in] release Module release to be sent to Sentry. */ void gvm_sentry_init (const char *dsn, const char *release) { #ifdef HAVE_SENTRY sentry_options_t *options = sentry_options_new (); sentry_options_set_dsn (options, dsn); sentry_options_set_release (options, release); sentry_options_set_sample_rate (options, 1.0); sentry_init (options); set_init_sentry (); #else (void) dsn; (void) release; #endif /* HAVE_SENTRY */ } /** * @brief Send a message to Sentry server if it was initialized * * The function does nothing if HAVE_SENTRY is not defined * * @param[in] message Message to send */ void gvm_sentry_log (const char *message) { #ifdef HAVE_SENTRY if (is_sentry_initialized ()) { sentry_capture_event (sentry_value_new_message_event ( /* level */ SENTRY_LEVEL_INFO, /* logger */ "custom", /* message */ message)); } #else (void) message; #endif /* HAVE_SENTRY */ } /** * @brief Shutdown Sentry if it was initialized. * * This function must be called before exiting to ensure that all * message has been sent to Sentry. * * The function does nothing if HAVE_SENTRY is not defined * */ void gvm_close_sentry (void) { #ifdef HAVE_SENTRY if (is_sentry_initialized ()) { sentry_close (); reset_init_sentry (); } #endif /* HAVE_SENTRY */ } gvm-libs-22.20.0/base/gvm_sentry.h000066400000000000000000000011371477470532200166720ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2017-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of sentry methods. * * This file contains all methods needed for sentry. To enable sentry and log * log in the sentry server, methods in this file are called. * */ #ifndef _GVM_SENTRY_H #define _GVM_SENTRY_H #ifdef HAVE_SENTRY #include #endif /* HAVE_SENTRY*/ void gvm_sentry_init (const char *, const char *); void gvm_sentry_log (const char *); void gvm_close_sentry (void); int gvm_has_sentry_support (void); #endif /* not _GVM_SENTRY_H */ gvm-libs-22.20.0/base/hosts.c000066400000000000000000001627511477470532200156420ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of an API to handle Hosts objects * * This file contains all methods to handle Hosts collections (gvm_hosts_t) * and single hosts objects (gvm_host_t.) * * The module consequently uses glib datatypes. */ #include "hosts.h" #include "networking.h" /* for ipv4_as_ipv6, addr6_as_str, gvm_resolve */ #include /* for inet_pton, inet_ntop */ #include /* for assert */ #include /* for isdigit */ #include #include /* for getnameinfo, NI_NAMEREQD */ #include /* for uint8_t, uint32_t */ #include /* for sscanf, perror */ #include /* for strtol, atoi */ #include /* for strchr, memcpy, memcmp, bzero, strcasecmp */ #include /* for AF_INET, AF_INET6, sockaddr */ #include /* for usleep() */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /* Static variables */ gchar *host_type_str[HOST_TYPE_MAX] = { [HOST_TYPE_NAME] = "Hostname", [HOST_TYPE_IPV4] = "IPv4", [HOST_TYPE_IPV6] = "IPv6", [HOST_TYPE_CIDR_BLOCK] = "IPv4 CIDR block", [HOST_TYPE_RANGE_SHORT] = "IPv4 short range", [HOST_TYPE_RANGE_LONG] = "IPv4 long range"}; /* Function definitions */ /** * @brief Checks if a buffer points to a valid IPv4 address. * "192.168.11.1" is valid, "192.168.1.300" and "192.168.1.1e" are not. * * @param[in] str Buffer to check in. * * @return 1 if valid IPv4 address, 0 otherwise. */ static int is_ipv4_address (const char *str) { struct sockaddr_in sa; return inet_pton (AF_INET, str, &(sa.sin_addr)) == 1; } /** * @brief Checks if a buffer points to a valid IPv6 address. * "0:0:0:0:0:0:0:1", "::1" and "::FFFF:192.168.13.55" are valid "::1g" is not. * * @param[in] str Buffer to check in. * * @return 1 if valid IPv6 address, 0 otherwise. */ static int is_ipv6_address (const char *str) { struct sockaddr_in6 sa6; return inet_pton (AF_INET6, str, &(sa6.sin6_addr)) == 1; } /** * @brief Checks if a buffer points to an IPv4 CIDR-expressed block. * "192.168.12.3/24" is valid, "192.168.1.3/31" is not. * * @param[in] str Buffer to check in. * * @return 1 if valid CIDR-expressed block, 0 otherwise. */ static int is_cidr_block (const char *str) { long block; char *addr_str, *block_str, *p; addr_str = g_strdup (str); block_str = strchr (addr_str, '/'); if (block_str == NULL) { g_free (addr_str); return 0; } /* Separate the address from the block value. */ *block_str = '\0'; block_str++; if (!is_ipv4_address (addr_str) || !isdigit (*block_str)) { g_free (addr_str); return 0; } p = NULL; block = strtol (block_str, &p, 10); if (*p || block <= 0 || block > 30) { g_free (addr_str); return 0; } g_free (addr_str); return 1; } /** * @brief Gets the network block value from a CIDR-expressed block string. * For "192.168.1.1/24" it is 24. * * @param[in] str Buffer containing CIDR-expressed block. * @param[out] block Variable to store block value. * * @return -1 if error, 0 otherwise. */ static int cidr_get_block (const char *str, unsigned int *block) { if (str == NULL || block == NULL) return -1; if (sscanf (str, "%*[0-9.]/%2u", block) != 1) return -1; return 0; } /** * @brief Gets the IPv4 value from a CIDR-expressed block. * eg. For "192.168.1.10/24" it is "192.168.1.10". * * @param[in] str String containing CIDR-expressed block. * @param[out] addr Variable to store the IPv4 address value. * * @return -1 if error, 0 otherwise. */ static int cidr_get_ip (const char *str, struct in_addr *addr) { gchar *addr_str, *tmp; if (str == NULL || addr == NULL) return -1; addr_str = g_strdup (str); tmp = strchr (addr_str, '/'); if (tmp == NULL) { g_free (addr_str); return -1; } *tmp = '\0'; if (inet_pton (AF_INET, addr_str, addr) != 1) return -1; g_free (addr_str); return 0; } /** * @brief Gets the first and last usable IPv4 addresses from a CIDR-expressed * block. eg. "192.168.1.0/24" would give 192.168.1.1 as first and 192.168.1.254 * as last. * * Both network and broadcast addresses are skipped: * - They are _never_ used as a host address. Not being included is the expected * behaviour from users. * - When needed, short/long ranges (eg. 192.168.1.0-255) are available. * * @param[in] str Buffer containing CIDR-expressed block. * @param[out] first First IPv4 address in block. * @param[out] last Last IPv4 address in block. * * @return -1 if error, 0 else. */ static int cidr_block_ips (const char *str, struct in_addr *first, struct in_addr *last) { unsigned int block; if (str == NULL || first == NULL || last == NULL) return -1; /* Get IP and block values. */ if (cidr_get_block (str, &block) == -1) return -1; if (cidr_get_ip (str, first) == -1) return -1; /* First IP: And with mask and increment. */ first->s_addr &= htonl (0xffffffff ^ ((1 << (32 - block)) - 1)); first->s_addr = htonl (ntohl (first->s_addr) + 1); /* Last IP: First IP + Number of usable hosts - 1. */ last->s_addr = htonl (ntohl (first->s_addr) + (1 << (32 - block)) - 3); return 0; } /** * @brief Checks if a buffer points to a valid long range-expressed network. * "192.168.12.1-192.168.13.50" is valid. * * @param[in] str Buffer to check in. * * @return 1 if valid long range-expressed network, 0 otherwise. */ static int is_long_range_network (const char *str) { char *first_str, *second_str; int ret; first_str = g_strdup (str); second_str = strchr (first_str, '-'); if (second_str == NULL) { g_free (first_str); return 0; } /* Separate the addresses. */ *second_str = '\0'; second_str++; ret = is_ipv4_address (first_str) && is_ipv4_address (second_str); g_free (first_str); return ret; } /** * @brief Gets the first and last IPv4 addresses from a long range-expressed * network. eg. "192.168.1.1-192.168.2.40" would give 192.168.1.1 as first and * 192.168.2.40 as last. * * @param[in] str String containing long range-expressed network. * @param[out] first First IP address in block. * @param[out] last Last IP address in block. * * @return -1 if error, 0 else. */ static int long_range_network_ips (const char *str, struct in_addr *first, struct in_addr *last) { char *first_str, *last_str; if (str == NULL || first == NULL || last == NULL) return -1; first_str = g_strdup (str); last_str = strchr (first_str, '-'); if (last_str == NULL) { g_free (first_str); return -1; } /* Separate the two IPs. */ *last_str = '\0'; last_str++; if (inet_pton (AF_INET, first_str, first) != 1 || inet_pton (AF_INET, last_str, last) != 1) { g_free (first_str); return -1; } g_free (first_str); return 0; } /** * @brief Checks if a buffer points to a valid short range-expressed network. * "192.168.11.1-50" is valid, "192.168.1.1-50e" and "192.168.1.1-300" are not. * * @param str String to check in. * * @return 1 if str points to a valid short range-network, 0 otherwise. */ static int is_short_range_network (const char *str) { long end; char *ip_str, *end_str, *p; ip_str = g_strdup (str); end_str = strchr (ip_str, '-'); if (end_str == NULL) { g_free (ip_str); return 0; } /* Separate the addresses. */ *end_str = '\0'; end_str++; if (!is_ipv4_address (ip_str) || !isdigit (*end_str)) { g_free (ip_str); return 0; } p = NULL; end = strtol (end_str, &p, 10); if (*p || end < 0 || end > 255) { g_free (ip_str); return 0; } g_free (ip_str); return 1; } /** * @brief Gets the first and last IPv4 addresses from a short range-expressed * network. "192.168.1.1-40" would give 192.168.1.1 as first and 192.168.1.40 as * last. * * @param[in] str String containing short range-expressed network. * @param[out] first First IP address in block. * @param[out] last Last IP address in block. * * @return -1 if error, 0 else. */ static int short_range_network_ips (const char *str, struct in_addr *first, struct in_addr *last) { char *first_str, *last_str; int end; if (str == NULL || first == NULL || last == NULL) return -1; first_str = g_strdup (str); last_str = strchr (first_str, '-'); if (last_str == NULL) { g_free (first_str); return -1; } /* Separate the two IPs. */ *last_str = '\0'; last_str++; end = atoi (last_str); /* Get the first IP */ if (inet_pton (AF_INET, first_str, first) != 1) { g_free (first_str); return -1; } /* Get the last IP */ last->s_addr = htonl ((ntohl (first->s_addr) & 0xffffff00) + end); g_free (first_str); return 0; } /** * @brief Checks if a buffer points to a valid hostname. * * @param[in] str String to check. * * @return 1 if valid hostname, 0 otherwise. */ static int is_hostname (const char *str) { gchar *copy, **point, **split; /* From * https://stackoverflow.com/questions/2532053/validate-a-hostname-string. */ /* Remove one dot from the end. */ copy = g_strdup (str); if (copy[strlen (copy) - 1] == '.') copy[strlen (copy) - 1] = '\0'; /* Check length. */ if (strlen (copy) == 0 || strlen (copy) > 253) { g_free (copy); return 0; } /* Split on dots. */ point = split = g_strsplit (copy, ".", 0); g_free (copy); /* Last part (TLD) may not be an integer. */ if (*point) { gchar *last; while (*(point + 1)) point++; last = *point; if (strlen (last)) { while (*last && isdigit (*last)) last++; if (*last == '\0') return 0; } } /* Check each part. */ point = split; while (*point) if (g_regex_match_simple ("^(?!-)[a-z0-9_-]{1,63}(? 128) { g_free (addr6_str); return 0; } g_free (addr6_str); return 1; } /** * @brief Gets the network block value from a CIDR-expressed block string. * For "192.168.1.1/24" it is 24. * * @param[in] str Buffer containing CIDR-expressed block. * @param[out] block Variable to store block value. * * @return -1 if error, 0 otherwise. */ static int cidr6_get_block (const char *str, unsigned int *block) { if (str == NULL || block == NULL) return -1; if (sscanf (str, "%*[0-9a-fA-F.:]/%3u", block) != 1) return -1; return 0; } /** * @brief Gets the IPv4 value from a CIDR-expressed block. * eg. For "192.168.1.10/24" it is "192.168.1.10". * * @param[in] str String containing CIDR-expressed block. * @param[out] addr6 Variable to store the IPv4 address value. * * @return -1 if error, 0 otherwise. */ static int cidr6_get_ip (const char *str, struct in6_addr *addr6) { gchar *addr6_str, *tmp; if (str == NULL || addr6 == NULL) return -1; addr6_str = g_strdup (str); tmp = strchr (addr6_str, '/'); if (tmp == NULL) { g_free (addr6_str); return -1; } *tmp = '\0'; if (inet_pton (AF_INET6, addr6_str, addr6) != 1) return -1; g_free (addr6_str); return 0; } /** * @brief Gets the first and last usable IPv4 addresses from a CIDR-expressed * block. eg. "192.168.1.0/24 would give 192.168.1.1 as first and 192.168.1.254 * as last. Thus, it skips the network and broadcast addresses. * * @param[in] str Buffer containing CIDR-expressed block. * @param[out] first First IPv4 address in block. * @param[out] last Last IPv4 address in block. * * @return -1 if error, 0 else. */ static int cidr6_block_ips (const char *str, struct in6_addr *first, struct in6_addr *last) { unsigned int block; int i, j; if (str == NULL || first == NULL || last == NULL) return -1; /* Get IP and block values. */ if (cidr6_get_block (str, &block) == -1) return -1; if (cidr6_get_ip (str, first) == -1) return -1; memcpy (&last->s6_addr, &first->s6_addr, 16); /* /128 => Specified address is the first and last one. */ if (block == 128) return 0; /* First IP: And with mask and increment to skip network address. */ j = 15; for (i = (128 - block) / 8; i > 0; i--) { first->s6_addr[j] = 0; j--; } first->s6_addr[j] &= 0xff ^ ((1 << ((128 - block) % 8)) - 1); /* Last IP: Broadcast address - 1. */ j = 15; for (i = (128 - block) / 8; i > 0; i--) { last->s6_addr[j] = 0xff; j--; } last->s6_addr[j] |= (1 << ((128 - block) % 8)) - 1; /* /127 => Only two addresses. Don't skip network / broadcast addresses.*/ if (block == 127) return 0; /* Increment first IP. */ for (i = 15; i >= 0; --i) if (first->s6_addr[i] < 255) { first->s6_addr[i]++; break; } else first->s6_addr[i] = 0; /* Decrement last IP. */ for (i = 15; i >= 0; --i) if (last->s6_addr[i] > 0) { last->s6_addr[i]--; break; } else last->s6_addr[i] = 0xff; return 0; } /** * @brief Checks if a buffer points to a valid long IPv6 range-expressed * network. "::fee5-::1:530" is valid. * * @param[in] str Buffer to check in. * * @return 1 if valid long range-expressed network, 0 otherwise. */ static int is_long_range6_network (const char *str) { char *first_str, *second_str; int ret; first_str = g_strdup (str); second_str = strchr (first_str, '-'); if (second_str == NULL) { g_free (first_str); return 0; } /* Separate the addresses. */ *second_str = '\0'; second_str++; ret = is_ipv6_address (first_str) && is_ipv6_address (second_str); g_free (first_str); return ret; } /** * @brief Gets the first and last IPv6 addresses from a long range-expressed * network. eg. "::1:200:7-::1:205:500" would give ::1:200:7 as first and * ::1:205:500 as last. * * @param[in] str String containing long IPv6 range-expressed network. * @param[out] first First IPv6 address in range. * @param[out] last Last IPv6 address in range. * * @return -1 if error, 0 else. */ static int long_range6_network_ips (const char *str, struct in6_addr *first, struct in6_addr *last) { char *first_str, *last_str; if (str == NULL || first == NULL || last == NULL) return -1; first_str = g_strdup (str); last_str = strchr (first_str, '-'); if (last_str == NULL) { g_free (first_str); return -1; } /* Separate the two IPs. */ *last_str = '\0'; last_str++; if (inet_pton (AF_INET6, first_str, first) != 1 || inet_pton (AF_INET6, last_str, last) != 1) { g_free (first_str); return -1; } g_free (first_str); return 0; } /** * @brief Checks if a buffer points to a valid short IPv6 range-expressed * network. "::200:ff:1-fee5" is valid. * * @param str String to check in. * * @return 1 if str points to a valid short-range IPv6 network, 0 otherwise. */ static int is_short_range6_network (const char *str) { char *ip_str, *end_str, *p; ip_str = g_strdup (str); end_str = strchr (ip_str, '-'); if (end_str == NULL) { g_free (ip_str); return 0; } /* Separate the addresses. */ *end_str = '\0'; end_str++; if (!is_ipv6_address (ip_str) || *end_str == '\0') { g_free (ip_str); return 0; } p = end_str; /* Check that the 2nd part is at most 4 hexadecimal characters. */ while (isxdigit (*p) && p++) ; if (*p || p - end_str > 4) { g_free (ip_str); return 0; } g_free (ip_str); return 1; } /** * @brief Gets the first and last IPv6 addresses from a short range-expressed * network. eg. "\::ffee:1:1001-1005" would give \::ffee:1:1001 as first and * \::ffee:1:1005 as last. * * @param[in] str String containing short IPv6 range-expressed network. * @param[out] first First IPv6 address in range. * @param[out] last Last IPv6 address in range. * * @return -1 if error, 0 else. */ static int short_range6_network_ips (const char *str, struct in6_addr *first, struct in6_addr *last) { char *first_str, *last_str; long int end; if (str == NULL || first == NULL || last == NULL) return -1; first_str = g_strdup (str); last_str = strchr (first_str, '-'); if (last_str == NULL) { g_free (first_str); return -1; } /* Separate the first IP. */ *last_str = '\0'; last_str++; if (inet_pton (AF_INET6, first_str, first) != 1) { g_free (first_str); return -1; } /* Calculate the last IP. */ memcpy (last, first, sizeof (*last)); end = strtol (last_str, NULL, 16); memcpy (&last->s6_addr[15], &end, 1); memcpy (&last->s6_addr[14], ((char *) &end) + 1, 1); g_free (first_str); return 0; } /** * @brief Determines the host type in a buffer. * * @param[in] str_stripped Buffer that contains host definition, could a be * hostname, single IPv4 or IPv6, CIDR-expressed block etc,. * * @return Host_TYPE_*, -1 if error. */ int gvm_get_host_type (const gchar *str_stripped) { /* * We have a single element with no leading or trailing * white spaces. This element could represent different host * definitions: single IPs, host names, CIDR-expressed blocks, * range-expressed networks, IPv6 addresses. */ /* Null or empty string. */ if (str_stripped == NULL || *str_stripped == '\0') return -1; /* Check for regular single IPv4 address. */ if (is_ipv4_address (str_stripped)) return HOST_TYPE_IPV4; /* Check for regular single IPv6 address. */ if (is_ipv6_address (str_stripped)) return HOST_TYPE_IPV6; /* Check for regular IPv4 CIDR-expressed block like "192.168.12.0/24" */ if (is_cidr_block (str_stripped)) return HOST_TYPE_CIDR_BLOCK; /* Check for short range-expressed networks "192.168.12.5-40" */ if (is_short_range_network (str_stripped)) return HOST_TYPE_RANGE_SHORT; /* Check for long range-expressed networks "192.168.1.0-192.168.3.44" */ if (is_long_range_network (str_stripped)) return HOST_TYPE_RANGE_LONG; /* Check for regular IPv6 CIDR-expressed block like "2620:0:2d0:200::7/120" */ if (is_cidr6_block (str_stripped)) return HOST_TYPE_CIDR6_BLOCK; /* Check for short range-expressed networks "::1-ef12" */ if (is_short_range6_network (str_stripped)) return HOST_TYPE_RANGE6_SHORT; /* Check for long IPv6 range-expressed networks like "::1:20:7-::1:25:3" */ if (is_long_range6_network (str_stripped)) return HOST_TYPE_RANGE6_LONG; /* Check for hostname. */ if (is_hostname (str_stripped)) return HOST_TYPE_NAME; return -1; } /** * @brief Creates a new gvm_vhost_t object. * * @param[in] value Vhost value. * @param[in] source Source of hostname. * * @return Pointer to new vhost object. */ gvm_vhost_t * gvm_vhost_new (char *value, char *source) { gvm_vhost_t *vhost; vhost = g_malloc0 (sizeof (gvm_vhost_t)); vhost->value = value; vhost->source = source; return vhost; } /** * @brief Frees the memory occupied by an gvm_vhost_t object. * * @param[in] vhost Vhost to free. */ static void gvm_vhost_free (gpointer vhost) { if (vhost) { g_free (((gvm_vhost_t *) vhost)->value); g_free (((gvm_vhost_t *) vhost)->source); } g_free (vhost); } /** * @brief Creates a deep copy of a gvm_vhost_t object. * * @param vhost source vhost * @param data dummy for g_slist_copy_deep * @return gpointer copy of vhost */ gpointer gvm_duplicate_vhost (gconstpointer vhost, gpointer data) { (void) (data); gvm_vhost_t *ret = NULL; if (!vhost) return NULL; ret = gvm_vhost_new (g_strdup (((gvm_vhost_t *) vhost)->value), g_strdup (((gvm_vhost_t *) vhost)->source)); return ret; } /** * @brief Creates a new gvm_host_t object. * * @return Pointer to new host object, NULL if creation fails. */ static gvm_host_t * gvm_host_new () { gvm_host_t *host; host = g_malloc0 (sizeof (gvm_host_t)); return host; } /** * @brief Frees the memory occupied by an gvm_host_t object. * * @param[in] host Host to free. */ void gvm_host_free (gpointer host) { gvm_host_t *h = host; if (h == NULL) return; /* If host of type hostname, free the name buffer, first. */ if (h->type == HOST_TYPE_NAME) g_free (h->name); g_slist_free_full (h->vhosts, gvm_vhost_free); g_free (h); } /** * @brief Inserts a host object at the end of a hosts collection. * * @param[in] hosts Hosts in which to insert the host. * @param[in] host Host to insert. */ void gvm_hosts_add (gvm_hosts_t *hosts, gvm_host_t *host) { if (hosts->count == hosts->max_size) { hosts->max_size *= 4; hosts->hosts = g_realloc_n (hosts->hosts, hosts->max_size, sizeof (*hosts->hosts)); memset (hosts->hosts + hosts->count, '\0', (hosts->max_size - hosts->count) * sizeof (gvm_host_t *)); } hosts->hosts[hosts->count] = host; hosts->count++; } /** * @brief Creates a hosts collection from a hosts string. * * @param[in] hosts_str String of hosts. * * @return Hosts collection. */ static gvm_hosts_t * gvm_hosts_init (const char *hosts_str) { gvm_hosts_t *hosts; hosts = g_malloc0 (sizeof (gvm_hosts_t)); hosts->max_size = 1024; hosts->hosts = g_malloc0_n (hosts->max_size, sizeof (gvm_host_t *)); hosts->orig_str = g_strdup (hosts_str); return hosts; } /** * @brief Fill the gaps in the array of a hosts collection, which are caused by * the removal of host entries. * * @param[in] hosts Hosts collection to fill gaps in. */ static void gvm_hosts_fill_gaps (gvm_hosts_t *hosts) { size_t i; if (!hosts) return; for (i = 0; i < hosts->max_size; i++) { if (!hosts->hosts[i]) { size_t j; /* Fill the gap with the closest host entry, in order to keep the * sequential ordering. */ for (j = i + 1; j < hosts->max_size; j++) { if (hosts->hosts[j]) { hosts->hosts[i] = hosts->hosts[j]; hosts->hosts[j] = NULL; break; } } /* No more entries left, ie. the empty space between count and * max_size. */ if (!hosts->hosts[i]) return; } } } /** * @brief Removes duplicate hosts values from an gvm_hosts_t structure. * Also resets the iterator current position. * * @param[in] hosts hosts collection from which to remove duplicates. */ static void gvm_hosts_deduplicate (gvm_hosts_t *hosts) { /** * Uses a hash table in order to deduplicate the hosts list in O(N) time. */ GHashTable *name_table; size_t i, duplicates = 0; if (hosts == NULL) return; name_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < hosts->count; i++) { gchar *name; name = gvm_host_value_str (hosts->hosts[i]); if (name) { gvm_host_t *host, *removed = hosts->hosts[i]; host = g_hash_table_lookup (name_table, name); if (host) { /* Remove duplicate host. Add its vhosts to the original host. */ host->vhosts = g_slist_concat (host->vhosts, removed->vhosts); removed->vhosts = NULL; gvm_host_free (removed); hosts->hosts[i] = NULL; duplicates++; g_free (name); } else g_hash_table_insert (name_table, name, hosts->hosts[i]); } } if (duplicates) gvm_hosts_fill_gaps (hosts); g_hash_table_destroy (name_table); hosts->count -= duplicates; hosts->duplicated += duplicates; hosts->current = 0; #ifdef __GLIBC__ malloc_trim (0); #endif } /** * @brief Creates a new gvm_hosts_t structure and the associated hosts * objects from the provided hosts_str. * * @param[in] hosts_str The hosts string. A copy will be created of this within * the returned struct. * @param[in] max_hosts Max number of hosts in hosts_str. 0 means unlimited. * * @return NULL if error or hosts_str contains more than max hosts. Otherwise, a * hosts structure that should be released using @ref gvm_hosts_free. */ gvm_hosts_t * gvm_hosts_new_with_max (const gchar *hosts_str, unsigned int max_hosts) { gvm_hosts_t *hosts; gchar **host_element, **split; gchar *str; if (hosts_str == NULL) return NULL; /* Normalize separator: Transform newlines into commas. */ hosts = gvm_hosts_init (hosts_str); str = hosts->orig_str; while (*str) { if (*str == '\n') *str = ','; str++; } /* Split comma-separated list into single host-specifications */ split = g_strsplit (hosts->orig_str, ",", 0); /* first element of the split list */ host_element = split; while (*host_element) { int host_type; gchar *stripped = g_strstrip (*host_element); if (stripped == NULL || *stripped == '\0') { host_element++; continue; } /* IPv4, hostname, IPv6, collection (short/long range, cidr block) etc,. ? */ /* -1 if error. */ host_type = gvm_get_host_type (stripped); switch (host_type) { case HOST_TYPE_NAME: case HOST_TYPE_IPV4: case HOST_TYPE_IPV6: { /* New host. */ gvm_host_t *host = gvm_host_new (); host->type = host_type; if (host_type == HOST_TYPE_NAME) host->name = g_ascii_strdown (stripped, -1); else if (host_type == HOST_TYPE_IPV4) { if (inet_pton (AF_INET, stripped, &host->addr) != 1) break; } else if (host_type == HOST_TYPE_IPV6) { if (inet_pton (AF_INET6, stripped, &host->addr6) != 1) break; } gvm_hosts_add (hosts, host); break; } case HOST_TYPE_CIDR_BLOCK: case HOST_TYPE_RANGE_SHORT: case HOST_TYPE_RANGE_LONG: { struct in_addr first, last; uint32_t current; int (*ips_func) (const char *, struct in_addr *, struct in_addr *); if (host_type == HOST_TYPE_CIDR_BLOCK) ips_func = cidr_block_ips; else if (host_type == HOST_TYPE_RANGE_SHORT) ips_func = short_range_network_ips; else ips_func = long_range_network_ips; if (ips_func (stripped, &first, &last) == -1) break; /* Make sure that first actually comes before last */ if (ntohl (first.s_addr) > ntohl (last.s_addr)) break; /* Add addresses from first to last as single hosts. */ current = first.s_addr; while (ntohl (current) <= ntohl (last.s_addr)) { gvm_host_t *host; if (max_hosts > 0 && hosts->count > max_hosts) { g_strfreev (split); gvm_hosts_free (hosts); return NULL; } host = gvm_host_new (); host->type = HOST_TYPE_IPV4; host->addr.s_addr = current; gvm_hosts_add (hosts, host); /* Next IP address. */ current = htonl (ntohl (current) + 1); } break; } case HOST_TYPE_CIDR6_BLOCK: case HOST_TYPE_RANGE6_LONG: case HOST_TYPE_RANGE6_SHORT: { struct in6_addr first, last; unsigned char current[16]; int (*ips_func) (const char *, struct in6_addr *, struct in6_addr *); if (host_type == HOST_TYPE_CIDR6_BLOCK) ips_func = cidr6_block_ips; else if (host_type == HOST_TYPE_RANGE6_SHORT) ips_func = short_range6_network_ips; else ips_func = long_range6_network_ips; if (ips_func (stripped, &first, &last) == -1) break; /* Make sure the first comes before the last. */ if (memcmp (&first.s6_addr, &last.s6_addr, 16) > 0) break; /* Add addresses from first to last as single hosts. */ memcpy (current, &first.s6_addr, 16); while (memcmp (current, &last.s6_addr, 16) <= 0) { int i; gvm_host_t *host; if (max_hosts > 0 && hosts->count > max_hosts) { g_strfreev (split); gvm_hosts_free (hosts); return NULL; } host = gvm_host_new (); host->type = HOST_TYPE_IPV6; memcpy (host->addr6.s6_addr, current, 16); gvm_hosts_add (hosts, host); /* Next IPv6 address. */ for (i = 15; i >= 0; --i) if (current[i] < 255) { current[i]++; break; } else current[i] = 0; } break; } case -1: default: /* Invalid host string. */ g_strfreev (split); gvm_hosts_free (hosts); return NULL; } host_element++; /* move on to next element of split list */ if (max_hosts > 0 && hosts->count > max_hosts) { g_strfreev (split); gvm_hosts_free (hosts); return NULL; } } /* No need to check for duplicates when a hosts string contains a * single (IP/Hostname/Range/Subnetwork) entry. */ if (g_strv_length (split) > 1) gvm_hosts_deduplicate (hosts); g_strfreev (split); #ifdef __GLIBC__ malloc_trim (0); #endif return hosts; } /** * @brief Creates a new gvm_hosts_t structure and the associated hosts * objects from the provided hosts_str. * * @param[in] hosts_str The hosts string. A copy will be created of this within * the returned struct. * * @return NULL if error, otherwise, a hosts structure that should be released * using @ref gvm_hosts_free. */ gvm_hosts_t * gvm_hosts_new (const gchar *hosts_str) { return gvm_hosts_new_with_max (hosts_str, 0); } /** * @brief Gets the next gvm_host_t from a gvm_hosts_t structure. The * state of iteration is kept internally within the gvm_hosts structure. * * @param[in] hosts gvm_hosts_t structure to get next host from. * * @return Pointer to host. NULL if error or end of hosts. */ gvm_host_t * gvm_hosts_next (gvm_hosts_t *hosts) { if (!hosts || hosts->current == hosts->count) return NULL; return hosts->hosts[hosts->current++]; } /** * @brief Move the current gvm_host_t from a gvm_hosts_t structure to * the end of the hosts list. * * @param[in,out] hosts gvm_hosts_t structure which hosts must be * rearange. The hosts->current index points to the last used hosts and * gvm_hosts_next() must be called to get the next host in the list. * */ void gvm_hosts_move_current_host_to_end (gvm_hosts_t *hosts) { void *host_tmp; size_t i; if (!hosts) return; if (hosts->current == hosts->count) { hosts->current -= 1; return; } hosts->current -= 1; host_tmp = hosts->hosts[hosts->current]; for (i = hosts->current; i < hosts->count; i++) hosts->hosts[i - 1] = hosts->hosts[i]; hosts->hosts[hosts->count - 1] = host_tmp; } /** * @brief Frees memory occupied by an gvm_hosts_t structure. * * @param[in] hosts The hosts collection to free. * */ void gvm_hosts_free (gvm_hosts_t *hosts) { size_t i; if (hosts == NULL) return; if (hosts->orig_str) g_free (hosts->orig_str); for (i = 0; i < hosts->count; i++) gvm_host_free (hosts->hosts[i]); g_free (hosts->hosts); g_free (hosts); hosts = NULL; } /** * @brief Randomizes the order of the hosts objects in the collection. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection to shuffle. */ void gvm_hosts_shuffle (gvm_hosts_t *hosts) { size_t i = 0; GRand *rand; if (hosts == NULL) return; /* Shuffle the array. */ rand = g_rand_new (); for (i = 0; i < hosts->count; i++) { void *tmp; int j = g_rand_int_range (rand, 0, hosts->count); tmp = hosts->hosts[i]; hosts->hosts[i] = hosts->hosts[j]; hosts->hosts[j] = tmp; } hosts->current = 0; g_rand_free (rand); } /** * @brief Reverses the order of the hosts objects in the collection. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection to reverse. */ void gvm_hosts_reverse (gvm_hosts_t *hosts) { size_t i, j; if (hosts == NULL) return; for (i = 0, j = hosts->count - 1; i < j; i++, j--) { gvm_host_t *tmp = hosts->hosts[i]; hosts->hosts[i] = hosts->hosts[j]; hosts->hosts[j] = tmp; } hosts->current = 0; } /** * @brief Resolves host objects of type name in a hosts collection, replacing * hostnames with IPv4 values. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection from which to exclude. * * @return List of unresolved hostnames. */ GSList * gvm_hosts_resolve (gvm_hosts_t *hosts) { size_t i, new_entries = 0, resolved = 0; GSList *unresolved = NULL; for (i = 0; i < hosts->count; i++) { GSList *list, *tmp; gvm_host_t *host = hosts->hosts[i]; if (host->type != HOST_TYPE_NAME) continue; list = tmp = gvm_resolve_list (host->name); while (tmp) { /* Create a new host for each IP address. */ gvm_host_t *new; struct in6_addr *ip6 = tmp->data; gvm_vhost_t *vhost; new = gvm_host_new (); if (ip6->s6_addr32[0] != 0 || ip6->s6_addr32[1] != 0 || ip6->s6_addr32[2] != htonl (0xffff)) { new->type = HOST_TYPE_IPV6; memcpy (&new->addr6, ip6, sizeof (new->addr6)); } else { new->type = HOST_TYPE_IPV4; memcpy (&new->addr6, &ip6->s6_addr32[3], sizeof (new->addr)); } vhost = gvm_vhost_new (g_strdup (host->name), g_strdup ("Forward-DNS")); new->vhosts = g_slist_prepend (new->vhosts, vhost); gvm_hosts_add (hosts, new); tmp = tmp->next; new_entries = 1; } /* Remove hostname from list, as it was either replaced by IPs, or * is unresolvable. */ hosts->hosts[i] = NULL; resolved++; if (!list) unresolved = g_slist_prepend (unresolved, g_strdup (host->name)); gvm_host_free (host); g_slist_free_full (list, g_free); } if (resolved) gvm_hosts_fill_gaps (hosts); hosts->count -= resolved; hosts->removed += resolved; if (new_entries) gvm_hosts_deduplicate (hosts); hosts->current = 0; return unresolved; } /** * @brief Exclude a list of vhosts from a host's vhosts list. * * @param[in] host The host whose vhosts are to be excluded from. * @param[in] excluded_str String of hosts to exclude. * * @return Number of excluded vhosts. */ int gvm_vhosts_exclude (gvm_host_t *host, const char *excluded_str) { GSList *vhost; char **excluded; int ret = 0; if (!host || !excluded_str) return ret; vhost = host->vhosts; excluded = g_strsplit (excluded_str, ",", 0); if (!excluded || !*excluded) { g_strfreev (excluded); return ret; } while (vhost) { char **tmp = excluded; char *value = ((gvm_vhost_t *) vhost->data)->value; while (*tmp) { if (!strcasecmp (value, g_strstrip (*tmp))) { gvm_vhost_free (vhost->data); host->vhosts = vhost = g_slist_delete_link (host->vhosts, vhost); ret++; break; } tmp++; if (!*tmp) { vhost = vhost->next; break; } } } g_strfreev (excluded); return ret; } /** * @brief Excludes a set of hosts provided as a string from a hosts collection. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in,out] hosts The hosts collection from which to exclude. * @param[in] excluded_str String of hosts to exclude. * @param[in] max_hosts Max number of hosts in hosts_str. 0 means unlimited. * * @return Number of excluded hosts, -1 if error. */ int gvm_hosts_exclude_with_max (gvm_hosts_t *hosts, const char *excluded_str, unsigned int max_hosts) { /** * Uses a hash table in order to exclude hosts in O(N+M) time. */ gvm_hosts_t *excluded_hosts; GHashTable *name_table; size_t excluded = 0, i; if (hosts == NULL || excluded_str == NULL) return -1; excluded_hosts = gvm_hosts_new_with_max (excluded_str, max_hosts); if (excluded_hosts == NULL) return -1; if (gvm_hosts_count (excluded_hosts) == 0) { gvm_hosts_free (excluded_hosts); return 0; } /* Hash host values from excluded hosts list. */ name_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < excluded_hosts->count; i++) { gchar *name; name = gvm_host_value_str (excluded_hosts->hosts[i]); if (name) g_hash_table_insert (name_table, name, hosts); } /* Check for hosts values in hash table. */ for (i = 0; i < hosts->count; i++) { gchar *name; name = gvm_host_value_str (hosts->hosts[i]); if (name) { if (g_hash_table_lookup (name_table, name)) { gvm_host_free (hosts->hosts[i]); hosts->hosts[i] = NULL; excluded++; g_free (name); continue; } g_free (name); } } /* Cleanup. */ if (excluded) gvm_hosts_fill_gaps (hosts); hosts->count -= excluded; hosts->removed += excluded; hosts->current = 0; g_hash_table_destroy (name_table); gvm_hosts_free (excluded_hosts); return excluded; } /** * @brief Returns a list of hosts after a host authorization check. * * @param[in,out] hosts The hosts collection from which to exclude. * @param[in] deny_hosts_str String of denied hosts. This hosts will be * removed from the hosts list * @param[in] allow_hosts_str String of allow hosts. This hosts will be kept * in the hosts list * * @return List of non-authorized hosts if any, otherwise Null. The returned * list must be free()'d by the caller functions. */ GSList * gvm_hosts_allowed_only (gvm_hosts_t *hosts, const char *deny_hosts_str, const char *allow_hosts_str) { /** * Uses a hash table in order to exclude hosts in O(N+M) time. */ gvm_hosts_t *allowed_hosts, *denied_hosts; GHashTable *name_allow_table = NULL, *name_deny_table = NULL; GSList *removed = NULL; size_t excluded = 0, i; if (hosts == NULL || (deny_hosts_str == NULL && allow_hosts_str == NULL)) return NULL; // Prepare list of denied and allowed hosts denied_hosts = gvm_hosts_new_with_max (deny_hosts_str, 0); allowed_hosts = gvm_hosts_new_with_max (allow_hosts_str, 0); if (denied_hosts == NULL && allowed_hosts == NULL) return NULL; if (gvm_hosts_count (denied_hosts) == 0) gvm_hosts_free (denied_hosts); else { /* Hash host values from denied hosts list. */ name_deny_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < denied_hosts->count; i++) { gchar *name; name = gvm_host_value_str (denied_hosts->hosts[i]); if (name) g_hash_table_insert (name_deny_table, name, hosts); } } if (gvm_hosts_count (allowed_hosts) == 0) gvm_hosts_free (allowed_hosts); else { /* Hash host values from allowed hosts list. */ name_allow_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < allowed_hosts->count; i++) { gchar *name; name = gvm_host_value_str (allowed_hosts->hosts[i]); if (name) g_hash_table_insert (name_allow_table, name, hosts); } } /* Check for authorized hosts in hash table and create a list of removed * hosts. */ for (i = 0; i < hosts->count; i++) { gchar *name; name = gvm_host_value_str (hosts->hosts[i]); if (name) { if (denied_hosts != NULL && g_hash_table_lookup (name_deny_table, name)) { gvm_host_free (hosts->hosts[i]); hosts->hosts[i] = NULL; excluded++; removed = g_slist_prepend (removed, name); continue; } else if (allowed_hosts != NULL && !g_hash_table_lookup (name_allow_table, name)) { gvm_host_free (hosts->hosts[i]); hosts->hosts[i] = NULL; excluded++; removed = g_slist_prepend (removed, name); continue; } g_free (name); } } /* Cleanup. */ if (excluded) gvm_hosts_fill_gaps (hosts); hosts->count -= excluded; hosts->removed += excluded; hosts->current = 0; if (name_allow_table != NULL) g_hash_table_destroy (name_allow_table); if (name_deny_table != NULL) g_hash_table_destroy (name_deny_table); if (allowed_hosts != NULL) gvm_hosts_free (allowed_hosts); if (denied_hosts != NULL) gvm_hosts_free (denied_hosts); return removed; } /** * @brief Excludes a set of hosts provided as a string from a hosts collection. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection from which to exclude. * @param[in] excluded_str String of hosts to exclude. * * @return Number of excluded hosts, -1 if error. */ int gvm_hosts_exclude (gvm_hosts_t *hosts, const char *excluded_str) { return gvm_hosts_exclude_with_max (hosts, excluded_str, 0); } /** * @brief Creates a new gvm_host_t from a host string. * * @param[in] host_str The host string can consist of a hostname, IPv4 address * or IPv6 address. * * @return NULL if error. Otherwise, a single host structure that should be put * into a gvm_hosts_t structure for freeing with @ref gvm_hosts_free or * freed directly via @ref gvm_host_free. */ gvm_host_t * gvm_host_from_str (const gchar *host_str) { int host_type; if (host_str == NULL) return NULL; /* IPv4, hostname, IPv6 */ /* -1 if error. */ host_type = gvm_get_host_type (host_str); switch (host_type) { case HOST_TYPE_NAME: case HOST_TYPE_IPV4: case HOST_TYPE_IPV6: { /* New host. */ gvm_host_t *host = gvm_host_new (); host->type = host_type; if (host_type == HOST_TYPE_NAME) host->name = g_ascii_strdown (host_str, -1); else if (host_type == HOST_TYPE_IPV4) { if (inet_pton (AF_INET, host_str, &host->addr) != 1) break; } else if (host_type == HOST_TYPE_IPV6) { if (inet_pton (AF_INET6, host_str, &host->addr6) != 1) break; } return host; } case -1: default: return NULL; } return NULL; } /** * @brief Checks for a host object reverse dns lookup existence. * * @param[in] host The host to reverse-lookup. * * @return Result of look-up, NULL otherwise. */ char * gvm_host_reverse_lookup (gvm_host_t *host) { int retry = 10; gchar hostname[NI_MAXHOST]; void *addr; size_t addrlen; struct sockaddr_in sa; struct sockaddr_in6 sa6; if (!host) return NULL; if (host->type == HOST_TYPE_IPV4) { addr = &sa; addrlen = sizeof (sa); memset (addr, '\0', addrlen); sa.sin_addr = host->addr; sa.sin_family = AF_INET; } else if (host->type == HOST_TYPE_IPV6) { addr = &sa6; addrlen = sizeof (sa6); memset (&sa6, '\0', addrlen); memcpy (&sa6.sin6_addr, &host->addr6, 16); sa6.sin6_family = AF_INET6; } else return NULL; while (retry--) { int ret = getnameinfo (addr, addrlen, hostname, sizeof (hostname), NULL, 0, NI_NAMEREQD); if (!ret) return g_ascii_strdown (hostname, -1); if (ret != EAI_AGAIN) break; usleep (10000); // 10ms } return NULL; } /** * @brief Verifies that hostname value resolves to a host's IP. * * @param[in] host The host whose IP is to be checked against. * @param[in] value Hostname value to verify. * * @return 0 if hostname resolves to host's IP, -1 otherwise. */ static int host_name_verify (gvm_host_t *host, const char *value) { GSList *list, *tmp; char *host_str; int ret = -1; assert (host); assert (value); host_str = gvm_host_value_str (host); list = tmp = gvm_resolve_list (value); while (tmp) { char buffer[INET6_ADDRSTRLEN]; addr6_to_str (tmp->data, buffer); if (!strcasecmp (host_str, buffer)) { ret = 0; break; } tmp = tmp->next; } g_free (host_str); g_slist_free_full (list, g_free); return ret; } /** * @brief Add a host's reverse-lookup name to the vhosts list. * * @param[in] host The host to which we add the vhost. */ void gvm_host_add_reverse_lookup (gvm_host_t *host) { GSList *vhosts; gvm_vhost_t *vhost; char *value; if (!host || host->type == HOST_TYPE_NAME) return; value = gvm_host_reverse_lookup (host); if (!value) return; if (host_name_verify (host, value)) { g_free (value); return; } /* Don't add vhost, if already in the list. */ vhosts = host->vhosts; while (vhosts) { if (!strcasecmp (((gvm_vhost_t *) vhosts->data)->value, value)) { g_free (value); return; } vhosts = vhosts->next; } vhost = gvm_vhost_new (value, g_strdup ("Reverse-DNS")); host->vhosts = g_slist_prepend (host->vhosts, vhost); } /** * @brief Removes hosts that don't reverse-lookup from the hosts collection. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection to filter. * * @return list of hosts removed, Null on error. */ gvm_hosts_t * gvm_hosts_reverse_lookup_only_excluded (gvm_hosts_t *hosts) { size_t i, count = 0; gvm_hosts_t *excluded = gvm_hosts_new (""); if (hosts == NULL) return NULL; for (i = 0; i < hosts->count; i++) { gchar *name = gvm_host_reverse_lookup (hosts->hosts[i]); if (name == NULL) { gvm_hosts_add (excluded, gvm_duplicate_host (hosts->hosts[i])); gvm_host_free (hosts->hosts[i]); hosts->hosts[i] = NULL; count++; } else g_free (name); } if (count) gvm_hosts_fill_gaps (hosts); hosts->count -= count; hosts->removed += count; hosts->current = 0; return excluded; } /** * @brief Removes hosts that don't reverse-lookup from the hosts collection. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection to filter. * * @return Number of hosts removed, -1 if error. */ int gvm_hosts_reverse_lookup_only (gvm_hosts_t *hosts) { gvm_hosts_t *excluded; int count = 0; if (hosts == NULL) return -1; excluded = gvm_hosts_reverse_lookup_only_excluded (hosts); count = excluded->count; gvm_hosts_free (excluded); return count; } /** * @brief Removes hosts duplicates that reverse-lookup to the same value. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection to filter. * * @return List of hosts removed, Null if error. */ gvm_hosts_t * gvm_hosts_reverse_lookup_unify_excluded (gvm_hosts_t *hosts) { /** * Uses a hash table in order to unify the hosts list in O(N) time. */ size_t i, count = 0; GHashTable *name_table; gvm_hosts_t *excluded = NULL; if (hosts == NULL) return NULL; excluded = gvm_hosts_new (""); name_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < hosts->count; i++) { gchar *name; name = gvm_host_reverse_lookup (hosts->hosts[i]); if (name) { if (g_hash_table_lookup (name_table, name)) { gvm_hosts_add (excluded, gvm_duplicate_host (hosts->hosts[i])); gvm_host_free (hosts->hosts[i]); hosts->hosts[i] = NULL; count++; g_free (name); } else { /* Insert in the hash table. Value not important. */ g_hash_table_insert (name_table, name, hosts); } } } if (count) gvm_hosts_fill_gaps (hosts); g_hash_table_destroy (name_table); hosts->removed += count; hosts->count -= count; hosts->current = 0; return excluded; } /** * @brief Removes hosts duplicates that reverse-lookup to the same value. * Not to be used while iterating over the single hosts as it resets the * iterator. * * @param[in] hosts The hosts collection to filter. * * @return Number of hosts removed, -1 if error. */ int gvm_hosts_reverse_lookup_unify (gvm_hosts_t *hosts) { gvm_hosts_t *excluded = NULL; int count = 0; if (hosts == NULL) return -1; excluded = gvm_hosts_reverse_lookup_unify_excluded (hosts); count = excluded->count; gvm_hosts_free (excluded); return count; } /** * @brief Gets the count of single hosts objects in a hosts collection. * * @param[in] hosts The hosts collection to count hosts of. * * @return The number of single hosts. */ unsigned int gvm_hosts_count (const gvm_hosts_t *hosts) { return hosts ? hosts->count : 0; } /** * @brief Gets the count of single values in hosts string that were removed * (duplicates / excluded.) * * @param[in] hosts The hosts collection. * * @return The number of removed values. */ unsigned int gvm_hosts_removed (const gvm_hosts_t *hosts) { return hosts ? hosts->removed : 0; } /** * @brief Gets the count of single values in hosts string that were duplicated * and therefore removed from the list * * @param[in] hosts The hosts collection. * * @return The number of duplicated values. */ unsigned int gvm_hosts_duplicated (const gvm_hosts_t *hosts) { return hosts ? hosts->duplicated : 0; } /** * @brief Find the gvm_host_t from a gvm_hosts_t structure. * * @param[in] host The host object. * @param[in] addr Optional pointer to ip address. Could be used so that host * isn't resolved multiple times when type is HOST_TYPE_NAME. * @param[in] hosts Hosts collection. * * @return Pointer to host if found. NULL if error or host not found */ gvm_host_t * gvm_host_find_in_hosts (const gvm_host_t *host, const struct in6_addr *addr, const gvm_hosts_t *hosts) { char *host_str; size_t i; if (host == NULL || hosts == NULL) return NULL; host_str = gvm_host_value_str (host); for (i = 0; i < hosts->count; i++) { gvm_host_t *current_host = hosts->hosts[i]; char *tmp = gvm_host_value_str (current_host); if (strcasecmp (host_str, tmp) == 0) { g_free (host_str); g_free (tmp); return current_host; } g_free (tmp); /* Hostnames in hosts list shouldn't be resolved. */ if (addr && gvm_host_type (current_host) != HOST_TYPE_NAME) { struct in6_addr tmpaddr; gvm_host_get_addr6 (current_host, &tmpaddr); if (memcmp (addr->s6_addr, &tmpaddr.s6_addr, 16) == 0) { g_free (host_str); return current_host; } } } g_free (host_str); return NULL; } /** * @brief Creates a deep copy of a host. gvm_host_free has to be called on it. * * @param host source host * @return gvm_host_t* copy of host */ gvm_host_t * gvm_duplicate_host (gvm_host_t *host) { gvm_host_t *ret = NULL; if (host == NULL) return NULL; ret = gvm_host_new (); ret->type = host->type; switch (host->type) { case HOST_TYPE_NAME: ret->name = g_strdup (host->name); break; case HOST_TYPE_IPV4: ret->addr.s_addr = host->addr.s_addr; break; case HOST_TYPE_IPV6: ret->addr6.__in6_u = host->addr6.__in6_u; break; default: g_free (ret); return NULL; } ret->vhosts = g_slist_copy_deep (host->vhosts, gvm_duplicate_vhost, NULL); return ret; } /** * @brief Returns whether a host has an equal host in a hosts collection. * eg. 192.168.10.1 has an equal in list created from * "192.168.10.1-5, 192.168.10.10-20" string while 192.168.10.7 doesn't. * * @param[in] host The host object. * @param[in] addr Optional pointer to ip address. Could be used so that host * isn't resolved multiple times when type is HOST_TYPE_NAME. * @param[in] hosts Hosts collection. * * @return 1 if host has equal in hosts, 0 otherwise. */ int gvm_host_in_hosts (const gvm_host_t *host, const struct in6_addr *addr, const gvm_hosts_t *hosts) { if (gvm_host_find_in_hosts (host, addr, hosts)) return 1; return 0; } /** * @brief Gets a host object's type. * * @param[in] host The host object. * * @return Host type. */ enum host_type gvm_host_type (const gvm_host_t *host) { assert (host); return host->type; } /** * @brief Gets a host's type in printable format. * * @param[in] host The host object. * * @return String representing host type. Statically allocated, thus, not to be * freed. */ gchar * gvm_host_type_str (const gvm_host_t *host) { if (host == NULL) return NULL; return host_type_str[host->type]; } /** * @brief Gets a host's value in printable format. * * @param[in] host The host object. * * @return String representing host value. To be freed with g_free(). */ gchar * gvm_host_value_str (const gvm_host_t *host) { if (host == NULL) return NULL; switch (host->type) { case HOST_TYPE_NAME: return g_strdup (host->name); break; case HOST_TYPE_IPV4: case HOST_TYPE_IPV6: /* Handle both cases using inet_ntop(). */ { int family, size; gchar *str; const void *srcaddr; if (host->type == HOST_TYPE_IPV4) { family = AF_INET; size = INET_ADDRSTRLEN; srcaddr = &host->addr; } else { family = AF_INET6; size = INET6_ADDRSTRLEN; srcaddr = &host->addr6; } str = g_malloc0 (size); if (inet_ntop (family, srcaddr, str, size) == NULL) { perror ("inet_ntop"); g_free (str); return NULL; } return str; } default: return g_strdup ("Erroneous host type: Should be Hostname/IPv4/IPv6."); } } /** * @brief Resolves a host object's name to an IPv4 or IPv6 address. Host object * should be of type HOST_TYPE_NAME. * * @param[in] host The host object whose name to resolve. * @param[out] dst Buffer to store resolved address. Size must be at least * 4 bytes for AF_INET and 16 bytes for AF_INET6. * @param[in] family Either AF_INET or AF_INET6. * * @return -1 if error, 0 otherwise. */ int gvm_host_resolve (const gvm_host_t *host, void *dst, int family) { if (host == NULL || dst == NULL || host->type != HOST_TYPE_NAME) return -1; return gvm_resolve (host->name, dst, family); } /** * @brief Gives a host object's value as an IPv6 address. * If the host type is hostname, it resolves the IPv4 address then gives an * IPv4-mapped IPv6 address (eg. \::ffff:192.168.1.1 .) * If the host type is IPv4, it gives an IPv4-mapped IPv6 address. * If the host's type is IPv6, it gives the value directly. * * @param[in] host The host object whose value to get as IPv6. * @param[out] ip6 Buffer to store the IPv6 address. * * @return -1 if error, 0 otherwise. */ int gvm_host_get_addr6 (const gvm_host_t *host, struct in6_addr *ip6) { if (host == NULL || ip6 == NULL) return -1; switch (gvm_host_type (host)) { case HOST_TYPE_IPV6: memcpy (ip6, &host->addr6, sizeof (struct in6_addr)); return 0; case HOST_TYPE_IPV4: ipv4_as_ipv6 (&host->addr, ip6); return 0; case HOST_TYPE_NAME: { struct in_addr ip4; /* Fail if IPv4 and IPv6 both don't resolve. */ if (gvm_host_resolve (host, &ip4, AF_INET) == 0) ipv4_as_ipv6 (&ip4, ip6); else if (gvm_host_resolve (host, ip6, AF_INET6) == -1) return -1; return 0; } default: return -1; } } gvm-libs-22.20.0/base/hosts.h000066400000000000000000000115711477470532200156400ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Protos and data structures for Hosts collections and single hosts * objects. * * This file contains the protos for \ref hosts.c */ #ifndef _GVM_HOSTS_H #define _GVM_HOSTS_H /** @brief Flag that indecates that this version includes * the function gvm_hosts_allowed_only() */ #define FEATURE_HOSTS_ALLOWED_ONLY 1 /** @brief Flag that indecates that this version includes * the functions gvm_reverse_lookup_only_excluded() * and gvm_reverse_lookup_unify_excluded() */ #define FEATURE_REVERSE_LOOKUP_EXCLUDED 1 #include /* for gchar, GList */ #include /* for in6_addr, in_addr */ /* Static values */ enum host_type { HOST_TYPE_NAME = 0, /* Hostname eg. foo */ HOST_TYPE_IPV4, /* eg. 192.168.1.1 */ HOST_TYPE_CIDR_BLOCK, /* eg. 192.168.15.0/24 */ HOST_TYPE_RANGE_SHORT, /* eg. 192.168.15.10-20 */ HOST_TYPE_RANGE_LONG, /* eg. 192.168.15.10-192.168.18.3 */ HOST_TYPE_IPV6, /* eg. ::1 */ HOST_TYPE_CIDR6_BLOCK, /* eg. ::ffee/120 */ HOST_TYPE_RANGE6_LONG, /* eg. ::1:200:7-::1:205:500 */ HOST_TYPE_RANGE6_SHORT, /* eg. ::1-fe10 */ HOST_TYPE_MAX /* Boundary checking. */ }; /* Typedefs */ typedef struct gvm_host gvm_host_t; typedef struct gvm_vhost gvm_vhost_t; typedef struct gvm_hosts gvm_hosts_t; /* Data structures. */ /** * @brief The structure for a single host object. * * The elements of this structure should never be accessed directly. * Only the functions corresponding to this module should be used. */ struct gvm_host { union { gchar *name; /**< Hostname. */ struct in_addr addr; /**< IPv4 address */ struct in6_addr addr6; /**< IPv6 address */ }; enum host_type type; /**< HOST_TYPE_NAME, HOST_TYPE_IPV4 or HOST_TYPE_IPV6. */ GSList *vhosts; /**< List of hostnames/vhosts attached to this host. */ }; /** * @brief The structure for a single vhost object. */ struct gvm_vhost { char *value; /**< Hostname string. */ char *source; /**< Source of the value eg. DNS-Resolution. */ }; /** * @brief The structure for Hosts collection. * * The elements of this structure should never be accessed directly. * Only the functions corresponding to this module should be used. */ struct gvm_hosts { gchar *orig_str; /**< Original hosts definition string. */ gvm_host_t **hosts; /**< Hosts objects list. */ size_t max_size; /**< Current max size of hosts array entries. */ size_t current; /**< Current host index in iteration. */ size_t count; /**< Number of single host objects in hosts list. */ size_t removed; /**< Number of duplicate/excluded values. */ size_t duplicated; /**< Number of duplicated values. */ }; /* Function prototypes. */ /* gvm_hosts_t related */ gvm_hosts_t * gvm_hosts_new (const gchar *); gvm_hosts_t * gvm_hosts_new_with_max (const gchar *, unsigned int); gvm_host_t * gvm_hosts_next (gvm_hosts_t *); void gvm_hosts_move_current_host_to_end (gvm_hosts_t *); void gvm_hosts_free (gvm_hosts_t *); void gvm_hosts_shuffle (gvm_hosts_t *); void gvm_hosts_reverse (gvm_hosts_t *); void gvm_hosts_add (gvm_hosts_t *, gvm_host_t *); GSList * gvm_hosts_resolve (gvm_hosts_t *); int gvm_hosts_exclude (gvm_hosts_t *, const char *); int gvm_vhosts_exclude (gvm_host_t *, const char *); int gvm_hosts_exclude_with_max (gvm_hosts_t *, const char *, unsigned int); GSList * gvm_hosts_allowed_only (gvm_hosts_t *, const char *, const char *); char * gvm_host_reverse_lookup (gvm_host_t *); int gvm_hosts_reverse_lookup_only (gvm_hosts_t *); int gvm_hosts_reverse_lookup_unify (gvm_hosts_t *); gvm_hosts_t * gvm_hosts_reverse_lookup_only_excluded (gvm_hosts_t *); gvm_hosts_t * gvm_hosts_reverse_lookup_unify_excluded (gvm_hosts_t *); unsigned int gvm_hosts_count (const gvm_hosts_t *); unsigned int gvm_hosts_removed (const gvm_hosts_t *); unsigned int gvm_hosts_duplicated (const gvm_hosts_t *); /* gvm_host_t related */ gvm_host_t * gvm_host_from_str (const gchar *hosts_str); int gvm_host_in_hosts (const gvm_host_t *, const struct in6_addr *, const gvm_hosts_t *); gvm_host_t * gvm_host_find_in_hosts (const gvm_host_t *, const struct in6_addr *, const gvm_hosts_t *); gchar * gvm_host_type_str (const gvm_host_t *); enum host_type gvm_host_type (const gvm_host_t *); gchar * gvm_host_value_str (const gvm_host_t *); int gvm_host_resolve (const gvm_host_t *, void *, int); int gvm_host_get_addr6 (const gvm_host_t *, struct in6_addr *); void gvm_host_add_reverse_lookup (gvm_host_t *); void gvm_host_free (gpointer); gpointer gvm_duplicate_vhost (gconstpointer, gpointer); gvm_host_t * gvm_duplicate_host (gvm_host_t *); /* Miscellaneous functions */ gvm_vhost_t * gvm_vhost_new (char *, char *); int gvm_get_host_type (const gchar *); #endif /* not _GVM_HOSTS_H */ gvm-libs-22.20.0/base/hosts_tests.c000066400000000000000000000265341477470532200170620ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "hosts.c" #include "networking.h" #include #include Describe (hosts); BeforeEach (hosts) { } AfterEach (hosts) { } /* make_hosts */ Ensure (hosts, gvm_hosts_new_never_returns_null) { assert_that (gvm_hosts_new (""), is_not_null); assert_that (gvm_hosts_new ("172.10.1.1"), is_not_null); assert_that (gvm_hosts_new ("172.10.1.1/24"), is_not_null); } Ensure (hosts, gvm_get_host_type_returns_host_type_ipv4) { assert_that (gvm_get_host_type ("192.168.0.4"), is_equal_to (HOST_TYPE_IPV4)); assert_that (gvm_get_host_type ("1.1.1.1"), is_equal_to (HOST_TYPE_IPV4)); assert_that (gvm_get_host_type ("0.0.0.0"), is_equal_to (HOST_TYPE_IPV4)); assert_that (gvm_get_host_type ("255.255.255.255"), is_equal_to (HOST_TYPE_IPV4)); assert_that (gvm_get_host_type ("10.1.1.1"), is_equal_to (HOST_TYPE_IPV4)); } Ensure (hosts, gvm_get_host_type_returns_host_type_ipv6) { assert_that (gvm_get_host_type ("::ffee"), is_equal_to (HOST_TYPE_IPV6)); assert_that (gvm_get_host_type ("0001:1:1:1::1"), is_equal_to (HOST_TYPE_IPV6)); } #define TEN "0123456789" #define SIXTY TEN TEN TEN TEN TEN TEN #define HUNDRED TEN TEN TEN TEN TEN TEN TEN TEN TEN TEN Ensure (hosts, gvm_get_host_type_returns_host_type_hostname) { assert_that (gvm_get_host_type ("www.greenbone.net"), is_equal_to (HOST_TYPE_NAME)); assert_that (gvm_get_host_type ("www.example_underscore.net"), is_equal_to (HOST_TYPE_NAME)); assert_that (gvm_get_host_type ("www.example-dash.net"), is_equal_to (HOST_TYPE_NAME)); assert_that (gvm_get_host_type ("greenbone.net"), is_equal_to (HOST_TYPE_NAME)); assert_that (gvm_get_host_type ("g"), is_equal_to (HOST_TYPE_NAME)); assert_that (gvm_get_host_type ("123.com"), is_equal_to (HOST_TYPE_NAME)); /* Lengths. */ assert_that (gvm_get_host_type (SIXTY "123.short.enough.com"), is_equal_to (0)); assert_that (gvm_get_host_type (SIXTY "." SIXTY "." SIXTY "." SIXTY "." "56789.com"), is_equal_to (0)); } Ensure (hosts, gvm_get_host_type_returns_host_type_cidr_block) { assert_that (gvm_get_host_type ("192.168.0.0/24"), is_equal_to (HOST_TYPE_CIDR_BLOCK)); assert_that (gvm_get_host_type ("1.1.1.1/8"), is_equal_to (HOST_TYPE_CIDR_BLOCK)); assert_that (gvm_get_host_type ("192.168.1.128/25"), is_equal_to (HOST_TYPE_CIDR_BLOCK)); assert_that (gvm_get_host_type ("10.0.0.1/16"), is_equal_to (HOST_TYPE_CIDR_BLOCK)); assert_that (gvm_get_host_type ("10.1.1.0/30"), is_equal_to (HOST_TYPE_CIDR_BLOCK)); } Ensure (hosts, gvm_get_host_type_returns_host_type_cidr6_block) { assert_that (gvm_get_host_type ("::ffee:1/64"), is_equal_to (HOST_TYPE_CIDR6_BLOCK)); assert_that (gvm_get_host_type ("2001:db8::/78"), is_equal_to (HOST_TYPE_CIDR6_BLOCK)); assert_that (gvm_get_host_type ("2001:db8:0000:0000:001f:ffff:ffff:1/1"), is_equal_to (HOST_TYPE_CIDR6_BLOCK)); } Ensure (hosts, gvm_get_host_type_returns_host_type_range_short) { assert_that (gvm_get_host_type ("192.168.10.1-9"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("192.168.10.1-50"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("192.168.10.1-255"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("1.1.1.1-9"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("1.1.1.1-50"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("1.1.1.1-255"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("255.255.255.1-9"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("255.255.255.1-50"), is_equal_to (HOST_TYPE_RANGE_SHORT)); assert_that (gvm_get_host_type ("255.255.255.1-255"), is_equal_to (HOST_TYPE_RANGE_SHORT)); } Ensure (hosts, gvm_get_host_type_returns_host_type_range6_short) { assert_that (gvm_get_host_type ("::ffee:1-fe50"), is_equal_to (HOST_TYPE_RANGE6_SHORT)); assert_that (gvm_get_host_type ("2000::-ffff"), is_equal_to (HOST_TYPE_RANGE6_SHORT)); } Ensure (hosts, gvm_get_host_type_returns_host_type_range_long) { assert_that (gvm_get_host_type ("192.168.10.1-192.168.10.9"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("192.168.10.1-192.168.10.50"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("192.168.10.1-192.168.10.255"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("1.1.1.1-1.1.1.9"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("1.1.1.1-1.1.1.50"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("1.1.1.1-1.1.1.255"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("255.255.255.1-255.255.255.9"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("255.255.255.1-255.255.255.50"), is_equal_to (HOST_TYPE_RANGE_LONG)); assert_that (gvm_get_host_type ("255.255.255.1-255.255.255.255"), is_equal_to (HOST_TYPE_RANGE_LONG)); } Ensure (hosts, gvm_get_host_type_returns_host_type_range6_long) { assert_that ( gvm_get_host_type ("2001:db0::-2001:0dbf:ffff:ffff:ffff:ffff:ffff:ffff"), is_equal_to (HOST_TYPE_RANGE6_LONG)); assert_that (gvm_get_host_type ("::1:200:7-::1:205:500"), is_equal_to (HOST_TYPE_RANGE6_LONG)); } Ensure (hosts, gvm_get_host_type_returns_error) { assert_that (gvm_get_host_type (""), is_equal_to (-1)); assert_that (gvm_get_host_type ("."), is_equal_to (-1)); /* Invalid chars. */ assert_that (gvm_get_host_type ("a,b"), is_equal_to (-1)); assert_that (gvm_get_host_type ("="), is_equal_to (-1)); /* Numeric TLD. */ assert_that (gvm_get_host_type ("a.123"), is_equal_to (-1)); /* IP with too many parts. */ assert_that (gvm_get_host_type ("192.168.10.1.1"), is_equal_to (-1)); /* IP with numbers out of bounds. */ assert_that (gvm_get_host_type ("256.168.10.1"), is_equal_to (-1)); assert_that (gvm_get_host_type ("192.256.10.1"), is_equal_to (-1)); assert_that (gvm_get_host_type ("192.168.256.1"), is_equal_to (-1)); assert_that (gvm_get_host_type ("192.168.10.256"), is_equal_to (-1)); assert_that (gvm_get_host_type ("192.168.10.855"), is_equal_to (-1)); /* Lengths. */ assert_that (gvm_get_host_type (SIXTY "1234.too.long.com"), is_equal_to (-1)); assert_that (gvm_get_host_type (SIXTY "." SIXTY "." SIXTY "." SIXTY "." "567890.com"), is_equal_to (-1)); } Ensure (hosts, gvm_hosts_new_with_max_returns_success) { assert_that (gvm_hosts_new_with_max ("127.0.0.1", 1), is_not_null); assert_that (gvm_hosts_new_with_max ("127.0.0.1", 2000), is_not_null); assert_that (gvm_hosts_new_with_max ("127.0.0.1,127.0.0.2", 2), is_not_null); assert_that (gvm_hosts_new_with_max ("127.0.0.1, 127.0.0.2", 2), is_not_null); } Ensure (hosts, gvm_hosts_new_with_max_returns_error) { /* Host error. */ assert_that (gvm_hosts_new_with_max ("a.123", 2), is_null); /* More than max_hosts hosts. */ assert_that (gvm_hosts_new_with_max ("127.0.0.1, 127.0.0.2", 1), is_null); /* Wrong separator. */ assert_that (gvm_hosts_new_with_max ("127.0.0.1 127.0.0.2", 2), is_null); assert_that (gvm_hosts_new_with_max ("127.0.0.1|127.0.0.2", 2), is_null); } Ensure (hosts, gvm_hosts_move_host_to_end) { gvm_hosts_t *hosts = NULL; gvm_host_t *host = NULL; int totalhosts; size_t current; hosts = gvm_hosts_new ("192.168.0.0/28"); // Get first host host = gvm_hosts_next (hosts); totalhosts = gvm_hosts_count (hosts); assert_that (totalhosts, is_equal_to (14)); while (g_strcmp0 (gvm_host_value_str (host), "192.168.0.9")) { host = gvm_hosts_next (hosts); } assert_that (g_strcmp0 (gvm_host_value_str (host), "192.168.0.9"), is_equal_to (0)); current = hosts->current; gvm_hosts_move_current_host_to_end (hosts); assert_that (hosts->current, is_equal_to (current - 1)); host = gvm_hosts_next (hosts); assert_that (g_strcmp0 (gvm_host_value_str (host), "192.168.0.10"), is_equal_to (0)); assert_that (g_strcmp0 (gvm_host_value_str (hosts->hosts[totalhosts - 1]), "192.168.0.9"), is_equal_to (0)); gvm_hosts_free (hosts); } Ensure (hosts, gvm_hosts_allowed_only) { gvm_hosts_t *hosts = NULL; gvm_host_t *host = NULL; int totalhosts; GSList *removed = NULL; hosts = gvm_hosts_new ("192.168.0.1,192.168.0.2,192.168.0.3"); removed = gvm_hosts_allowed_only (hosts, NULL, NULL); totalhosts = gvm_hosts_count (hosts); assert_that (totalhosts, is_equal_to (3)); removed = gvm_hosts_allowed_only (hosts, "192.168.0.2", NULL); totalhosts = gvm_hosts_count (hosts); assert_that (totalhosts, is_equal_to (2)); assert_that (g_slist_length (removed), is_equal_to (1)); g_slist_free_full (removed, g_free); removed = gvm_hosts_allowed_only (hosts, NULL, "192.168.0.3"); totalhosts = gvm_hosts_count (hosts); assert_that (totalhosts, is_equal_to (1)); assert_that (g_slist_length (removed), is_equal_to (1)); g_slist_free_full (removed, g_free); host = gvm_hosts_next (hosts); assert_that (g_strcmp0 (gvm_host_value_str (host), "192.168.0.3"), is_equal_to (0)); gvm_hosts_free (hosts); } /* Test suite. */ int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, hosts, gvm_hosts_new_never_returns_null); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_ipv4); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_ipv6); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_hostname); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_cidr_block); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_cidr6_block); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_range_short); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_range6_short); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_range_long); add_test_with_context (suite, hosts, gvm_get_host_type_returns_host_type_range6_long); add_test_with_context (suite, hosts, gvm_get_host_type_returns_error); add_test_with_context (suite, hosts, gvm_hosts_new_with_max_returns_error); add_test_with_context (suite, hosts, gvm_hosts_new_with_max_returns_success); add_test_with_context (suite, hosts, gvm_hosts_move_host_to_end); add_test_with_context (suite, hosts, gvm_hosts_allowed_only); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/libgvm_base.pc.in000066400000000000000000000004771477470532200175350ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@EXEC_PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: gvmlibs-base Description: Greenbone Vulnerability Management Library base Version: @LIBGVMCONFIG_VERSION@ Requires.private: glib-2.0 >= 2.42.1 Cflags: -I${includedir} -I${includedir}/gvm Libs: -L${libdir} -lgvm_base gvm-libs-22.20.0/base/logging.c000066400000000000000000000734101477470532200161210ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2017-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of logging methods. * * This file contains all methods needed for logging. To enable logging, * methods in this file are called. * * The module reuses glib datatypes and api for memory management and logging. */ #include "logging.h" #include "gvm_sentry.h" /* for gvm_sentry_log */ #include "logging_domain.h" #include /* for errno */ #include /* for dirname */ #include /* for fflush, fprintf, stderr */ #include /* for atoi */ #include /* for strcasecmp, strlen, strerror */ #define SYSLOG_NAMES #include /* for LOG_INFO, facilitynames, closelog, openlog */ #undef SYSLOG_NAMES #include /* for localtime, time, time_t */ #include /* for getpid */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Timezone to use for logs. * * NULL means to use the current timezone. */ static gchar *log_tz = NULL; /** * @brief Returns time as specified in time_fmt strftime format. * * @param time_fmt ptr to the string format to use. The strftime * man page documents the conversion specification. An * example time_fmt string is "%Y-%m-%d %H:%M:%S". * * @return NULL in case the format string is NULL. A ptr to a * string that contains the formatted date time value. * This value must be freed using glib's g_free. */ gchar * get_time (gchar *time_fmt) { time_t now; struct tm ts; gchar buf[80], *original_tz; if (!time_fmt) return NULL; if (log_tz) { original_tz = getenv ("TZ") ? g_strdup (getenv ("TZ")) : NULL; setenv ("TZ", log_tz, 1); tzset (); } /* Get the current time. */ now = time (NULL); /* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz." */ localtime_r (&now, &ts); strftime (buf, sizeof (buf), time_fmt, &ts); if (log_tz) { /* Revert to stored TZ. */ if (original_tz) { setenv ("TZ", original_tz, 1); g_free (original_tz); tzset (); } else unsetenv ("TZ"); } return g_strdup_printf ("%s", buf); } /** * @brief Return the integer corresponding to a log level string. * * @param level Level name or integer. * * @return Log level integer if level matches a level name, else 0. */ static gint level_int_from_string (const gchar *level) { if (level && strlen (level) > 0) { if (level[0] >= '0' && level[0] <= '9') return atoi (level); if (strcasecmp (level, "critical") == 0) return G_LOG_LEVEL_CRITICAL; if (strcasecmp (level, "debug") == 0) return G_LOG_LEVEL_DEBUG; if (strcasecmp (level, "error") == 0) return G_LOG_LEVEL_ERROR; if (strcasecmp (level, "info") == 0) return G_LOG_LEVEL_INFO; if (strcasecmp (level, "message") == 0) return G_LOG_LEVEL_MESSAGE; if (strcasecmp (level, "warning") == 0) return G_LOG_LEVEL_WARNING; } return 0; } /** * @brief Return the integer corresponding to a syslog facility string. * * @param facility Facility name. * * @return Facility integer if facility matches a facility name, else * LOG_LOCAL0. */ static gint facility_int_from_string (const gchar *facility) { if (facility && strlen (facility) > 0) { int i = 0; while (facilitynames[i].c_name != NULL) { if (g_ascii_strcasecmp (facility, facilitynames[i].c_name) == 0) return facilitynames[i].c_val; i++; } } return LOG_LOCAL0; } /** * @brief Loads parameters from a config file into a linked list. * * @param config_file A string containing the path to the configuration file * to load. * * @return NULL in case the config file could not be loaded or an error * occurred otherwise, a singly linked list of parameter groups * is returned. */ GSList * load_log_configuration (gchar *config_file) { GKeyFile *key_file; GKeyFileFlags flags; GError *error = NULL; /* key_file *_has_* functions requires this. */ // FIXME: If a g_* function that takes error fails, then free error. /* Groups found in the conf file. */ gchar **groups; /* Temp variable to iterate over groups. */ gchar **group; /* The link list for the structure above and it's tmp helper */ GSList *log_domain_list = NULL; /* Create a new GKeyFile object and a bitwise list of flags. */ key_file = g_key_file_new (); flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS; /* Load the GKeyFile from conf or return. */ if (!g_key_file_load_from_file (key_file, config_file, flags, &error)) { g_error ("%s: %s", config_file, error->message); } /* Get all the groups available. */ groups = g_key_file_get_groups (key_file, NULL); /* Point to the group head. */ group = groups; /* Iterate till we get to the end of the array. */ while (*group != NULL) { /* Structure to hold per group settings. */ gvm_logging_domain_t *log_domain_entry = gvm_logging_domain_new (g_strdup (*group)); /* Look for the prepend string. */ if (g_key_file_has_key (key_file, *group, "prepend", &error)) { gvm_logging_domain_set_prepend_string ( log_domain_entry, g_key_file_get_value (key_file, *group, "prepend", &error)); } /* Look for the log_separator string. */ if (g_key_file_has_key (key_file, *group, "separator", &error)) { gvm_logging_domain_set_prepend_separator ( log_domain_entry, g_key_file_get_value (key_file, *group, "separator", &error)); } /* Look for the prepend time format string. */ if (g_key_file_has_key (key_file, *group, "prepend_time_format", &error)) { gvm_logging_domain_set_prepend_time_format ( log_domain_entry, g_key_file_get_value (key_file, *group, "prepend_time_format", &error)); } /* Look for the log file string. */ if (g_key_file_has_key (key_file, *group, "file", &error)) { gvm_logging_domain_set_log_file ( log_domain_entry, g_key_file_get_value (key_file, *group, "file", &error)); } /* Look for the prepend log level string. */ if (g_key_file_has_key (key_file, *group, "level", &error)) { gchar *level; level = g_key_file_get_value (key_file, *group, "level", &error); level = g_strchug (level); gvm_logging_domain_set_default_level (log_domain_entry, level_int_from_string (level)); g_free (level); } /* Look for the syslog_facility string. */ if (g_key_file_has_key (key_file, *group, "syslog_facility", &error)) { gvm_logging_domain_set_syslog_facility ( log_domain_entry, g_key_file_get_value (key_file, *group, "syslog_facility", &error)); } else gvm_logging_domain_set_syslog_facility (log_domain_entry, g_strdup ("local0")); /* Look for the syslog_ident string. */ if (g_key_file_has_key (key_file, *group, "syslog_ident", &error)) { gvm_logging_domain_set_syslog_ident ( log_domain_entry, g_key_file_get_value (key_file, *group, "syslog_ident", &error)); } else gvm_logging_domain_set_syslog_ident (log_domain_entry, g_strdup (*group)); /* Attach the struct to the list. */ log_domain_list = g_slist_prepend (log_domain_list, log_domain_entry); group++; } /* Free the groups array. */ g_strfreev (groups); /* Free the key file. */ g_key_file_free (key_file); return log_domain_list; } /** * @brief Frees all resources loaded by the config loader. * * @param log_domain_list Head of the link list. */ void free_log_configuration (GSList *log_domain_list) { GSList *log_domain_list_tmp; /* Free the struct fields then the struct and then go the next * item in the link list. */ /* Go to the head of the list. */ log_domain_list_tmp = log_domain_list; while (log_domain_list_tmp != NULL) { gvm_logging_domain_t *log_domain_entry; /* Get the list data which is an gvm_logging_t struct. */ log_domain_entry = log_domain_list_tmp->data; /* Free the struct contents. */ gvm_logging_domain_free (log_domain_entry); /* Go to the next item. */ log_domain_list_tmp = g_slist_next (log_domain_list_tmp); } /* Free the link list. */ g_slist_free (log_domain_list); } /** * @brief Returns immediately. * * @param log_domain A string containing the message's log domain. * @param log_level Flags defining the message's log level. * @param message A string containing the log message. * @param gvm_log_config_list A pointer to the configuration linked list. */ void gvm_log_silent (const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer gvm_log_config_list) { (void) log_domain; (void) log_level; (void) message; (void) gvm_log_config_list; return; } static GMutex *logger_mutex = NULL; /** * @brief Initialize logger_mutex mutex if it was not done before. */ static void gvm_log_lock_init (void) { if (logger_mutex == NULL) { logger_mutex = g_malloc (sizeof (*logger_mutex)); g_mutex_init (logger_mutex); } } /** * @brief Try to lock logger_mutex. */ void gvm_log_lock (void) { /* Initialize logger lock if not done already. */ gvm_log_lock_init (); g_mutex_lock (logger_mutex); } /** * @brief Unlock logger_mutex. */ void gvm_log_unlock (void) { g_mutex_unlock (logger_mutex); } static char *reference = NULL; /** * @brief Set the log reference object. * * In order to be able to see which logs are related to each other, we define a * common reference for them. E.g. when multiple scans in OpenVAS are running * simultaniousely it is possible to detect all log corresponding to the same * scan. The log reference is optional and must be set before calling * setup_log_handlers. The data given must be freed by calling * free_log_reference(). If called multiple times the old reference gets freed * and the new one is set instead. * * @param ref */ void set_log_reference (char *ref) { if (reference) g_free ((char *) reference); reference = ref; } /** * @brief Get the log reference object * * This function returns the current log reference. This enables the possibility * to save or modify the current reference value. * * @return char* */ char * get_log_reference (void) { return (char *) reference; } /** * @brief Free the log reference object * * The reference object is used to detect corresponding logs. * */ void free_log_reference (void) { if (reference) g_free ((char *) reference); reference = NULL; } /** * @brief Creates the formatted string and outputs it to the log destination. * * @param log_domain A string containing the message's log domain. * @param log_level Flags defining the message's log level. * @param message A string containing the log message. * @param gvm_log_config_list A pointer to the configuration linked list. */ void gvm_log_func (const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer gvm_log_config_list) { gchar *prepend; gchar *prepend_buf; gchar *prepend_tmp; gchar *prepend_tmp1; gchar *tmp; gchar *tmpstr; int messagelen; /* For link list operations. */ GSList *log_domain_list_tmp; gvm_logging_domain_t *log_domain_entry = NULL; /* Channel to log through. */ GIOChannel *channel = NULL; GError *error = NULL; /* The default parameters to be used. The group '*' will override * these defaults if it's found. */ gchar *prepend_format = "%t %s %p - "; gchar *time_format = "%Y-%m-%d %Hh%M.%S %Z"; gchar *log_separator = ":"; gchar *log_file = "-"; GLogLevelFlags default_level = G_LOG_LEVEL_DEBUG; gchar *syslog_facility = "local0"; gchar *syslog_ident = NULL; /* Let's load the default configuration file directives from the * linked list. Scanning the link list twice is inefficient but * leaves the source cleaner. */ if (gvm_log_config_list != NULL && log_domain != NULL) { /* Go to the head of the list. */ log_domain_list_tmp = (GSList *) gvm_log_config_list; while (log_domain_list_tmp != NULL) { gvm_logging_domain_t *entry; entry = log_domain_list_tmp->data; /* Override defaults if the current linklist group name is '*'. */ if (g_ascii_strcasecmp (gvm_logging_domain_get_log_domain (entry), "*") == 0) { /* Get the list data for later use. */ log_domain_entry = entry; /* Override defaults if the group items are not null. */ if (gvm_logging_domain_get_prepend_string (log_domain_entry)) prepend_format = gvm_logging_domain_get_prepend_string (log_domain_entry); if (gvm_logging_domain_get_prepend_time_format (log_domain_entry)) time_format = gvm_logging_domain_get_prepend_time_format (log_domain_entry); if (gvm_logging_domain_get_log_file (log_domain_entry)) log_file = gvm_logging_domain_get_log_file (log_domain_entry); if (gvm_logging_domain_get_default_level (log_domain_entry)) default_level = *gvm_logging_domain_get_default_level (log_domain_entry); if (gvm_logging_domain_get_log_channel (log_domain_entry)) channel = gvm_logging_domain_get_log_channel (log_domain_entry); if (gvm_logging_domain_get_syslog_facility (log_domain_entry)) syslog_facility = gvm_logging_domain_get_syslog_facility (log_domain_entry); if (gvm_logging_domain_get_prepend_separator (log_domain_entry)) log_separator = gvm_logging_domain_get_prepend_separator (log_domain_entry); break; } /* Go to the next item. */ log_domain_list_tmp = g_slist_next (log_domain_list_tmp); } } /* Let's load the configuration file directives if a linked list item for * the log domain group exists. */ if (gvm_log_config_list != NULL && log_domain != NULL) { /* Go to the head of the list. */ log_domain_list_tmp = (GSList *) gvm_log_config_list; while (log_domain_list_tmp != NULL) { gvm_logging_domain_t *entry; entry = log_domain_list_tmp->data; /* Search for the log domain in the link list. */ if (g_ascii_strcasecmp (gvm_logging_domain_get_log_domain (entry), log_domain) == 0) { /* Get the list data which is an gvm_logging_t struct. */ log_domain_entry = entry; /* Get the struct contents. */ if (gvm_logging_domain_get_prepend_string (log_domain_entry)) prepend_format = gvm_logging_domain_get_prepend_string (log_domain_entry); if (gvm_logging_domain_get_prepend_time_format (log_domain_entry)) time_format = gvm_logging_domain_get_prepend_time_format (log_domain_entry); if (gvm_logging_domain_get_log_file (log_domain_entry)) log_file = gvm_logging_domain_get_log_file (log_domain_entry); if (gvm_logging_domain_get_default_level (log_domain_entry)) default_level = *gvm_logging_domain_get_default_level (log_domain_entry); if (gvm_logging_domain_get_log_channel (log_domain_entry)) channel = gvm_logging_domain_get_log_channel (log_domain_entry); if (gvm_logging_domain_get_syslog_facility (log_domain_entry)) syslog_facility = gvm_logging_domain_get_syslog_facility (log_domain_entry); if (gvm_logging_domain_get_syslog_ident (log_domain_entry)) syslog_ident = gvm_logging_domain_get_syslog_ident (log_domain_entry); if (gvm_logging_domain_get_prepend_separator (log_domain_entry)) log_separator = gvm_logging_domain_get_prepend_separator (log_domain_entry); break; } /* Go to the next item. */ log_domain_list_tmp = g_slist_next (log_domain_list_tmp); } } /* If the current log entry is less severe than the specified log level, * let's exit. */ if (default_level < log_level) return; /* Prepend buf is a newly allocated empty string. Makes life easier. */ prepend_buf = g_strdup (""); /* Make the tmp pointer (for iteration) point to the format string. */ tmp = prepend_format; while (*tmp != '\0') { /* If the current char is a % and the next one is a p, get the pid. */ if ((*tmp == '%') && (*(tmp + 1) == 'p')) { if (reference) { prepend_tmp = g_strdup_printf ("%s%d%s%s", prepend_buf, (int) getpid (), log_separator, reference); } else { /* Use g_strdup, a new string returned. Store it in a tmp var * until we free the old one. */ prepend_tmp = g_strdup_printf ("%s%d", prepend_buf, (int) getpid ()); } /* Free the old string. */ g_free (prepend_buf); /* Point the buf ptr to the new string. */ prepend_buf = prepend_tmp; /* Skip over the two chars we've processed '%p'. */ tmp += 2; } else if ((*tmp == '%') && (*(tmp + 1) == 't')) { /* Get time returns a newly allocated string. * Store it in a tmp var. */ prepend_tmp1 = get_time (time_format); if (!prepend_tmp1) { prepend_tmp1 = g_strdup (""); } /* Use g_strdup. New string returned. Store it in a tmp var until * we free the old one. */ prepend_tmp = g_strdup_printf ("%s%s", prepend_buf, prepend_tmp1); /* Free the time tmp var. */ g_free (prepend_tmp1); /* Free the old string. */ g_free (prepend_buf); /* Point the buf ptr to the new string. */ prepend_buf = prepend_tmp; /* Skip over the two chars we've processed '%t.' */ tmp += 2; } else if ((*tmp == '%') && (*(tmp + 1) == 's')) { /* Use g_strdup. New string returned. Store it in a tmp var until * we free the old one. */ prepend_tmp = g_strdup_printf ("%s%s", prepend_buf, log_separator); /* Free the old string. */ g_free (prepend_buf); /* Point the buf ptr to the new string. */ prepend_buf = prepend_tmp; /* Skip over the two chars we've processed '%s.' */ tmp += 2; } else { /* Jump to the next character. */ tmp++; } } /* Step through all possible messages prefixing them with an appropriate * tag. */ switch (log_level) { case G_LOG_FLAG_RECURSION: prepend = g_strdup_printf ("RECURSION%s%s", log_separator, prepend_buf); break; case G_LOG_FLAG_FATAL: prepend = g_strdup_printf ("FATAL%s%s", log_separator, prepend_buf); break; case G_LOG_LEVEL_ERROR: prepend = g_strdup_printf ("ERROR%s%s", log_separator, prepend_buf); break; case G_LOG_LEVEL_CRITICAL: prepend = g_strdup_printf ("CRITICAL%s%s", log_separator, prepend_buf); break; case G_LOG_LEVEL_WARNING: prepend = g_strdup_printf ("WARNING%s%s", log_separator, prepend_buf); break; case G_LOG_LEVEL_MESSAGE: prepend = g_strdup_printf ("MESSAGE%s%s", log_separator, prepend_buf); break; case G_LOG_LEVEL_INFO: prepend = g_strdup_printf (" INFO%s%s", log_separator, prepend_buf); break; case G_LOG_LEVEL_DEBUG: prepend = g_strdup_printf (" DEBUG%s%s", log_separator, prepend_buf); break; default: prepend = g_strdup_printf ("UNKNOWN%s%s", log_separator, prepend_buf); break; } /* If the current log entry is more severe than the specified log * level, print out the message. In case MESSAGE already ends in a * LF and there is not only the LF, remove the LF to avoid empty * lines in the log. */ messagelen = message ? strlen (message) : 0; if (messagelen > 1 && message[messagelen - 1] == '\n') messagelen--; tmpstr = g_strdup_printf ("%s%s%s%s %.*s\n", log_domain ? log_domain : "", log_separator, prepend, log_separator, messagelen, message); g_free (prepend); if (log_level <= G_LOG_LEVEL_WARNING) gvm_sentry_log (message); gvm_log_lock (); /* Output everything to stderr if logfile is NULL, an empty string or "-". */ if (!log_file || g_ascii_strcasecmp (log_file, "-") == 0 || !g_strcmp0 (log_file, "")) { fprintf (stderr, "%s", tmpstr); fflush (stderr); } /* Output everything to syslog if logfile is "syslog" */ else if (g_ascii_strcasecmp (log_file, "syslog") == 0) { int facility = facility_int_from_string (syslog_facility); int syslog_level = LOG_INFO; openlog (syslog_ident, LOG_CONS | LOG_PID | LOG_NDELAY, facility); switch (log_level) { case G_LOG_FLAG_FATAL: syslog_level = LOG_ALERT; break; case G_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break; case G_LOG_LEVEL_CRITICAL: syslog_level = LOG_CRIT; break; case G_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break; case G_LOG_LEVEL_MESSAGE: syslog_level = LOG_NOTICE; break; case G_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break; case G_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break; default: syslog_level = LOG_INFO; break; } /* Syslog doesn't support messages longer than 1kb. The overflow data will not be logged or will be shown in the hypervisor console if it runs on a virtual machine. */ if (messagelen > 1000) { int pos; char *message_aux, *message_aux2; char buffer[1000]; message_aux2 = g_strdup (message); message_aux = message_aux2; for (pos = 0; pos <= messagelen; pos = pos + sizeof (buffer) - 1) { memcpy (buffer, message_aux, sizeof (buffer) - 1); buffer[sizeof (buffer) - 1] = '\0'; message_aux = &(message_aux[sizeof (buffer) - 1]); syslog (syslog_level, "%s", buffer); } g_free (message_aux2); } else syslog (syslog_level, "%s", message); closelog (); } else { /* Open a channel and store it in the struct or * retrieve and use an already existing channel. */ if (channel == NULL) { channel = g_io_channel_new_file (log_file, "a", &error); if (!channel) { gchar *log = g_strdup (log_file); gchar *dir = dirname (log); /* Check error. In case of the directory does not exist, it will * be handle below. In other case a message is printed to the * stderr since the channel is still not created/accessible. */ if (error->code != G_FILE_ERROR_NOENT) fprintf (stderr, "Can not open '%s' logfile: %s\n", log_file, error->message); g_error_free (error); /* Ensure directory exists. */ if (g_mkdir_with_parents (dir, 0755)) /* "rwxr-xr-x" */ { g_warning ("Failed to create log file directory %s: %s", dir, strerror (errno)); g_free (log); g_free (tmpstr); g_free (prepend_buf); return; } g_free (log); /* Try again. */ error = NULL; channel = g_io_channel_new_file (log_file, "a", &error); if (!channel) { g_error ("Can not open '%s' logfile: %s", log_file, error->message); } } /* Store it in the struct for later use. */ if (log_domain_entry != NULL) gvm_logging_domain_set_log_channel (log_domain_entry, channel); } g_io_channel_write_chars (channel, (const gchar *) tmpstr, -1, NULL, &error); g_io_channel_flush (channel, NULL); } gvm_log_unlock (); g_free (tmpstr); g_free (prepend_buf); } /** * @brief This function logs debug messages from gnutls. * * @param level GnuTLS log level (integer from 0 to 99 according to GnuTLS * documentation. * @param message GnuTLS log message. * * To enable GNUTLS debug messages, the environment variable @c * OPENVAS_GNUTLS_DEBUG is to be set to the desired log level as * described in the GNUTLS manual. */ void log_func_for_gnutls (int level, const char *message) { g_log ("x gnutls", G_LOG_LEVEL_INFO, "tls(%d): %s", level, message); } /** * @brief Check permissions of log file and log file directory. * * Do not check permissions if log file is syslog or empty string. * * @param log_domain_entry Log domain entry. * * @return 0 on success, -1 on error. */ static int check_log_file (gvm_logging_domain_t *log_domain_entry) { GIOChannel *channel = NULL; GError *error = NULL; const gchar *log_file; log_file = gvm_logging_domain_get_log_file (log_domain_entry); // No log file was specified, log file is empty or set to "-" then // stderr will be used as default later on. See gvm_log_func. if (!log_file || g_ascii_strcasecmp (log_file, "-") == 0 || !g_strcmp0 (log_file, "")) return 0; // If syslog is used we do not need to check the log file permissions. if (g_ascii_strcasecmp (log_file, "syslog") == 0) return 0; channel = g_io_channel_new_file (log_file, "a", &error); if (!channel) { gchar *log = g_strdup (log_file); gchar *dir = dirname (log); /* Ensure directory exists. */ if (g_mkdir_with_parents (dir, 0755)) /* "rwxr-xr-x" */ { g_free (log); return -1; } g_free (log); /* Try again. */ error = NULL; channel = g_io_channel_new_file (log_file, "a", &error); if (!channel) return -1; } return 0; } /** * @brief Set the log timezone. * * This is the timezone used for dates in log messages. If NULL then * the current timezone is used. * * @param tz Timezone. */ void set_log_tz (const gchar *tz) { g_free (log_tz); log_tz = tz ? g_strdup (tz) : NULL; } static int setup_log_handlers_internal (GSList *gvm_log_config_list, GLogFunc log_func, GLogFunc default_log_func, GLogFunc default_domain_log_func) { GSList *log_domain_list_tmp; int err; int ret = 0; if (gvm_log_config_list != NULL) { /* Go to the head of the list. */ log_domain_list_tmp = (GSList *) gvm_log_config_list; while (log_domain_list_tmp != NULL) { gvm_logging_domain_t *log_domain_entry; /* Get the list data which is an gvm_logging_t struct. */ log_domain_entry = log_domain_list_tmp->data; err = check_log_file (log_domain_entry); if (err) { ret = -1; /* Go to the next item. */ log_domain_list_tmp = g_slist_next (log_domain_list_tmp); continue; } if (g_ascii_strcasecmp ( gvm_logging_domain_get_log_domain (log_domain_entry), "*")) { g_log_set_handler ( gvm_logging_domain_get_log_domain (log_domain_entry), (GLogLevelFlags) (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), (GLogFunc) log_func, gvm_log_config_list); } else { g_log_set_default_handler (default_log_func, gvm_log_config_list); } /* Go to the next item. */ log_domain_list_tmp = g_slist_next (log_domain_list_tmp); } } g_log_set_handler ( "", (GLogLevelFlags) (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), default_domain_log_func, gvm_log_config_list); return ret; } /** * @brief Sets up routing of logdomains to log handlers. * * Iterates over the link list and adds the groups to the handler. * * @param gvm_log_config_list A pointer to the configuration linked list. * * @return 0 on success, -1 if not able to create log file directory or open log * file for some domain. */ int setup_log_handlers (GSList *gvm_log_config_list) { return setup_log_handlers_internal (gvm_log_config_list, gvm_log_func, gvm_log_func, gvm_log_func); } gvm-libs-22.20.0/base/logging.h000066400000000000000000000016471477470532200161310ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2017-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of logging methods. */ #ifndef _GVM_LOGGING_H #define _GVM_LOGGING_H #include /* for GSList, gchar, GLogLevelFlags, gpointer */ /** * @brief for backward compatibility * */ #define LOG_REFERENCES_AVAILABLE GSList * load_log_configuration (gchar *); void free_log_configuration (GSList *); gchar * get_time (gchar *); void gvm_log_silent (const char *, GLogLevelFlags, const char *, gpointer); void gvm_log_func (const char *, GLogLevelFlags, const char *, gpointer); void log_func_for_gnutls (int, const char *); int setup_log_handlers (GSList *); void gvm_log_lock (void); void gvm_log_unlock (void); void set_log_reference (char *); char * get_log_reference (void); void free_log_reference (void); void set_log_tz (const gchar *); #endif /* not _GVM_LOGGING_H */ gvm-libs-22.20.0/base/logging_domain.c000066400000000000000000000300341477470532200174430ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "logging_domain.h" /** * @struct gvm_logging_t * @brief Logging stores the parameters loaded from a log configuration * @brief file, to be used internally by the gvm_logging module only. */ struct gvm_logging_domain { gchar *log_domain; ///< Affected logdomain e.g libnasl. gchar *prepend_string; ///< Prepend this string before every message. gchar *prepend_time_format; ///< If prependstring has %t, format for strftime. gchar *log_file; ///< Where to log to. GLogLevelFlags *default_level; ///< What severity level to use as default. GIOChannel *log_channel; ///< Gio Channel - FD holder for logfile. gchar *syslog_facility; ///< Syslog facility to use for syslog logging. gchar *syslog_ident; ///< Syslog ident to use for syslog logging. gchar *prepend_separator; ///< If prependstring has %s, used this symbol as ///< separator. }; /** * @brief Function to initialize logging instance. * * This function is responsible for setting up the logging mechanism * and returning a pointer to the logging struct. It ensures that * the logging struct is properly configured before use. * * @param log_domain A string containing the log domain to be used. * Gets owned by the logging domain and must not be freed. * * @return gvm_logging_t* Pointer to the new logging struct. */ gvm_logging_domain_t * gvm_logging_domain_new (gchar *log_domain) { gvm_logging_domain_t *log_domain_entry; /* Create the struct. */ log_domain_entry = g_malloc (sizeof (gvm_logging_domain_t)); /* Set the logdomain. */ log_domain_entry->log_domain = log_domain; /* Initialize everything else to NULL. */ log_domain_entry->prepend_string = NULL; log_domain_entry->prepend_time_format = NULL; log_domain_entry->log_file = NULL; log_domain_entry->default_level = NULL; log_domain_entry->log_channel = NULL; log_domain_entry->syslog_facility = NULL; log_domain_entry->syslog_ident = NULL; log_domain_entry->prepend_separator = NULL; return log_domain_entry; } /** * @brief Frees the resources associated with the given logging domain * * Frees the resources associated with the given logging domain. * This function should be called when the logging domain is no longer needed * to ensure that all allocated resources are properly released. * * @param log_domain A pointer to a gvm_logging_t structure representing the * logging domain to be freed. * */ void gvm_logging_domain_free (gvm_logging_domain_t *log_domain) { g_free (log_domain->log_domain); g_free (log_domain->prepend_string); g_free (log_domain->prepend_time_format); g_free (log_domain->log_file); g_free (log_domain->default_level); g_free (log_domain->syslog_ident); g_free (log_domain->prepend_separator); /* Drop the reference to the GIOChannel. */ if (log_domain->log_channel) g_io_channel_unref (log_domain->log_channel); /* Free the struct. */ g_free (log_domain); } /** * Retrieves the log domain associated with the given logging domain. * * The returned log domain is still owned by the logging domain and should not * be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The log domain associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_log_domain (gvm_logging_domain_t *log_domain) { return log_domain->log_domain; } /** * Retrieves the log file associated with the given logging domain. * * The returned log file is still owned by the logging domain and should not * be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The log file associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_log_file (gvm_logging_domain_t *log_domain) { return log_domain->log_file; } /** * @brief Sets the log file for the logging domain. * * This function sets the file to which log messages for the specified logging * domain will be written. * * @param log_domain The logging domain for which the log file is to be set. * @param log_file The path to the log file. Gets owned by the logging domain * and must not be freed. */ void gvm_logging_domain_set_log_file (gvm_logging_domain_t *log_domain, gchar *log_file) { g_free (log_domain->log_file); log_domain->log_file = log_file; } /** * Retrieves the prepend string associated with the given logging domain. * * The returned prepend string is still owned by the logging domain and should * not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The prepend string associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_prepend_string (gvm_logging_domain_t *log_domain) { return log_domain->prepend_string; } /** * @brief Sets the preprend string for the logging domain. * * This function sets the string that will be prepended to every log message * * @param log_domain The logging domain for which the prepend string is to be * set. * @param prepend_string The string to prepend. Gets owned by the logging domain * and must not be freed. */ void gvm_logging_domain_set_prepend_string (gvm_logging_domain_t *log_domain, gchar *prepend_string) { g_free (log_domain->prepend_string); log_domain->prepend_string = prepend_string; } /** * Retrieves the prepend time format associated with the given logging domain. * * The returned prepend time format is still owned by the logging domain and * should not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The prepend time format associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_prepend_time_format (gvm_logging_domain_t *log_domain) { return log_domain->prepend_time_format; } /** * @brief Sets the prepend time format for the logging domain. * * This function sets the time format that will be used when %t is present in * the prepend string. * * @param log_domain The logging domain for which the prepend time format is to * be set. * @param prepend_time_format The time format to set. Gets owned by the logging * domain and must not be freed. */ void gvm_logging_domain_set_prepend_time_format (gvm_logging_domain_t *log_domain, gchar *prepend_time_format) { g_free (log_domain->prepend_time_format); log_domain->prepend_time_format = prepend_time_format; } /** * Retrieves the default log level associated with the given logging domain. * * The returned default log level is still owned by the logging domain and * should not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The default log level associated with the logging domain or NULL */ GLogLevelFlags * gvm_logging_domain_get_default_level (gvm_logging_domain_t *log_domain) { return log_domain->default_level; } /** * @brief Sets the default log level for the logging domain. * * This function sets the default log level for the specified logging domain. * * @param log_domain The logging domain for which the default log level is to be * set. * @param default_level The default log level to set. */ void gvm_logging_domain_set_default_level (gvm_logging_domain_t *log_domain, GLogLevelFlags default_level) { g_free (log_domain->default_level); log_domain->default_level = g_malloc (sizeof (gint)); *log_domain->default_level = default_level; } /** * Retrieves the syslog facility associated with the given logging domain. * * The returned syslog facility is still owned by the logging domain and should * not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The syslog facility associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_syslog_facility (gvm_logging_domain_t *log_domain) { return log_domain->syslog_facility; } /** * @brief Sets the syslog facility for the logging domain. * * This function sets the syslog facility for the specified logging domain. * * @param log_domain The logging domain for which the syslog facility is to be * set. * @param syslog_facility The syslog facility to set. Gets owned by the logging * domain and must not be freed. */ void gvm_logging_domain_set_syslog_facility (gvm_logging_domain_t *log_domain, gchar *syslog_facility) { g_free (log_domain->syslog_facility); log_domain->syslog_facility = syslog_facility; } /** * Retrieves the syslog ident associated with the given logging domain. * * The returned syslog ident is still owned by the logging domain and should * not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The syslog ident associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_syslog_ident (gvm_logging_domain_t *log_domain) { return log_domain->syslog_ident; } /** * @brief Sets the syslog ident for the logging domain. * * This function sets the syslog ident for the specified logging domain. * * @param log_domain The logging domain for which the syslog ident is to be set. * @param syslog_ident The syslog ident to set. Gets owned by the logging domain * and must not be freed. */ void gvm_logging_domain_set_syslog_ident (gvm_logging_domain_t *log_domain, gchar *syslog_ident) { g_free (log_domain->syslog_ident); log_domain->syslog_ident = syslog_ident; } /** * Retrieves the prepend separator associated with the given logging domain. * * The returned prepend separator is still owned by the logging domain and * should not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The prepend separator associated with the logging domain or NULL */ gchar * gvm_logging_domain_get_prepend_separator (gvm_logging_domain_t *log_domain) { return log_domain->prepend_separator; } /** * @brief Sets the prepend separator for the logging domain. * * This function sets the prepend separator for the specified logging domain. * * @param log_domain The logging domain for which the prepend separator is to be * set. * @param prepend_separator The prepend separator to set. Gets owned by the * logging domain and must not be freed. */ void gvm_logging_domain_set_prepend_separator (gvm_logging_domain_t *log_domain, gchar *prepend_separator) { g_free (log_domain->prepend_separator); log_domain->prepend_separator = prepend_separator; } /** * Retrieves the log channel associated with the given logging domain. * * The returned log channel is still owned by the logging domain and should * not be freed by the caller. * * @param log_domain A pointer to a gvm_logging_domain_t structure. * * @return The log channel associated with the logging domain or NULL */ GIOChannel * gvm_logging_domain_get_log_channel (gvm_logging_domain_t *log_domain) { return log_domain->log_channel; } /** * @brief Sets the log channel for the logging domain. * * This function sets the log channel for the specified logging domain. * * @param log_domain The logging domain for which the log channel is to be set. * @param log_channel The log channel to set. Gets referenced by the logging and * unreferenced when the logging domain is freed. */ void gvm_logging_domain_set_log_channel (gvm_logging_domain_t *log_domain, GIOChannel *log_channel) { if (log_domain->log_channel) g_io_channel_unref (log_domain->log_channel); log_domain->log_channel = log_channel; if (log_channel) g_io_channel_ref (log_channel); } gvm-libs-22.20.0/base/logging_domain.h000066400000000000000000000045001477470532200174470ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of logging domain handling. */ #ifndef _GVM_LOGGING_DOMAIN_H #define _GVM_LOGGING_DOMAIN_H #include typedef struct gvm_logging_domain gvm_logging_domain_t; gvm_logging_domain_t * gvm_logging_domain_new (gchar *log_domain); void gvm_logging_domain_free (gvm_logging_domain_t *log_domain); gchar * gvm_logging_domain_get_log_domain (gvm_logging_domain_t *log_domain); gchar * gvm_logging_domain_get_log_file (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_log_file (gvm_logging_domain_t *log_domain, gchar *log_file); gchar * gvm_logging_domain_get_prepend_string (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_prepend_string (gvm_logging_domain_t *log_domain, gchar *prepend_string); gchar * gvm_logging_domain_get_prepend_time_format (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_prepend_time_format (gvm_logging_domain_t *log_domain, gchar *prepend_time_format); GLogLevelFlags * gvm_logging_domain_get_default_level (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_default_level (gvm_logging_domain_t *log_domain, GLogLevelFlags default_level); gchar * gvm_logging_domain_get_syslog_facility (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_syslog_facility (gvm_logging_domain_t *log_domain, gchar *syslog_facility); gchar * gvm_logging_domain_get_syslog_ident (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_syslog_ident (gvm_logging_domain_t *log_domain, gchar *syslog_ident); gchar * gvm_logging_domain_get_prepend_separator (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_prepend_separator (gvm_logging_domain_t *log_domain, gchar *prepend_separator); GIOChannel * gvm_logging_domain_get_log_channel (gvm_logging_domain_t *log_domain); void gvm_logging_domain_set_log_channel (gvm_logging_domain_t *log_domain, GIOChannel *log_channel); #endif /* _GVM_LOGGING_DOMAIN_H */ gvm-libs-22.20.0/base/logging_domain_tests.c000066400000000000000000000101251477470532200206640ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "logging_domain.c" #include #include #include #include Describe (logging_domain); BeforeEach (logging_domain) { } AfterEach (logging_domain) { } Ensure (logging_domain, should_initalize_logging_domain) { gvm_logging_domain_t *log_domain_entry = gvm_logging_domain_new (g_strdup ("test")); assert_that (log_domain_entry, is_not_null); assert_that (gvm_logging_domain_get_log_domain (log_domain_entry), is_equal_to_string ("test")); assert_that (gvm_logging_domain_get_log_file (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_prepend_string (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_prepend_time_format (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_default_level (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_log_channel (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_syslog_facility (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_syslog_ident (log_domain_entry), is_null); assert_that (gvm_logging_domain_get_prepend_separator (log_domain_entry), is_null); gvm_logging_domain_free (log_domain_entry); } Ensure (logging_domain, should_allow_setting_properties) { gvm_logging_domain_t *log_domain_entry = gvm_logging_domain_new (g_strdup ("test")); assert_that (log_domain_entry, is_not_null); assert_that (gvm_logging_domain_get_log_domain (log_domain_entry), is_equal_to_string ("test")); gvm_logging_domain_set_log_file (log_domain_entry, g_strdup ("logfile.log")); assert_that (gvm_logging_domain_get_log_file (log_domain_entry), is_equal_to_string ("logfile.log")); gvm_logging_domain_set_prepend_string (log_domain_entry, g_strdup ("prepend")); assert_that (gvm_logging_domain_get_prepend_string (log_domain_entry), is_equal_to_string ("prepend")); gvm_logging_domain_set_prepend_time_format (log_domain_entry, g_strdup ("%Y-%m-%d")); assert_that (gvm_logging_domain_get_prepend_time_format (log_domain_entry), is_equal_to_string ("%Y-%m-%d")); gvm_logging_domain_set_default_level (log_domain_entry, G_LOG_LEVEL_DEBUG); assert_that (*gvm_logging_domain_get_default_level (log_domain_entry), is_equal_to (G_LOG_LEVEL_DEBUG)); GIOChannel *log_channel = g_io_channel_new_file ("log_channel.log", "w", NULL); gvm_logging_domain_set_log_channel (log_domain_entry, log_channel); assert_that (gvm_logging_domain_get_log_channel (log_domain_entry), is_equal_to (log_channel)); gvm_logging_domain_set_syslog_facility (log_domain_entry, g_strdup ("user")); assert_that (gvm_logging_domain_get_syslog_facility (log_domain_entry), is_equal_to_string ("user")); gvm_logging_domain_set_syslog_ident (log_domain_entry, g_strdup ("ident")); assert_that (gvm_logging_domain_get_syslog_ident (log_domain_entry), is_equal_to_string ("ident")); gvm_logging_domain_set_prepend_separator (log_domain_entry, g_strdup ("|")); assert_that (gvm_logging_domain_get_prepend_separator (log_domain_entry), is_equal_to_string ("|")); gvm_logging_domain_free (log_domain_entry); g_remove ("log_channel.log"); } static TestSuite * logging_test_suite () { TestSuite *suite = create_test_suite (); add_test_with_context (suite, logging_domain, should_initalize_logging_domain); add_test_with_context (suite, logging_domain, should_allow_setting_properties); return suite; } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_suite (suite, logging_test_suite ()); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/logging_tests.c000066400000000000000000000317711477470532200173470ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "logging.c" #include #include #include #include Describe (logging); BeforeEach (logging) { } AfterEach (logging) { } Ensure (logging, validate_check_log_file) { gvm_logging_domain_t *log_domain_entry = gvm_logging_domain_new (g_strdup ("test")); assert_that (check_log_file (log_domain_entry), is_equal_to (0)); gvm_logging_domain_set_log_file (log_domain_entry, g_strdup ("")); assert_that (check_log_file (log_domain_entry), is_equal_to (0)); gvm_logging_domain_set_log_file (log_domain_entry, g_strdup ("syslog")); assert_that (check_log_file (log_domain_entry), is_equal_to (0)); gvm_logging_domain_set_log_file (log_domain_entry, g_strdup ("-")); assert_that (check_log_file (log_domain_entry), is_equal_to (0)); assert_that (g_file_test ("-", G_FILE_TEST_EXISTS), is_equal_to (FALSE)); gvm_logging_domain_set_log_file (log_domain_entry, g_strdup ("some-file.log")); assert_that (check_log_file (log_domain_entry), is_equal_to (0)); assert_that (g_file_test ("some-file.log", G_FILE_TEST_EXISTS), is_equal_to (1)); assert_that (g_remove ("some-file.log"), is_equal_to (0)); gvm_logging_domain_set_log_file (log_domain_entry, g_strdup ("some-dir/some-file.log")); assert_that (check_log_file (log_domain_entry), is_equal_to (0)); assert_that (g_file_test ("some-dir/some-file.log", G_FILE_TEST_EXISTS), is_equal_to (1)); assert_that (g_remove ("some-dir/some-file.log"), is_equal_to (0)); assert_that (g_rmdir ("some-dir"), is_equal_to (0)); if (getuid () != 0) { /* root can always write. therefore test writing to a non-writable file as * non-root user only */ assert_that (g_mkdir_with_parents ("some-dir", 0700), is_equal_to (0)); assert_that (g_creat ("some-dir/some-file.log", 0400), is_not_equal_to (-1)); assert_that (check_log_file (log_domain_entry), is_equal_to (-1)); assert_that (g_chmod ("some-dir/some-file.log", 0700), is_equal_to (0)); assert_that (g_remove ("some-dir/some-file.log"), is_equal_to (0)); assert_that (g_rmdir ("some-dir"), is_equal_to (0)); } gvm_logging_domain_free (log_domain_entry); } Ensure (logging, should_convert_level_int_from_string) { assert_that (level_int_from_string (NULL), is_equal_to (0)); assert_that (level_int_from_string (""), is_equal_to (0)); assert_that (level_int_from_string ("error"), is_equal_to (G_LOG_LEVEL_ERROR)); assert_that (level_int_from_string ("critical"), is_equal_to (G_LOG_LEVEL_CRITICAL)); assert_that (level_int_from_string ("warning"), is_equal_to (G_LOG_LEVEL_WARNING)); assert_that (level_int_from_string ("message"), is_equal_to (G_LOG_LEVEL_MESSAGE)); assert_that (level_int_from_string ("info"), is_equal_to (G_LOG_LEVEL_INFO)); assert_that (level_int_from_string ("debug"), is_equal_to (G_LOG_LEVEL_DEBUG)); assert_that (level_int_from_string ("4"), is_equal_to (G_LOG_LEVEL_ERROR)); assert_that (level_int_from_string ("8"), is_equal_to (G_LOG_LEVEL_CRITICAL)); assert_that (level_int_from_string ("16"), is_equal_to (G_LOG_LEVEL_WARNING)); assert_that (level_int_from_string ("32"), is_equal_to (G_LOG_LEVEL_MESSAGE)); assert_that (level_int_from_string ("64"), is_equal_to (G_LOG_LEVEL_INFO)); assert_that (level_int_from_string ("128"), is_equal_to (G_LOG_LEVEL_DEBUG)); assert_that (level_int_from_string ("123"), is_equal_to (123)); assert_that (level_int_from_string ("A"), is_equal_to (0)); } Ensure (logging, should_convert_facility_int_from_string) { assert_that (facility_int_from_string (NULL), is_equal_to (LOG_LOCAL0)); assert_that (facility_int_from_string (""), is_equal_to (LOG_LOCAL0)); assert_that (facility_int_from_string ("auth"), is_equal_to (LOG_AUTH)); assert_that (facility_int_from_string ("authpriv"), is_equal_to (LOG_AUTHPRIV)); assert_that (facility_int_from_string ("cron"), is_equal_to (LOG_CRON)); assert_that (facility_int_from_string ("daemon"), is_equal_to (LOG_DAEMON)); assert_that (facility_int_from_string ("ftp"), is_equal_to (LOG_FTP)); assert_that (facility_int_from_string ("kern"), is_equal_to (LOG_KERN)); assert_that (facility_int_from_string ("lpr"), is_equal_to (LOG_LPR)); assert_that (facility_int_from_string ("mail"), is_equal_to (LOG_MAIL)); assert_that (facility_int_from_string ("mark"), is_equal_to (INTERNAL_MARK)); assert_that (facility_int_from_string ("news"), is_equal_to (LOG_NEWS)); assert_that (facility_int_from_string ("syslog"), is_equal_to (LOG_SYSLOG)); assert_that (facility_int_from_string ("user"), is_equal_to (LOG_USER)); assert_that (facility_int_from_string ("uucp"), is_equal_to (LOG_UUCP)); assert_that (facility_int_from_string ("local0"), is_equal_to (LOG_LOCAL0)); assert_that (facility_int_from_string ("local1"), is_equal_to (LOG_LOCAL1)); assert_that (facility_int_from_string ("local2"), is_equal_to (LOG_LOCAL2)); assert_that (facility_int_from_string ("local3"), is_equal_to (LOG_LOCAL3)); assert_that (facility_int_from_string ("local4"), is_equal_to (LOG_LOCAL4)); assert_that (facility_int_from_string ("local5"), is_equal_to (LOG_LOCAL5)); assert_that (facility_int_from_string ("local6"), is_equal_to (LOG_LOCAL6)); assert_that (facility_int_from_string ("local7"), is_equal_to (LOG_LOCAL7)); assert_that (facility_int_from_string (NULL), is_equal_to (LOG_LOCAL0)); assert_that (facility_int_from_string ("unknown"), is_equal_to (LOG_LOCAL0)); } Ensure (logging, should_load_log_configuration) { gchar *config_file = "test_log_config.conf"; GSList *log_config_list; /* Create a temporary configuration file */ FILE *file = fopen (config_file, "w"); assert_that (file, is_not_null); fprintf (file, "[*]\n" "prepend=%%t %%s %%p - \n" "separator=:\n" "prepend_time_format=%%Y-%%m-%%d %%H:%%M:%%S\n" "file=-\n" "level=debug\n" "syslog_facility=local0\n" "syslog_ident=test_ident\n"); fclose (file); /* Load the configuration */ log_config_list = load_log_configuration (config_file); assert_that (log_config_list, is_not_null); /* Verify the configuration */ gvm_logging_domain_t *log_domain_entry = (gvm_logging_domain_t *) log_config_list->data; assert_that (gvm_logging_domain_get_prepend_string (log_domain_entry), is_equal_to_string ("%t %s %p - ")); assert_that (gvm_logging_domain_get_prepend_separator (log_domain_entry), is_equal_to_string (":")); assert_that (gvm_logging_domain_get_prepend_time_format (log_domain_entry), is_equal_to_string ("%Y-%m-%d %H:%M:%S")); assert_that (gvm_logging_domain_get_log_file (log_domain_entry), is_equal_to_string ("-")); assert_that (*gvm_logging_domain_get_default_level (log_domain_entry), is_equal_to (G_LOG_LEVEL_DEBUG)); assert_that (gvm_logging_domain_get_syslog_facility (log_domain_entry), is_equal_to_string ("local0")); assert_that (gvm_logging_domain_get_syslog_ident (log_domain_entry), is_equal_to_string ("test_ident")); /* Clean up */ free_log_configuration (log_config_list); g_remove (config_file); } static void mock_log_func (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { mock (log_domain, log_level, message, user_data); } static void mock_default_log_func (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { mock (log_domain, log_level, message, user_data); } static void mock_default_domain_log_func (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { mock (log_domain, log_level, message, user_data); } Ensure (logging, should_setup_log_handlers_with_default_handler) { gchar *config_file = "test_log_config.conf"; GSList *log_config_list; /* Create a temporary configuration file */ FILE *file = fopen (config_file, "w"); assert_that (file, is_not_null); // fputs ("", file); fprintf (file, "[*]\n" "prepend=%%t %%s %%p - \n" "separator=:\n" "prepend_time_format=%%Y-%%m-%%d %%H:%%M:%%S\n" "file=-\n" "level=debug\n"); fclose (file); /* Load the configuration */ log_config_list = load_log_configuration (config_file); assert_that (log_config_list, is_not_null); /* Setup log handlers */ setup_log_handlers_internal (log_config_list, mock_log_func, mock_default_log_func, mock_default_domain_log_func); /* Verify the log handlers setup */ never_expect (mock_log_func); never_expect (mock_default_domain_log_func); expect (mock_default_log_func, when (log_domain, is_equal_to_string ("foo")), when (log_level, is_equal_to (G_LOG_LEVEL_DEBUG)), when (message, is_equal_to_string ("test message")), when (user_data, is_equal_to (log_config_list))); g_log ("foo", G_LOG_LEVEL_DEBUG, "test message"); /* Clean up */ free_log_configuration (log_config_list); g_remove (config_file); } Ensure (logging, should_setup_log_handlers_with_default_domain_handler) { /* Setup log handlers */ setup_log_handlers_internal (NULL, mock_log_func, mock_default_log_func, mock_default_domain_log_func); /* Verify the log handlers setup */ never_expect (mock_default_log_func); never_expect (mock_log_func); expect (mock_default_domain_log_func, when (log_domain, is_equal_to_string ("")), when (log_level, is_equal_to (G_LOG_LEVEL_DEBUG)), when (message, is_equal_to_string ("test message")), when (user_data, is_null)); expect (mock_default_domain_log_func, when (log_domain, is_null), when (log_level, is_equal_to (G_LOG_LEVEL_INFO)), when (message, is_equal_to_string ("test message 2")), when (user_data, is_null)); g_log ("", G_LOG_LEVEL_DEBUG, "test message"); g_log (NULL, G_LOG_LEVEL_INFO, "test message 2"); } Ensure (logging, should_setup_log_handlers_with_domain_handler) { gchar *config_file = "test_log_config.conf"; GSList *log_config_list; /* Create a temporary configuration file */ FILE *file = fopen (config_file, "w"); assert_that (file, is_not_null); // fputs ("", file); fprintf (file, "[foo]\n" "prepend=%%t %%s %%p - \n" "separator=:\n" "prepend_time_format=%%Y-%%m-%%d %%H:%%M:%%S\n" "file=-\n" "level=debug\n"); fclose (file); /* Load the configuration */ log_config_list = load_log_configuration (config_file); assert_that (log_config_list, is_not_null); /* Setup log handlers */ setup_log_handlers_internal (log_config_list, mock_log_func, mock_default_log_func, mock_default_domain_log_func); /* Verify the log handlers setup */ never_expect (mock_default_log_func); never_expect (mock_default_domain_log_func); expect (mock_log_func, when (log_domain, is_equal_to_string ("foo")), when (log_level, is_equal_to (G_LOG_LEVEL_DEBUG)), when (message, is_equal_to_string ("test message")), when (user_data, is_equal_to (log_config_list))); g_log ("foo", G_LOG_LEVEL_DEBUG, "test message"); /* Clean up */ free_log_configuration (log_config_list); g_remove (config_file); } Ensure (logging, should_get_time_for_null) { assert_that (get_time (NULL), is_null); } static TestSuite * logging_test_suite () { TestSuite *suite = create_test_suite (); add_test_with_context (suite, logging, validate_check_log_file); add_test_with_context (suite, logging, should_convert_level_int_from_string); add_test_with_context (suite, logging, should_convert_facility_int_from_string); add_test_with_context (suite, logging, should_load_log_configuration); add_test_with_context (suite, logging, should_setup_log_handlers_with_default_handler); add_test_with_context (suite, logging, should_setup_log_handlers_with_default_domain_handler); add_test_with_context (suite, logging, should_setup_log_handlers_with_domain_handler); add_test_with_context (suite, logging, should_setup_log_handlers_with_domain_handler); add_test_with_context (suite, logging, should_get_time_for_null); return suite; } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_suite (suite, logging_test_suite ()); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/networking.c000066400000000000000000001030371477470532200166610ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of GVM Networking related API. */ #include "networking.h" #include /* for inet_ntop */ #include /* for assert */ #include /* for isblank */ #include /* for errno, EAFNOSUPPORT */ #include #include /* for ifaddrs, freeifaddrs, getifaddrs */ #include /* for IFNAMSIZ */ #include /* for uint32_t, uint8_t */ #include /* for atoi, strtol */ #include /* for memcpy, bzero, strchr, strlen, strcmp, strncpy */ #include /* for AF_INET, AF_INET6, AF_UNSPEC, sockaddr_storage */ #include /* for close */ #ifdef __FreeBSD__ #include #define s6_addr32 __u6_addr.__u6_addr32 #endif #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" #if GLIB_CHECK_VERSION(2, 67, 3) #define memdup g_memdup2 #else #define memdup g_memdup #endif /* Global variables */ /* Source interface name eg. eth1. */ char global_source_iface[IFNAMSIZ] = {'\0'}; /* Source IPv4 address. */ struct in_addr global_source_addr = {.s_addr = 0}; /* Source IPv6 address. */ struct in6_addr global_source_addr6 = {.s6_addr32 = {0, 0, 0, 0}}; /* Source Interface/Address related functions. */ /** * @brief Initializes the source network interface name and related information. * * @param[in] iface Name of network interface to use as source interface. * * @return 0 if success. If error, return 1 and reset source values to default. */ int gvm_source_iface_init (const char *iface) { struct ifaddrs *ifaddr, *ifa; int ret = 1; bzero (global_source_iface, sizeof (global_source_iface)); global_source_addr.s_addr = INADDR_ANY; global_source_addr6 = in6addr_any; if (iface == NULL) return ret; if (strlen (iface) >= sizeof (global_source_iface)) return ret; if (getifaddrs (&ifaddr) == -1) return ret; /* Search for the adequate interface/family. */ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr && strcmp (iface, ifa->ifa_name) == 0) { if (ifa->ifa_addr->sa_family == AF_INET) { struct in_addr *addr = &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; memcpy (&global_source_addr, addr, sizeof (global_source_addr)); ret = 0; } else if (ifa->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; addr = (struct sockaddr_in6 *) ifa->ifa_addr; memcpy (&global_source_addr6.s6_addr, &addr->sin6_addr, sizeof (struct in6_addr)); ret = 0; } } } /* At least one address for the interface was found. */ if (ret == 0) memcpy (global_source_iface, iface, strlen (iface)); freeifaddrs (ifaddr); return ret; } /** * @brief Check if global_source @ref global_source_iface is set. * * @return 1 if set, 0 otherwise. */ int gvm_source_iface_is_set (void) { return *global_source_iface != '\0'; } /** * @brief Binds a socket to use the global source address. * * @param[in] socket Socket to set source address for. * @param[in] port Network port for socket. * @param[in] family Family of socket. AF_INET or AF_INET6. * * @return 0 if success, -1 if error. */ int gvm_source_set_socket (int socket, int port, int family) { if (family == AF_INET) { struct sockaddr_in addr; bzero (&addr, sizeof (addr)); gvm_source_addr (&addr.sin_addr); addr.sin_port = htons (port); addr.sin_family = AF_INET; if (bind (socket, (struct sockaddr *) &addr, sizeof (addr)) < 0) return -1; } else if (family == AF_INET6) { struct sockaddr_in6 addr6; bzero (&addr6, sizeof (addr6)); gvm_source_addr6 (&addr6.sin6_addr); addr6.sin6_port = htons (port); addr6.sin6_family = AF_INET6; if (bind (socket, (struct sockaddr *) &addr6, sizeof (addr6)) < 0) return -1; } else return -1; return 0; } /** * @brief Gives the source IPv4 address. * * @param[out] addr Buffer of at least 4 bytes. */ void gvm_source_addr (void *addr) { if (addr) memcpy (addr, &global_source_addr.s_addr, 4); } /** * @brief Gives the source IPv6 address. * * @param[out] addr6 Buffer of at least 16 bytes. */ void gvm_source_addr6 (void *addr6) { if (addr6) memcpy (addr6, &global_source_addr6.s6_addr, 16); } /** * @brief Gives the source IPv4 mapped as an IPv6 address. * eg. 192.168.20.10 would map to \::ffff:192.168.20.10. * * @param[out] addr6 Buffer of at least 16 bytes. */ void gvm_source_addr_as_addr6 (struct in6_addr *addr6) { if (addr6) ipv4_as_ipv6 (&global_source_addr, addr6); } /** * @brief Gives the source IPv4 address in string format. * * @return Source IPv4 string. Free with g_free(). */ char * gvm_source_addr_str (void) { char *str = g_malloc0 (INET_ADDRSTRLEN); inet_ntop (AF_INET, &global_source_addr.s_addr, str, INET_ADDRSTRLEN); return str; } /** * @brief Gives the source IPv6 address in string format. * * @return Source IPv6 string. Free with g_free(). */ char * gvm_source_addr6_str (void) { char *str = g_malloc0 (INET6_ADDRSTRLEN); inet_ntop (AF_INET6, &global_source_addr6, str, INET6_ADDRSTRLEN); return str; } /* Miscellaneous functions. */ /** * @brief Maps an IPv4 address as an IPv6 address. * eg. 192.168.10.20 would map to \::ffff:192.168.10.20. * * @param[in] ip4 IPv4 address to map. * @param[out] ip6 Buffer to store the IPv6 address. */ void ipv4_as_ipv6 (const struct in_addr *ip4, struct in6_addr *ip6) { if (ip4 == NULL || ip6 == NULL) return; ip6->s6_addr32[0] = 0; ip6->s6_addr32[1] = 0; ip6->s6_addr32[2] = htonl (0xffff); memcpy (&ip6->s6_addr32[3], ip4, sizeof (struct in_addr)); } /** * @brief Stringifies an IP address. * * @param[in] addr6 IP address. * @param[out] str Buffer to output IP. */ void addr6_to_str (const struct in6_addr *addr6, char *str) { if (!addr6) return; if (IN6_IS_ADDR_V4MAPPED (addr6)) inet_ntop (AF_INET, &addr6->s6_addr32[3], str, INET6_ADDRSTRLEN); else inet_ntop (AF_INET6, addr6, str, INET6_ADDRSTRLEN); } /** * @brief Stringifies an IP address. * * @param[in] addr6 IP address. * * @return IP as string. NULL otherwise. */ char * addr6_as_str (const struct in6_addr *addr6) { char *str; if (!addr6) return NULL; str = g_malloc0 (INET6_ADDRSTRLEN); addr6_to_str (addr6, str); return str; } /** * @brief Convert an IP address to string format. * * @param[in] addr Address to convert. * @param[out] str Buffer of INET6_ADDRSTRLEN size. */ void sockaddr_as_str (const struct sockaddr_storage *addr, char *str) { if (!addr || !str) return; if (addr->ss_family == AF_INET) { struct sockaddr_in *saddr = (struct sockaddr_in *) addr; inet_ntop (AF_INET, &saddr->sin_addr, str, INET6_ADDRSTRLEN); } else if (addr->ss_family == AF_INET6) { struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *) addr; if (IN6_IS_ADDR_V4MAPPED (&s6addr->sin6_addr)) inet_ntop (AF_INET, &s6addr->sin6_addr.s6_addr[12], str, INET6_ADDRSTRLEN); else inet_ntop (AF_INET6, &s6addr->sin6_addr, str, INET6_ADDRSTRLEN); } else if (addr->ss_family == AF_UNIX) { g_snprintf (str, INET6_ADDRSTRLEN, "unix_socket"); } else if (addr->ss_family == AF_UNSPEC) { g_snprintf (str, INET6_ADDRSTRLEN, "unknown_socket"); } else { g_snprintf (str, INET6_ADDRSTRLEN, "type_%d_socket", addr->ss_family); } } /** * @brief Returns a list of addresses that a hostname resolves to. * * @param[in] name Hostname to resolve. * * @return List of addresses, NULL otherwise. */ GSList * gvm_resolve_list (const char *name) { struct addrinfo hints, *info, *p; GSList *list = NULL; if (name == NULL) return NULL; bzero (&hints, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((getaddrinfo (name, NULL, &hints, &info)) != 0) return NULL; p = info; while (p) { struct in6_addr dst; if (p->ai_family == AF_INET) { struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr; ipv4_as_ipv6 (&(addrin->sin_addr), &dst); list = g_slist_prepend (list, memdup (&dst, sizeof (dst))); } else if (p->ai_family == AF_INET6) { struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr; memcpy (&dst, &(addrin->sin6_addr), sizeof (struct in6_addr)); list = g_slist_prepend (list, memdup (&dst, sizeof (dst))); } p = p->ai_next; } freeaddrinfo (info); return list; } /** * @brief Resolves a hostname to an IPv4 or IPv6 address. * * @param[in] name Hostname to resolve. * @param[out] dst Buffer to store resolved address. Size must be at least * 4 bytes for AF_INET and 16 bytes for AF_INET6. * @param[in] family Either AF_INET or AF_INET6. * * @return -1 if error, 0 otherwise. */ int gvm_resolve (const char *name, void *dst, int family) { struct addrinfo hints, *info, *p; if (name == NULL || dst == NULL || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)) return -1; bzero (&hints, sizeof (hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((getaddrinfo (name, NULL, &hints, &info)) != 0) return -1; p = info; while (p) { if (p->ai_family == family || family == AF_UNSPEC) { if (p->ai_family == AF_INET && family == AF_UNSPEC) { struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr; ipv4_as_ipv6 (&(addrin->sin_addr), dst); } else if (p->ai_family == AF_INET) { struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr; memcpy (dst, &(addrin->sin_addr), sizeof (struct in_addr)); } else if (p->ai_family == AF_INET6) { struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr; memcpy (dst, &(addrin->sin6_addr), sizeof (struct in6_addr)); } break; } p = p->ai_next; } freeaddrinfo (info); return 0; } /** * @brief Resolves a hostname to an IPv4-mapped IPv6 or IPv6 address. * * @param[in] name Hostname to resolve. * @param[out] ip6 Buffer to store resolved address. * * @return -1 if error, 0 otherwise. */ int gvm_resolve_as_addr6 (const char *name, struct in6_addr *ip6) { return gvm_resolve (name, ip6, AF_UNSPEC); } /* Ports related. */ /** * @brief Validate a port range string. * * Accepts ranges in form of "103,U:200-1024,3000-4000,T:3-4,U:7". * * @param[in] port_range A port range. * * @return 0 success, 1 failed. */ int validate_port_range (const char *port_range) { gchar **split, **point, *range, *range_start; if (!port_range) return 1; while (*port_range && isblank (*port_range)) port_range++; if (*port_range == '\0') return 1; /* Treat newlines like commas. */ range = range_start = g_strdup (port_range); while (*range) { if (*range == '\n') *range = ','; range++; } split = g_strsplit (range_start, ",", 0); g_free (range_start); point = split; while (*point) { gchar *hyphen, *element; /* Strip off any outer whitespace. */ element = g_strstrip (*point); /* Strip off any leading type specifier and following whitespace. */ if ((strlen (element) >= 2) && ((element[0] == 'T') || (element[0] == 'U'))) { element++; while (*element && isblank (*element)) element++; if (*element == ':') element++; } /* Look for a hyphen. */ hyphen = strchr (element, '-'); if (hyphen) { long int number1, number2; const char *first; char *end; hyphen++; /* Check the first number. */ first = element; while (*first && isblank (*first)) first++; if (*first == '-') goto fail; errno = 0; number1 = strtol (first, &end, 10); while (*end && isblank (*end)) end++; if (errno || (*end != '-')) goto fail; if (number1 == 0) goto fail; if (number1 > 65535) goto fail; /* Check the second number. */ while (*hyphen && isblank (*hyphen)) hyphen++; if (*hyphen == '\0') goto fail; errno = 0; number2 = strtol (hyphen, &end, 10); while (*end && isblank (*end)) end++; if (errno || *end) goto fail; if (number2 == 0) goto fail; if (number2 > 65535) goto fail; if (number1 > number2) goto fail; } else { long int number; const char *only; char *end; /* Check the single number. */ only = element; while (*only && isblank (*only)) only++; /* Empty ranges are OK. */ if (*only) { errno = 0; number = strtol (only, &end, 10); while (*end && isblank (*end)) end++; if (errno || *end) goto fail; if (number == 0) goto fail; if (number > 65535) goto fail; } } point += 1; } g_strfreev (split); return 0; fail: g_strfreev (split); return 1; } /** * @brief Create a range array from a port_range string. * * @param[in] port_range Valid port_range string. * * @return Range array or NULL if port_range invalid or NULL. */ array_t * port_range_ranges (const char *port_range) { gchar **split, **point, *range_start, *current; array_t *ranges; int tcp, err; if (!port_range) return NULL; /* port_range needs to be a valid port_range string. */ err = validate_port_range (port_range); if (err) return NULL; ranges = make_array (); while (*port_range && isblank (*port_range)) port_range++; /* Accepts T: and U: before any of the ranges. This toggles the remaining * ranges, as in nmap. Treats a leading naked range as TCP, whereas nmap * treats it as TCP and UDP. */ /* Treat newlines like commas. */ range_start = current = g_strdup (port_range); while (*current) { if (*current == '\n') *current = ','; current++; } tcp = 1; split = g_strsplit (range_start, ",", 0); g_free (range_start); point = split; while (*point) { gchar *hyphen, *element; range_t *range; int element_strlen; element = g_strstrip (*point); element_strlen = strlen (element); if (element_strlen >= 2) { if (element[0] == 'T') { element++; while (*element && isblank (*element)) element++; if (*element == ':') { element++; tcp = 1; } } else if (element[0] == 'U') { element++; while (*element && isblank (*element)) element++; if (*element == ':') { element++; tcp = 0; } } /* Else tcp stays as it is. */ } /* Skip any space that followed the type specifier. */ while (*element && isblank (*element)) element++; hyphen = strchr (element, '-'); if (hyphen) { *hyphen = '\0'; hyphen++; while (*hyphen && isblank (*hyphen)) hyphen++; assert (*hyphen); /* Validation checks this. */ /* A range. */ range = (range_t *) g_malloc0 (sizeof (range_t)); range->start = atoi (element); range->end = atoi (hyphen); range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP; range->exclude = 0; array_add (ranges, range); } else if (*element) { /* A single port. */ range = (range_t *) g_malloc0 (sizeof (range_t)); range->start = atoi (element); range->end = range->start; range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP; range->exclude = 0; array_add (ranges, range); } /* Else skip over empty range. */ point += 1; } g_strfreev (split); return ranges; } /** * @brief Checks if a port num is in port ranges array. * * @param[in] pnum Port number. * @param[in] ptype Port type. * @param[in] pranges Array of port ranges. * * @return 1 if port in port ranges, 0 otherwise. */ int port_in_port_ranges (int pnum, port_protocol_t ptype, array_t *pranges) { unsigned int i; if (pranges == NULL || pnum < 0 || pnum > 65536) return 0; for (i = 0; i < pranges->len; i++) { range_t *range = (range_t *) g_ptr_array_index (pranges, i); if (range->type != ptype) continue; if (range->start <= pnum && pnum <= range->end) return 1; } return 0; } /** * @brief Checks if IPv6 support is enabled. * * @return 1 if IPv6 is enabled, 0 if disabled. */ int ipv6_is_enabled (void) { int sock = socket (PF_INET6, SOCK_STREAM, 0); if (sock < 0) { if (errno == EAFNOSUPPORT) return 0; } else close (sock); return 1; } /* Functions used by alive detection module (Boreas). */ /** * @brief Determine if IP is localhost. * * @return True if IP is localhost, else false. */ static gboolean ip_islocalhost (struct sockaddr_storage *storage) { struct in_addr addr; struct in_addr *addr_p; struct in6_addr addr6 = IN6ADDR_ANY_INIT; struct in6_addr *addr6_p; struct sockaddr_in *sin_p; struct sockaddr_in6 *sin6_p; struct ifaddrs *ifaddr, *ifa; int family; family = storage->ss_family; addr6_p = &addr6; addr_p = &addr; addr.s_addr = 0; if (family == AF_INET) { sin_p = (struct sockaddr_in *) storage; addr = sin_p->sin_addr; if (addr_p == NULL) return FALSE; /* addr is 0.0.0.0 */ if ((addr_p)->s_addr == 0) return TRUE; /* addr starts with 127.0.0.1 */ if (((addr_p)->s_addr & htonl (0xFF000000)) == htonl (0x7F000000)) return TRUE; } if (family == AF_INET6) { sin6_p = (struct sockaddr_in6 *) storage; addr6 = sin6_p->sin6_addr; if (IN6_IS_ADDR_V4MAPPED (&addr6)) { /* addr is 0.0.0.0 */ if (addr6_p->s6_addr32[3] == 0) return 1; /* addr starts with 127.0.0.1 */ if ((addr6_p->s6_addr32[3] & htonl (0xFF000000)) == htonl (0x7F000000)) return 1; } if (IN6_IS_ADDR_LOOPBACK (addr6_p)) return 1; } if (getifaddrs (&ifaddr) == -1) { g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno)); return FALSE; } else { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family == AF_INET) { sin = (struct sockaddr_in *) (ifa->ifa_addr); /* Check if same address as local interface. */ if (addr_p->s_addr == sin->sin_addr.s_addr) return TRUE; } if (ifa->ifa_addr->sa_family == AF_INET6) { sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr); /* Check if same address as local interface. */ if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL (&(sin6->sin6_addr), addr6_p)) return TRUE; } } freeifaddrs (ifaddr); } return FALSE; } typedef struct route_entry route_entry_t; /** Entry of routing table /proc/net/route */ struct route_entry { gchar *interface; unsigned long mask; unsigned long dest; }; /** * @brief Get the entries of /proc/net/route as list of route_entry structs. * * @return GSList of route_entry structs. NULL if no routes found or Error. */ static GSList * get_routes (void) { GSList *routes; GError *err; GIOChannel *file_channel; gchar *line; gchar **items_in_line; int status; route_entry_t *entry; err = NULL; routes = NULL; line = NULL; /* Open "/proc/net/route". */ file_channel = g_io_channel_new_file ("/proc/net/route", "r", &err); if (file_channel == NULL) { g_warning ("%s: %s. ", __func__, err ? err->message : "Error opening /proc/net/ipv6_route"); err = NULL; return NULL; } /* Skip first first line of file. */ status = g_io_channel_read_line (file_channel, &line, NULL, NULL, &err); if (status != G_IO_STATUS_NORMAL || !line || err) { g_warning ("%s: %s", __func__, err ? err->message : "g_io_channel_read_line() status != G_IO_STATUS_NORMAL"); err = NULL; } g_free (line); /* Until EOF or err we go through lines of file and extract Iface, Mask and * Destination and put it into the to be returned list of routes.*/ while (1) { gchar *interface, *char_p; unsigned long mask, dest; int count; /* Get new line. */ line = NULL; status = g_io_channel_read_line (file_channel, &line, NULL, NULL, &err); if ((status != G_IO_STATUS_NORMAL) || !line || err) { if (status == G_IO_STATUS_AGAIN) g_warning ("%s: /proc/net/route unavailable.", __func__); if (err || status == G_IO_STATUS_ERROR) g_warning ( "%s: %s", __func__, err ? err->message : "g_io_channel_read_line() status == G_IO_STATUS_ERROR"); err = NULL; g_free (line); break; } /* Get items in line. */ items_in_line = g_strsplit (line, "\t", -1); /* Check for missing entries in line of "/proc/net/route". */ for (count = 0; items_in_line[count]; count++) ; if (11 != count) { g_strfreev (items_in_line); g_free (line); continue; } interface = g_strndup (items_in_line[0], 64); /* Cut interface str after ":" if IP aliasing is used. */ char_p = strchr (interface, ':'); if (char_p) { *char_p = '\0'; } dest = strtoul (items_in_line[1], NULL, 16); mask = strtoul (items_in_line[7], NULL, 16); /* Fill GSList entry. */ entry = g_malloc0 (sizeof (route_entry_t)); entry->interface = interface; entry->dest = dest; entry->mask = mask; routes = g_slist_append (routes, entry); g_strfreev (items_in_line); g_free (line); } status = g_io_channel_shutdown (file_channel, TRUE, &err); if ((G_IO_STATUS_NORMAL != status) || err) g_warning ("%s: %s", __func__, err ? err->message : "g_io_channel_shutdown() was not successful"); return routes; } /** * @brief Get Interface which should be used for routing to destination addr. * * This function should be used sparingly as it parses /proc/net/route for * every call. * * @param[in] storage_dest Destination address. * @param[out] storage_source Source address. Is set to either address of the * interface we use or global source address if set. Only gets filled if * storage_source != NULL. * * @return Interface name of interface used for routing to destination address. * NULL if no interface found or Error. */ gchar * gvm_routethrough (struct sockaddr_storage *storage_dest, struct sockaddr_storage *storage_source) { struct ifaddrs *ifaddr, *ifa; gchar *interface_out; interface_out = NULL; if (!storage_dest) return NULL; if (getifaddrs (&ifaddr) == -1) { g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno)); return NULL; } /* IPv4. */ if (storage_dest->ss_family == AF_INET) { GSList *routes; GSList *routes_p; routes = get_routes (); /* Set storage_source to localhost if storage_source was supplied and * return name of loopback interface. */ if (ip_islocalhost (storage_dest)) { // TODO: check for (storage_source->ss_family == AF_INET) if (storage_source) { struct sockaddr_in *sin_p = (struct sockaddr_in *) storage_source; sin_p->sin_addr.s_addr = htonl (0x7F000001); } for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET) && (ifa->ifa_flags & (IFF_LOOPBACK))) { interface_out = g_strdup (ifa->ifa_name); break; } } } else { struct sockaddr_in *sin_dest_p, *sin_src_p; struct in_addr global_src; unsigned long best_match; /* Check if global_source_addr in use. */ gvm_source_addr (&global_src); sin_dest_p = (struct sockaddr_in *) storage_dest; sin_src_p = (struct sockaddr_in *) storage_source; /* Check routes for matching address. Get interface name and set * storage_source*/ for (best_match = 0, routes_p = routes; routes_p; routes_p = routes_p->next) { if (((sin_dest_p->sin_addr.s_addr & ((route_entry_t *) (routes_p->data))->mask) == ((route_entry_t *) (routes_p->data))->dest) && (((route_entry_t *) (routes_p->data))->mask >= best_match)) { /* Interface of matching route.*/ g_free (interface_out); interface_out = g_strdup (((route_entry_t *) (routes_p->data))->interface); best_match = ((route_entry_t *) (routes_p->data))->mask; if (!storage_source) continue; /* Set storage_source to global source if global source * present.*/ if (global_src.s_addr != INADDR_ANY) sin_src_p->sin_addr.s_addr = global_src.s_addr; /* Set storage_source to addr of matching interface if no * global source present.*/ else { for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET) && (g_strcmp0 (interface_out, ifa->ifa_name) == 0)) { sin_src_p->sin_addr.s_addr = ((struct sockaddr_in *) (ifa->ifa_addr)) ->sin_addr.s_addr; break; } } } } } } /* Free GSList. */ if (routes) { for (routes_p = routes; routes_p; routes_p = routes_p->next) { if (((route_entry_t *) (routes_p->data))->interface) g_free (((route_entry_t *) (routes_p->data))->interface); } g_slist_free (routes); } } else if (storage_dest->ss_family == AF_INET6) { g_warning ("%s: IPv6 not yet implemented for this function. Will be " "implemented soon. Thanks for your patience.", __func__); } return interface_out != NULL ? interface_out : NULL; } /** * @brief Get a connected UDP socket. * * @param target_addr Holds addr for connect call * * @return Socket number or -1 on error. */ static int get_connected_udp_sock (struct sockaddr_storage *target_addr) { int family = target_addr->ss_family; int sockfd = -1; if (family == AF_INET) { sockfd = socket (AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { g_warning ("Socket error: %s", strerror (errno)); return -1; } ((struct sockaddr_in *) target_addr)->sin_port = htons (9877); if (connect (sockfd, (struct sockaddr *) target_addr, sizeof (struct sockaddr_in)) < 0) { g_warning ("Connect error: %s", strerror (errno)); close (sockfd); return -1; } } else if (family == AF_INET6) { sockfd = socket (AF_INET6, SOCK_DGRAM, 0); if (sockfd < 0) { g_warning ("Socket error: %s", strerror (errno)); return -1; } ((struct sockaddr_in6 *) target_addr)->sin6_port = htons (9877); if (connect (sockfd, (struct sockaddr *) target_addr, sizeof (struct sockaddr_in6)) < 0) { g_warning ("Connect error: %s", strerror (errno)); close (sockfd); return -1; } } return sockfd; } /** * @brief Get address from socket. * * @param[in] sockfd Socket from which to get the address. * @param[out] sock_addr Location to write address into. * * @return 0 on success, -1 on error. */ static int get_sock_addr (int sockfd, struct sockaddr_storage *sock_addr) { socklen_t len; int family = sock_addr->ss_family; if (family == AF_INET) { len = sizeof (struct sockaddr_in); if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0) { g_warning ("getsockname error: %s", strerror (errno)); close (sockfd); return -1; } } else if (family == AF_INET6) { len = sizeof (struct sockaddr_in6); if (getsockname (sockfd, (struct sockaddr *) sock_addr, &len) < 0) { g_warning ("getsockname error:%s", strerror (errno)); close (sockfd); return -1; } } return 0; } /** * @brief Get iface name of iface matching the given interface address. * * @param[in] target_addr Address of interface. * * @return Interface name of matching interface which to be freed by the caller. * Null if no interface found or error. */ static char * get_ifname_from_ifaddr (struct sockaddr_storage *target_addr) { struct ifaddrs *ifaddr, *ifa; int family = target_addr->ss_family; char *interface_out = NULL; if (getifaddrs (&ifaddr) == -1) { g_warning ("%s: getifaddr failed: %s", __func__, strerror (errno)); return NULL; } if (family == AF_INET) { struct sockaddr_in *sin; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (!(ifa->ifa_flags & IFF_UP)) continue; if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family == AF_INET) { sin = (struct sockaddr_in *) (ifa->ifa_addr); if (((struct sockaddr_in *) target_addr)->sin_addr.s_addr == sin->sin_addr.s_addr) interface_out = g_strdup (ifa->ifa_name); } } } else if (family == AF_INET6) { struct sockaddr_in6 *sin6; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (!(ifa->ifa_flags & IFF_UP)) continue; if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family == AF_INET6) { sin6 = (struct sockaddr_in6 *) (ifa->ifa_addr); if (IN6_ARE_ADDR_EQUAL ( &(sin6->sin6_addr), &((struct sockaddr_in6 *) target_addr)->sin6_addr)) interface_out = g_strdup (ifa->ifa_name); } } } freeifaddrs (ifaddr); return interface_out; } /** * @brief Get the outgoing interface name for a given destination addr. * * A UDP socket is connected and its address retrieved. The address is the * address of the interface of the outgoing interface. Its is determined by * the kernel. We then search the list of interfaces for this address to * determine the interface name. This method has the downside that if two * interfaces with same addr are UP, a wrong interface might be returned because * we can only retrieve the interface addr which was chosen by the kernel and * nothing else (like e.g. interface number). * * @param[in] target_addr Destination address. * * @return Name of outgoing interface which has to be freed by caller. NULL if * no interface found or Error. */ char * gvm_get_outgoing_iface (struct sockaddr_storage *target_addr) { int family, sockfd; struct sockaddr_storage out_iface_addr; char *out_iface_str; out_iface_str = NULL; family = target_addr->ss_family; if (!target_addr) return NULL; // get a connected udp socket sockfd = get_connected_udp_sock (target_addr); if (sockfd < 0) return NULL; // get socked address which is the addr of the interface we want to get out_iface_addr.ss_family = family; if (get_sock_addr (sockfd, &out_iface_addr) < 0) return NULL; // get interface name form interface address out_iface_str = get_ifname_from_ifaddr (&out_iface_addr); return out_iface_str; } gvm-libs-22.20.0/base/networking.h000066400000000000000000000037021477470532200166640ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief GVM Networking related API. */ #ifndef _GVM_NETWORKING_H #define _GVM_NETWORKING_H #include "array.h" /* for array_t */ #include /* for struct in6_addr */ /** * @brief Possible port types. * * Used in Manager database. If any symbol changes then a migrator must be * added to update existing data. */ typedef enum { PORT_PROTOCOL_TCP = 0, PORT_PROTOCOL_UDP = 1, PORT_PROTOCOL_OTHER = 2 } port_protocol_t; /** * @brief A port range. */ struct range { gchar *comment; /**< Comment. */ gchar *id; /**< UUID. */ int end; /**< End port. For single port end == start. */ int exclude; /**< Whether to exclude range. */ int start; /**< Start port. */ port_protocol_t type; /**< Port protocol. */ }; typedef struct range range_t; int gvm_source_iface_init (const char *); int gvm_source_iface_is_set (void); int gvm_source_set_socket (int, int, int); void gvm_source_addr (void *); void gvm_source_addr6 (void *); void gvm_source_addr_as_addr6 (struct in6_addr *); char * gvm_source_addr_str (void); char * gvm_source_addr6_str (void); void ipv4_as_ipv6 (const struct in_addr *, struct in6_addr *); void addr6_to_str (const struct in6_addr *, char *); char * addr6_as_str (const struct in6_addr *); void sockaddr_as_str (const struct sockaddr_storage *, char *); int gvm_resolve (const char *, void *, int); GSList * gvm_resolve_list (const char *); int gvm_resolve_as_addr6 (const char *, struct in6_addr *); int validate_port_range (const char *); array_t * port_range_ranges (const char *); int port_in_port_ranges (int, port_protocol_t, array_t *); int ipv6_is_enabled (void); gchar * gvm_routethrough (struct sockaddr_storage *, struct sockaddr_storage *); char * gvm_get_outgoing_iface (struct sockaddr_storage *); #endif /* not _GVM_NETWORKING_H */ gvm-libs-22.20.0/base/networking_tests.c000066400000000000000000002204471477470532200201100ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "networking.c" #include #include Describe (networking); BeforeEach (networking) { cgreen_mocks_are (loose_mocks); } AfterEach (networking) { } Ensure (networking, validate_port_range) { gchar *ports_all_privileged_tcp; gchar *ports_all_privileged_tcp_and_udp; gchar *ports_all_tcp; gchar *ports_openvas_default; gchar *ports_all_iana_assigned_tcp_and_udp_2020_02_12; gchar *ports_all_tcp_and_nmap_5_51_top_100_udp; gchar *ports_all_tcp_and_nmap_5_51_top_1000_udp; gchar *ports_nmap_5_51_top_2000_tcp_and_top_100_udp; gchar *ports_all_iana_assigned_tcp_2020_02_12; gchar *ports_web_services; gchar *(*ports) (const gchar *, ...) G_GNUC_NULL_TERMINATED; ports = g_strconcat; /* No port range provided. */ assert_that (validate_port_range (NULL), is_equal_to (1)); assert_that (validate_port_range (""), is_equal_to (1)); /* '\0' on end. */ assert_that (validate_port_range ("\0"), is_equal_to (1)); assert_that (validate_port_range ("T:1-5,7,9,U:1-3,5,7,9,\\0"), is_equal_to (1)); /* Newline in between range description.*/ assert_that (validate_port_range ("\nT:1-\n5,7,9,\nU:1-3,5\n,7,9\n"), is_equal_to (1)); /* Port <= 0 or Port > 65535. */ assert_that (validate_port_range ("0"), is_equal_to (1)); assert_that (validate_port_range ("-9"), is_equal_to (1)); assert_that (validate_port_range ("1,0,6,7"), is_equal_to (1)); assert_that (validate_port_range ("2,-9,4"), is_equal_to (1)); assert_that (validate_port_range ("90000"), is_equal_to (1)); /* Illegal Ranges. */ assert_that (validate_port_range ("T:-"), is_equal_to (1)); assert_that (validate_port_range ("T:-9"), is_equal_to (1)); assert_that (validate_port_range ("T:0-"), is_equal_to (1)); assert_that (validate_port_range ("T:0-9"), is_equal_to (1)); assert_that (validate_port_range ("T:90000-"), is_equal_to (1)); assert_that (validate_port_range ("T:90000-90010"), is_equal_to (1)); assert_that (validate_port_range ("T:9-\\0"), is_equal_to (1)); assert_that (validate_port_range ("T:9-0"), is_equal_to (1)); assert_that (validate_port_range ("T:9-90000"), is_equal_to (1)); assert_that (validate_port_range ("T:100-9"), is_equal_to (1)); assert_that (validate_port_range ("0-"), is_equal_to (1)); assert_that (validate_port_range ("0-9"), is_equal_to (1)); assert_that (validate_port_range ("9-"), is_equal_to (1)); assert_that (validate_port_range ("9-\\0"), is_equal_to (1)); assert_that (validate_port_range ("9-8"), is_equal_to (1)); assert_that (validate_port_range ("90000-90010"), is_equal_to (1)); assert_that (validate_port_range ("100-9"), is_equal_to (1)); assert_that (validate_port_range ("T,U"), is_equal_to (1)); assert_that (validate_port_range ("T :\n: 1-2,U"), is_equal_to (1)); assert_that (validate_port_range ("T :: 1-2,U"), is_equal_to (1)); assert_that (validate_port_range ("T:2=2"), is_equal_to (1)); assert_that (validate_port_range ("T:1.2-5,4.5"), is_equal_to (1)); /* Legal single ports.*/ assert_that (validate_port_range ("6,6,6,6,10,20"), is_equal_to (0)); assert_that (validate_port_range ("T:7, U:7"), is_equal_to (0)); assert_that (validate_port_range ("T:7, U:9"), is_equal_to (0)); assert_that (validate_port_range ("9"), is_equal_to (0)); assert_that (validate_port_range ("U:,T:"), is_equal_to (0)); /* is ignored */ assert_that (validate_port_range ("1,2,,,,,,,\n\n\n\n\n\n,,,5"), is_equal_to (0)); /* Example in Documentation. */ assert_that (validate_port_range ("T:1-5,7,9,U:1-3,5,7,9"), is_equal_to (0)); /* Treat newlines like commas. */ assert_that (validate_port_range ("1,2,\n,\n4,6"), is_equal_to (0)); assert_that (validate_port_range ("T:1-5,7,9,\nU:1-3,5\n,7,9"), is_equal_to (0)); /* Ranges without type specifier. */ assert_that (validate_port_range ("6-9,7,7,10-20,20"), is_equal_to (0)); /* Allow whitespace after T/U and anywhere else. */ assert_that ( validate_port_range (" T: 1 -5, 7 ,9, \nU :1- 3,5 \n,7,9"), is_equal_to (0)); assert_that (validate_port_range ( " T: 1 -5, 7 ,9, \nU :1- 3,5 \n,7,9, T : 5 -7"), is_equal_to (0)); assert_that (validate_port_range (" T : 1"), is_equal_to (0)); /* Some standard port lists.*/ ports_all_iana_assigned_tcp_2020_02_12 = ports ( "T:1-50,52-80,82-99,101-113,115-224,242-248,256-257,259-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-1001,1010,1021-1027,1029," "1033-", "1108,1110-1490,1492-1782,1784-2193,2197-2258,2260-2368,2370-2377,2379-", "2681,2683-2793,2795-2824,2826-2872,2874-2924,2926-3091,3093-3125,3127-", "3300,3302-3321,3326-3366,3372-3402,3405-3545,3547-3693,3695-3993,3995-", "4047,4049-4143,4145-4193,4197,4199,4300-4314,4316,4320-4323,4325-4336,", "4340-4362,4366,4368-4379,4389-4396,4400-4423,4425-4433,4441-4458,4484-", "4488,4500,4534-4538,4545-4559,4563,4566-4570,4573,4590-4605,4621,4646,", "4658-4692,4700-4704,4711,4725-4733,4737-4747,4749-4756,4774,4784-4791,", "4800-4804,4827,4837-4851,4867-4871,4876-4885,4888-4889,4894,4899-4902,", "4912-4915,4936-4937,4940-4942,4949-4953,4969-4971,4980,4984-4991,4999-", "5015,5020-5034,5042-5075,5078-5087,5092-5094,5099-5107,5111-5112,5114-", "5117,5120,5133-5137,5145-5146,5150-5157,5161-5168,5172,5190-5197,5200-", "5203,5209,5215,5221-5237,5245-5254,5264-5265,5269-5272,5280-5282,5298-", "5310,5312-5318,5320-5321,5343-5344,5349-5364,5397-5437,5443,5445,5450,", "5453-5456,5461-5465,5470-5475,5500-5507,5550,5553-5557,5565-5569,5573-", "5575,5579-5586,5597-5605,5618,5627-5639,5646,5666,5670-5684,5687-5689,", "5693,5696,5700,5705,5713-5730,5741-5748,5750,5755,5757,5766-5771,5777,", "5780-5787,5793-5794,5813-5814,5841-5842,5859,5863,5868,5883,5900,5910-", "5913,5963,5968-5969,5984-5993,5999,6064-6066,6068-6077,6080-6088,6099-", "6118,6121-6124,6130,6133,6140-6149,6159-6163,6200-6201,6209,6222,6241-", "6244,6251-6253,6267-6269,6300-6301,6306,6315-6317,6320-6322,6324-6326,", "6343-6344,6346-6347,6350,6355,6360,6363,6370,6379,6382,6389-6390,6417-", "6421,6432,6442-6446,6455-6456,6464,6471,6480-6489,6500-6503,6505-6511,", "6513-6515,6543-6544,6547-6551,6558,6566,6568,6579-6583,6600-6602,6619-", "6629,6632-6636,6640,6653,6655-6657,6670-6673,6678-6679,6687-6690,6696-", "6697,6701-6706,6714-6716,6767-6771,6777-6778,6784-6791,6801,6817,6831,", "6841-6842,6850,6868,6888,6900-6901,6924,6935-6936,6946,6951,6961-6966,", "6969-6970,6997-7026,7030-7031,7040,7070-7073,7080,7088,7095,7099-7101,", "7107,7117,7121,7128-7129,7161-7174,7181,7200-7202,7215-7216,7227-7229,", "7235-7237,7244,7262,7272-7283,7365,7391-7395,7397,7400-7402,7410-7411,", "7420-7421,7426-7431,7437,7443,7471,7473-7474,7478,7491,7500-7501,7508-", "7511,7542-7551,7560,7563,7566,7569-7570,7574,7588,7606,7624,7626-7631,", "7633,7648,7663,7672-7677,7680,7683,7687,7689,7697,7700-7701,7707-7708,", "7720,7724-7728,7734,7738,7741-7744,7747,7775,7777-7779,7781,7784,7786-", "7787,7789,7794,7797-7802,7810,7845-7847,7869-7872,7878,7880,7887,7900-", "7903,7913,7932-7933,7962,7967,7979-7982,7997-8009,8015-8016,8019-8023,", "8025-8026,8032-8034,8040-8044,8051-8060,8066-8067,8070,8074,8077,8080-", "8084,8086-8088,8090-8091,8097,8100-8102,8111,8115-8118,8121-8122,8128-", "8132,8140,8148-8149,8153,8160-8162,8181-8184,8190-8192,8194-8195,8199-", "8202,8204-8208,8211,8230-8232,8243,8266,8270,8276,8280,8282,8292-8294,", "8300-8301,8313,8320-8322,8351,8376-8380,8383-8384,8400-8405,8415-8417,", "8423,8442-8445,8450,8457,8470-8474,8500-8503,8554-8555,8567,8600,8609-", "8615,8665-8666,8675,8686,8688,8699,8710-8711,8732-8733,8750,8763-8770,", "8778,8786-8787,8793,8800,8804-8805,8807-8809,8873,8880-8881,8883,8888-", "8894,8899-8901,8910-8913,8937,8953-8954,8980-8981,8989-8991,8997-9002,", "9005,9007-9011,9020-9026,9050-9051,9060,9080-9081,9083-9093,9100-9107,", "9111,9119,9122-9123,9131,9160-9164,9191,9200-9217,9222,9255,9277-9287,", "9292-9295,9300,9306,9312,9318,9321,9339,9343-9346,9374,9380,9387-9390,", "9396-9397,9400-9402,9418,9443-9445,9450,9500,9522,9535-9536,9555,9592-", "9600,9612,9614,9616-9618,9628-9632,9640,9666-9668,9694-9695,9700,9747,", "9750,9753,9762,9800-9802,9875-9878,9888-9889,9898-9900,9903,9909,9911,", "9925,9950-9956,9966,9978-9979,9981,9987-9988,9990-10010,10020,10023," "10050-", "10051,10055,10080-10081,10100-10104,10107,10110-10111,10113-10117,10125,", "10128-10129,10160-10162,10200-10201,10252-10253,10260-10261,10288,10321,", "10439,10443,10500,10540-10544,10548,10631,10800,10805,10809-10810,10860,", "10880,10933,10990,11000-11001,11095,11103-11106,11108-11112,11161-11165,", "11171-11175,11201-11202,11208,11211,11319-11321,11367,11371,11430,11489,", "11600,11623,11720,11723,11751,11796,11876-11877,11967,11971,12000-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-14002,14033-14034,14141-", "14143,14145,14149-14150,14154,14250,14414,14500,14936-14937,15000,15002,", "15118,15345,15363,15555,15660,15740,15998-16003,16020-16021,16161-16162,", "16309-16311,16360-16361,16367-16368,16384-16385,16619,16665-16666,16789,", "16900,16950,16991-16995,17007,17184-17185,17219-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,19788,19998-20003,", "20005,20012-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,23272,23294,23333,", "23400-23402,23456-23457,23546,24000-24006,24242,24249,24321-24323,24386,", "24465,24554,24577,24666,24676-24678,24680,24754,24850,24922,25000-25009,", "25576,25604,25793,25900-25903,25954-25955,26000,26133,26208,26257,26260-", "26263,26486-26487,26489,27010,27017,27345,27442,27504,27782,27876,27999-", "28001,28010,28119,28200,28240,28589,29118,29167-29168,29999-30004,30100,", "30260,30400,30832,30999,31016,31020,31029,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-33435,33656,34249,", "34378-34379,34567,34962-34964,34980,35000-35006,35100,35354-35357,36001,", "36411-36412,36422,36462,36524,36602,36700,36865,37475,37483,37601,37654,", "38000-38002,38201-38203,38412,38422,38462,38472,38800,38865,39681,40000,", "40023,40404,40841-40843,40853,41111,41121,41230,41794-41797,42508-42510,", "43000,43188-43191,43210,43438-43441,44123,44321-44323,44444-44445,44544,", "44553,44600,44818,44900,45000-45002,45045,45054,45514,45678,45824-45825,", "45966,46336,46998-47001,47100,47557,47624,47806,47808-47809,48000-48005,", "48048-48050,48128-48129,48556,48619,48653,49000-49001,49150,6000-6063,", "6665-6669", NULL); ports_all_privileged_tcp = ports ("T:1-1023", NULL); ports_all_privileged_tcp_and_udp = ports ("T:1-1023, U:1-1023", NULL); ports_all_tcp = ports ("T:1-65535", NULL); ports_openvas_default = ports ( "T:1-5,7-7,9-9,11-11,13-13,15-15,17-25,27-27,29-29,31-31,33-33,35-35,37-" "39,", "41-59,61-224,242-248,256-268,280-287,308-322,333-333,344-700,702-702,704-", "707,709-711,721-721,723-723,729-731,740-742,744-744,747-754,758-765,767-", "767,769-777,780-783,786-787,799-801,808-808,810-810,828-829,847-848,860-", "860,871-871,873-873,886-888,898-898,900-904,911-913,927-927,950-950,953-", "953,975-975,989-1002,1005-1005,1008-1008,1010-1010,1023-1027,1029-1036,", "1040-1040,1042-1042,1045-1045,1047-1112,1114-1117,1119-1120,1122-1127,", "1139-1139,1154-1155,1161-1162,1168-1170,1178-1178,1180-1181,1183-1188,", "1194-1194,1199-1231,1233-1286,1288-1774,1776-2028,2030-2030,2032-2035,", "2037-2038,2040-2065,2067-2083,2086-2087,2089-2152,2155-2155,2159-2167,", "2170-2177,2180-2181,2190-2191,2199-2202,2213-2213,2220-2223,2232-2246,", "2248-2255,2260-2260,2273-2273,2279-2289,2294-2311,2313-2371,2381-2425,", "2427-2681,2683-2824,2826-2854,2856-2924,2926-3096,3098-3299,3302-3321,", "3326-3366,3372-3403,3405-3545,3547-3707,3709-3765,3767-3770,3772-3800,", "3802-3802,3845-3871,3875-3876,3885-3885,3900-3900,3928-3929,3939-3939,", "3959-3959,3970-3971,3984-3987,3999-4036,4040-4042,4045-4045,4080-4080,", "4096-4100,4111-4111,4114-4114,4132-4134,4138-4138,4141-4145,4154-4154,", "4160-4160,4199-4200,4242-4242,4300-4300,4321-4321,4333-4333,4343-4351,", "4353-4358,4369-4369,4400-4400,4442-4457,4480-4480,4500-4500,4545-4547,", "4555-4555,4557-4557,4559-4559,4567-4568,4600-4601,4658-4662,4672-4672,", "4752-4752,4800-4802,4827-4827,4837-4839,4848-4849,4868-4869,4885-4885,", "4894-4894,4899-4899,4950-4950,4983-4983,4987-4989,4998-4998,5000-5011,", "5020-5025,5031-5031,5042-5042,5050-5057,5060-5061,5064-5066,5069-5069,", "5071-5071,5081-5081,5093-5093,5099-5102,5137-5137,5145-5145,5150-5152,", "5154-5154,5165-5165,5190-5193,5200-5203,5222-5222,5225-5226,5232-5232,", "5236-5236,5250-5251,5264-5265,5269-5269,5272-5272,5282-5282,5300-5311,", "5314-5315,5351-5355,5400-5432,5435-5435,5454-5456,5461-5463,5465-5465,", "5500-5504,5510-5510,5520-5521,5530-5530,5540-5540,5550-5550,5553-5556,", "5566-5566,5569-5569,5595-5605,5631-5632,5666-5666,5673-5680,5688-5688,", "5690-5690,5713-5717,5720-5720,5729-5730,5741-5742,5745-5746,5755-5755,", "5757-5757,5766-5768,5771-5771,5800-5803,5813-5813,5858-5859,5882-5882,", "5888-5889,5900-5903,5968-5969,5977-5979,5987-5991,5997-6010,6050-6051,", "6064-6073,6085-6085,6100-6112,6123-6123,6141-6150,6175-6177,6200-6200,", "6253-6253,6255-6255,6270-6270,6300-6300,6321-6322,6343-6343,6346-6347,", "6373-6373,6382-6382,6389-6389,6400-6400,6455-6456,6471-6471,6500-6503,", "6505-6510,6543-6543,6547-6550,6558-6558,6566-6566,6580-6582,6588-6588,", "6620-6621,6623-6623,6628-6628,6631-6631,6665-6670,6672-6673,6699-6701,", "6714-6714,6767-6768,6776-6776,6788-6790,6831-6831,6841-6842,6850-6850,", "6881-6889,6891-6891,6901-6901,6939-6939,6961-6966,6969-6970,6998-7015,", "7020-7021,7030-7030,7070-7070,7099-7100,7121-7121,7161-7161,7170-7170,", "7174-7174,7200-7201,7210-7210,7269-7269,7273-7273,7280-7281,7283-7283,", "7300-7300,7320-7320,7326-7326,7391-7392,7395-7395,7426-7431,7437-7437,", "7464-7464,7491-7491,7501-7501,7510-7511,7544-7545,7560-7560,7566-7566,", "7570-7570,7575-7575,7588-7588,7597-7597,7624-7624,7626-7627,7633-7634,", "7648-7649,7666-7666,7674-7676,7743-7743,7775-7779,7781-7781,7786-7786,", "7797-7798,7800-7801,7845-7846,7875-7875,7902-7902,7913-7913,7932-7933,", "7967-7967,7979-7980,7999-8005,8007-8010,8022-8022,8032-8033,8044-8044,", "8074-8074,8080-8082,8088-8089,8098-8098,8100-8100,8115-8116,8118-8118,", "8121-8122,8130-8132,8160-8161,8181-8194,8199-8201,8204-8208,8224-8225,", "8245-8245,8311-8311,8351-8351,8376-8380,8400-8403,8416-8417,8431-8431,", "8443-8444,8450-8450,8473-8473,8554-8555,8649-8649,8733-8733,8763-8765,", "8786-8787,8804-8804,8863-8864,8875-8875,8880-8880,8888-8894,8900-8901,", "8910-8911,8954-8954,8989-8989,8999-9002,9006-9006,9009-9009,9020-9026,", "9080-9080,9090-9091,9100-9103,9110-9111,9131-9131,9152-9152,9160-9164,", "9200-9207,9210-9211,9217-9217,9281-9285,9287-9287,9292-9292,9321-9321,", "9343-9344,9346-9346,9374-9374,9390-9390,9396-9397,9400-9400,9418-9418,", "9495-9495,9500-9500,9535-9537,9593-9595,9600-9600,9612-9612,9704-9704,", "9747-9747,9753-9753,9797-9797,9800-9802,9872-9872,9875-9876,9888-9889,", "9898-9901,9909-9909,9911-9911,9950-9952,9990-10005,10007-10008,10012-", "10012,10080-10083,10101-10103,10113-10116,10128-10128,10252-10252,10260-", "10260,10288-10288,10607-10607,10666-10666,10752-10752,10990-10990,11000-", "11001,11111-11111,11201-11201,11223-11223,11319-11321,11367-11367,11371-", "11371,11600-11600,11720-11720,11751-11751,11965-11965,11967-11967,11999-", "12006,12076-12076,12109-12109,12168-12168,12172-12172,12223-12223,12321-", "12321,12345-12346,12361-12362,12468-12468,12701-12701,12753-12753,13160-", "13160,13223-13224,13701-13702,13705-13706,13708-13718,13720-13722,13724-", "13724,13782-13783,13818-13822,14001-14001,14033-14034,14141-14141,14145-", "14145,14149-14149,14194-14194,14237-14237,14936-14937,15000-15000,15126-", "15126,15345-15345,15363-15363,16360-16361,16367-16368,16384-16384,16660-", "16661,16959-16959,16969-16969,16991-16991,17007-17007,17185-17185,17219-", "17219,17300-17300,17770-17772,18000-18000,18181-18187,18190-18190,18241-", "18241,18463-18463,18769-18769,18888-18888,19191-19191,19194-19194,19283-", "19283,19315-19315,19398-19398,19410-19412,19540-19541,19638-19638,19726-", "19726,20000-20001,20005-20005,20011-20012,20034-20034,20200-20200,20202-", "20203,20222-20222,20670-20670,20999-21000,21490-21490,21544-21544,21590-", "21590,21800-21800,21845-21849,22000-22001,22222-22222,22273-22273,22289-", "22289,22305-22305,22321-22321,22370-22370,22555-22555,22800-22800,22951-", "22951,23456-23456,24000-24006,24242-24242,24249-24249,24345-24347,24386-", "24386,24554-24554,24677-24678,24922-24922,25000-25009,25378-25378,25544-", "25544,25793-25793,25867-25867,25901-25901,25903-25903,26000-26000,26208-", "26208,26260-26264,27000-27010,27345-27345,27374-27374,27504-27504,27665-", "27665,27999-27999,28001-28001,29559-29559,29891-29891,30001-30002,30100-", "30102,30303-30303,30999-30999,31337-31337,31339-31339,31416-31416,31457-", "31457,31554-31554,31556-31556,31620-31620,31765-31765,31785-31787,32261-", "32261,32666-32666,32768-32780,32786-32787,32896-32896,33270-33270,33331-", "33331,33434-33434,33911-33911,34249-34249,34324-34324,34952-34952,36865-", "36865,37475-37475,37651-37651,38037-38037,38201-38201,38292-38293,39681-", "39681,40412-40412,40841-40843,41111-41111,41508-41508,41794-41795,42508-", "42510,43118-43118,43188-43190,44321-44322,44333-44334,44442-44443,44818-", "44818,45000-45000,45054-45054,45678-45678,45966-45966,47000-47000,47557-", "47557,47624-47624,47806-47806,47808-47808,47891-47891,48000-48003,48556-", "48556,49400-49400,50000-50004,50505-50505,50776-50776,51210-51210,53001-", "53001,54320-54321,57341-57341,59595-59595,60177-60177,60179-60179,61439-", "61441,61446-61446,65000-65000,65301-65301", NULL); ports_all_iana_assigned_tcp_and_udp_2020_02_12 = ports ( "T:1-50,52-80,82-99,101-113,115-224,242-248,256-257,259-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-1001,1010,1021-1027,1029," "1033-", "1108,1110-1490,1492-1782,1784-2193,2197-2258,2260-2368,2370-2377,2379-", "2681,2683-2793,2795-2824,2826-2872,2874-2924,2926-3091,3093-3125,3127-", "3300,3302-3321,3326-3366,3372-3402,3405-3545,3547-3693,3695-3993,3995-", "4047,4049-4143,4145-4193,4197,4199,4300-4314,4316,4320-4323,4325-4336,", "4340-4362,4366,4368-4379,4389-4396,4400-4423,4425-4433,4441-4458,4484-", "4488,4500,4534-4538,4545-4559,4563,4566-4570,4573,4590-4605,4621,4646,", "4658-4692,4700-4704,4711,4725-4733,4737-4747,4749-4756,4774,4784-4791,", "4800-4804,4827,4837-4851,4867-4871,4876-4885,4888-4889,4894,4899-4902,", "4912-4915,4936-4937,4940-4942,4949-4953,4969-4971,4980,4984-4991,4999-", "5015,5020-5034,5042-5075,5078-5087,5092-5094,5099-5107,5111-5112,5114-", "5117,5120,5133-5137,5145-5146,5150-5157,5161-5168,5172,5190-5197,5200-", "5203,5209,5215,5221-5237,5245-5254,5264-5265,5269-5272,5280-5282,5298-", "5310,5312-5318,5320-5321,5343-5344,5349-5364,5397-5437,5443,5445,5450,", "5453-5456,5461-5465,5470-5475,5500-5507,5550,5553-5557,5565-5569,5573-", "5575,5579-5586,5597-5605,5618,5627-5639,5646,5666,5670-5684,5687-5689,", "5693,5696,5700,5705,5713-5730,5741-5748,5750,5755,5757,5766-5771,5777,", "5780-5787,5793-5794,5813-5814,5841-5842,5859,5863,5868,5883,5900,5910-", "5913,5963,5968-5969,5984-5993,5999,6064-6066,6068-6077,6080-6088,6099-", "6118,6121-6124,6130,6133,6140-6149,6159-6163,6200-6201,6209,6222,6241-", "6244,6251-6253,6267-6269,6300-6301,6306,6315-6317,6320-6322,6324-6326,", "6343-6344,6346-6347,6350,6355,6360,6363,6370,6379,6382,6389-6390,6417-", "6421,6432,6442-6446,6455-6456,6464,6471,6480-6489,6500-6503,6505-6511,", "6513-6515,6543-6544,6547-6551,6558,6566,6568,6579-6583,6600-6602,6619-", "6629,6632-6636,6640,6653,6655-6657,6670-6673,6678-6679,6687-6690,6696-", "6697,6701-6706,6714-6716,6767-6771,6777-6778,6784-6791,6801,6817,6831,", "6841-6842,6850,6868,6888,6900-6901,6924,6935-6936,6946,6951,6961-6966,", "6969-6970,6997-7026,7030-7031,7040,7070-7073,7080,7088,7095,7099-7101,", "7107,7117,7121,7128-7129,7161-7174,7181,7200-7202,7215-7216,7227-7229,", "7235-7237,7244,7262,7272-7283,7365,7391-7395,7397,7400-7402,7410-7411,", "7420-7421,7426-7431,7437,7443,7471,7473-7474,7478,7491,7500-7501,7508-", "7511,7542-7551,7560,7563,7566,7569-7570,7574,7588,7606,7624,7626-7631,", "7633,7648,7663,7672-7677,7680,7683,7687,7689,7697,7700-7701,7707-7708,", "7720,7724-7728,7734,7738,7741-7744,7747,7775,7777-7779,7781,7784,7786-", "7787,7789,7794,7797-7802,7810,7845-7847,7869-7872,7878,7880,7887,7900-", "7903,7913,7932-7933,7962,7967,7979-7982,7997-8009,8015-8016,8019-8023,", "8025-8026,8032-8034,8040-8044,8051-8060,8066-8067,8070,8074,8077,8080-", "8084,8086-8088,8090-8091,8097,8100-8102,8111,8115-8118,8121-8122,8128-", "8132,8140,8148-8149,8153,8160-8162,8181-8184,8190-8192,8194-8195,8199-", "8202,8204-8208,8211,8230-8232,8243,8266,8270,8276,8280,8282,8292-8294,", "8300-8301,8313,8320-8322,8351,8376-8380,8383-8384,8400-8405,8415-8417,", "8423,8442-8445,8450,8457,8470-8474,8500-8503,8554-8555,8567,8600,8609-", "8615,8665-8666,8675,8686,8688,8699,8710-8711,8732-8733,8750,8763-8770,", "8778,8786-8787,8793,8800,8804-8805,8807-8809,8873,8880-8881,8883,8888-", "8894,8899-8901,8910-8913,8937,8953-8954,8980-8981,8989-8991,8997-9002,", "9005,9007-9011,9020-9026,9050-9051,9060,9080-9081,9083-9093,9100-9107,", "9111,9119,9122-9123,9131,9160-9164,9191,9200-9217,9222,9255,9277-9287,", "9292-9295,9300,9306,9312,9318,9321,9339,9343-9346,9374,9380,9387-9390,", "9396-9397,9400-9402,9418,9443-9445,9450,9500,9522,9535-9536,9555,9592-", "9600,9612,9614,9616-9618,9628-9632,9640,9666-9668,9694-9695,9700,9747,", "9750,9753,9762,9800-9802,9875-9878,9888-9889,9898-9900,9903,9909,9911,", "9925,9950-9956,9966,9978-9979,9981,9987-9988,9990-10010,10020,10023," "10050-", "10051,10055,10080-10081,10100-10104,10107,10110-10111,10113-10117,10125,", "10128-10129,10160-10162,10200-10201,10252-10253,10260-10261,10288,10321,", "10439,10443,10500,10540-10544,10548,10631,10800,10805,10809-10810,10860,", "10880,10933,10990,11000-11001,11095,11103-11106,11108-11112,11161-11165,", "11171-11175,11201-11202,11208,11211,11319-11321,11367,11371,11430,11489,", "11600,11623,11720,11723,11751,11796,11876-11877,11967,11971,12000-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-14002,14033-14034,14141-", "14143,14145,14149-14150,14154,14250,14414,14500,14936-14937,15000,15002,", "15118,15345,15363,15555,15660,15740,15998-16003,16020-16021,16161-16162,", "16309-16311,16360-16361,16367-16368,16384-16385,16619,16665-16666,16789,", "16900,16950,16991-16995,17007,17184-17185,17219-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,19788,19998-20003,", "20005,20012-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,23272,23294,23333,", "23400-23402,23456-23457,23546,24000-24006,24242,24249,24321-24323,24386,", "24465,24554,24577,24666,24676-24678,24680,24754,24850,24922,25000-25009,", "25576,25604,25793,25900-25903,25954-25955,26000,26133,26208,26257,26260-", "26263,26486-26487,26489,27010,27017,27345,27442,27504,27782,27876,27999-", "28001,28010,28119,28200,28240,28589,29118,29167-29168,29999-30004,30100,", "30260,30400,30832,30999,31016,31020,31029,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-33435,33656,34249,", "34378-34379,34567,34962-34964,34980,35000-35006,35100,35354-35357,36001,", "36411-36412,36422,36462,36524,36602,36700,36865,37475,37483,37601,37654,", "38000-38002,38201-38203,38412,38422,38462,38472,38800,38865,39681,40000,", "40023,40404,40841-40843,40853,41111,41121,41230,41794-41797,42508-42510,", "43000,43188-43191,43210,43438-43441,44123,44321-44323,44444-44445,44544,", "44553,44600,44818,44900,45000-45002,45045,45054,45514,45678,45824-45825,", "45966,46336,46998-47001,47100,47557,47624,47806,47808-47809,48000-48005,", "48048-48050,48128-48129,48556,48619,48653,49000-49001,49150,6000-6063,", "6665-6669, ", "U:1-50,52-80,82-99,101-113,115-224,242-248,256-257,259-271,280-284,286-", "287,308-324,333,344-584,586-658,660-702,704-707,709-716,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-1001,1008,1010,1021-1027," "1029,", "1033-1108,1110-1490,1492-1782,1784-2193,2197-2258,2260-2368,2370-2375,", "2377,2379-2681,2683-2793,2795-2824,2826-2872,2874-2924,2926-3091,3093-", "3125,3127-3300,3302-3321,3326-3366,3372-3402,3405-3545,3547-3693,3695-", "3993,3995-4047,4049-4143,4145-4193,4197,4199,4300-4314,4316,4320-4323,", "4325-4336,4340-4362,4366,4368-4379,4389-4396,4400-4423,4425-4433,4441-", "4458,4484-4488,4500,4534-4538,4545-4559,4563,4566-4570,4573,4590-4605,", "4621,4646,4658-4692,4700-4704,4711,4725-4733,4737-4747,4749-4756,4774,", "4784-4791,4800-4804,4827,4837-4851,4867-4871,4876-4885,4888-4889,4894,", "4899-4902,4912,4914-4915,4936-4937,4940-4942,4949-4953,4969-4971,4980,", "4984-4991,4999-5015,5020-5034,5042-5075,5078-5087,5092-5094,5099-5107,", "5111-5112,5114-5117,5120,5133-5137,5145-5146,5150-5157,5161-5168,5172,", "5190-5197,5200-5203,5209,5215,5221-5237,5245-5254,5264-5265,5269-5272,", "5280-5282,5298-5310,5312-5318,5320-5321,5343-5344,5349-5364,5397-5437,", "5443,5445,5450,5453-5456,5461-5465,5470-5475,5500-5507,5550,5553-5557,", "5565-5569,5573-5575,5579-5586,5597-5605,5618,5627-5639,5646,5666,5670-", "5684,5687-5689,5693,5696,5700,5705,5713-5730,5741-5748,5750,5755,5757,", "5766-5771,5777,5780-5787,5793-5794,5813-5814,5841-5842,5859,5863,5868,", "5900,5910-5913,5963,5968-5969,5984-5993,5999,6064-6066,6068-6077,6080-", "6088,6099-6118,6121-6124,6130,6133,6140-6149,6159-6163,6200-6201,6209,", "6222,6241-6244,6251-6253,6267-6269,6300-6301,6306,6315-6317,6320-6322,", "6324-6326,6343-6344,6346-6347,6350,6355,6360,6363,6370,6379,6382,6389-", "6390,6417-6421,6432,6442-6446,6455-6456,6464,6471,6480-6489,6500-6503,", "6505-6511,6513-6515,6543-6544,6547-6551,6558,6566,6568,6579-6583,6600-", "6602,6619-6629,6632-6636,6640,6653,6655-6657,6670-6673,6678-6679,6687-", "6690,6696-6697,6701-6706,6714-6716,6767-6771,6777-6778,6784-6791,6801,", "6817,6831,6841-6842,6850,6868,6888,6900-6901,6924,6935-6936,6946,6951,", "6961-6966,6969-6970,6997-7026,7030-7031,7040,7070-7073,7080,7088,7095,", "7099-7101,7107,7117,7121,7128-7129,7161-7174,7181,7200-7201,7215-7216,", "7227-7229,7235-7237,7244,7262,7272-7283,7365,7391-7395,7397,7400-7402,", "7410-7411,7420-7421,7426-7431,7437,7443,7471,7473-7474,7478,7491,7500-", "7501,7508-7511,7542-7551,7560,7563,7566,7569-7570,7574,7588,7606,7624,", "7626-7631,7633,7648,7663,7672-7677,7680,7683,7687,7689,7697,7700-7702,", "7707-7708,7720,7724-7728,7734,7738,7741-7744,7747,7775,7777-7779,7781,", "7784,7786-7787,7789,7794,7797-7802,7810,7845-7847,7869-7872,7878,7880,", "7887,7900-7903,7913,7932-7933,7962,7967,7979-7982,7997-8009,8015-8016,", "8019-8023,8025-8026,8032-8034,8040-8044,8051-8060,8066-8067,8070,8074,", "8077,8080-8084,8086-8088,8090-8091,8097,8100-8102,8111,8115-8118,8121-", "8122,8128-8132,8140,8148-8149,8153,8160-8162,8181-8184,8190-8192,8194-", "8195,8199-8202,8204-8208,8211,8230-8232,8243,8266,8270,8276,8280,8282,", "8292-8294,8300-8301,8313,8320-8322,8351,8376-8380,8383-8384,8400-8405,", "8415-8417,8423,8442-8445,8450,8457,8470-8474,8500-8503,8554-8555,8567,", "8600,8609-8615,8665-8666,8675,8686,8688,8699,8710-8711,8732-8733,8750,", "8763-8770,8778,8786-8787,8793,8800,8804-8805,8807-8809,8873,8880-8881,", "8883,8888-8894,8899-8901,8910-8913,8937,8953-8954,8980-8981,8989-8991,", "8997-9002,9005,9007-9011,9020-9026,9050-9051,9060,9080-9081,9083-9093,", "9100-9107,9111,9119,9122-9123,9131,9160-9164,9191,9200-9217,9222,9255,", "9277-9287,9292-9295,9300,9306,9312,9318,9321,9339,9343-9346,9374,9380,", "9387-9390,9396-9397,9400-9402,9418,9443-9445,9450,9500,9522,9535-9536,", "9555,9592-9600,9612,9614,9616-9618,9628-9632,9640,9666-9668,9694-9695,", "9700,9747,9750,9753,9762,9800-9802,9875,9877-9878,9888-9889,9898-9901,", "9903,9909,9911,9925,9950-9956,9966,9978-9979,9981,9987-9988,9990-10010,", "10020,10023,10050-10051,10055,10080-10081,10100-10104,10107,10110-10111,", "10113-10117,10125,10128-10129,10160-10162,10200-10201,10252-10253,10260-", "10261,10288,10321,10439,10443,10500,10540-10544,10548,10631,10800,10805,", "10809-10810,10860,10880,10933,10990,11000-11001,11095,11103-11106,11108-", "11112,11161-11165,11171-11175,11201-11202,11208,11211,11319-11321,11367,", "11371,11430,11489,11600,11623,11720,11723,11751,11796,11876-11877,11967,", "11971,12000-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-14002,", "14033-14034,14141-14143,14145,14149-14150,14154,14250,14414,14500,14936-", "14937,15000,15002,15118,15345,15363,15555,15660,15740,15998-16003,16020-", "16021,16161-16162,16309-16311,16360-16361,16367-16368,16384-16385,16619,", "16665-16666,16789,16900,16950,16991-16995,17007,17184-17185,17219-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,", "19788,19998-20003,20005,20012-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,", "23272,23294,23333,23400-23402,23456-23457,23546,24000-24006,24242,24249,", "24321-24323,24386,24465,24554,24577,24666,24676-24678,24680,24754,24850,", "24922,25000-25009,25576,25604,25793,25900-25903,25954-25955,26000,26133,", "26208,26257,26260-26263,26486-26487,26489,27010,27017,27345,27442,27504,", "27782,27876,27999-28001,28010,28119,28200,28240,28589,29118,29167-29168,", "29999-30004,30100,30260,30400,30832,30999,31016,31020,31029,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-", "33435,33656,34249,34378-34379,34567,34962-34964,34980,35000-35006,35100,", "35354-35357,36001,36411-36412,36422,36462,36524,36602,36700,36865,37475,", "37483,37601,37654,38000-38002,38201-38203,38412,38422,38462,38472,38800,", "38865,39681,40000,40023,40404,40841-40843,40853,41111,41121,41230,41794-", "41797,42508-42510,43000,43188-43191,43210,43438-43441,44123,44321-44323,", "44444-44445,44544,44553,44600,44818,44900,45000-45002,45045,45054,45514,", "45678,45824-45825,45966,46336,46998-47001,47100,47557,47624,47806,47808-", "47809,48000-48005,48048-48050,48128-48129,48556,48619,48653,49000-49001,", "49150,6000-6063,6665-6669", NULL); ports_all_tcp_and_nmap_5_51_top_100_udp = ports ( "T:1-65535, ", "U:7-7,9-9,17-17,19-19,49-49,53-53,67-69,80-80,88-88,111-111,120-120,123-", "123,135-139,158-158,161-162,177-177,427-427,443-443,445-445,497-497,500-", "500,514-515,518-518,520-520,593-593,623-623,626-626,631-631,996-999,1022-", "1023,1025-1030,1433-1434,1645-1646,1701-1701,1718-1719,1812-1813,1900-", "1900,2000-2000,2048-2049,2222-2223,3283-3283,3456-3456,3703-3703,4444-", "4444,4500-4500,5000-5000,5060-5060,5353-5353,5632-5632,9200-9200,10000-", "10000,17185-17185,20031-20031,30718-30718,31337-31337,32768-32769,32771-", "32771,32815-32815,33281-33281,49152-49154,49156-49156,49181-49182,49185-", "49186,49188-49188,49190-49194,49200-49201", NULL); ports_all_tcp_and_nmap_5_51_top_1000_udp = ports ( "T:1-65535, " "U:2-3,7-7,9-9,13-13,17-17,19-23,37-38,42-42,49-49,53-53,67-69,80-80,88-" "88,", "111-113,120-120,123-123,135-139,158-158,161-162,177-177,192-192,199-199,", "207-207,217-217,363-363,389-389,402-402,407-407,427-427,434-434,443-443,", "445-445,464-464,497-497,500-500,502-502,512-515,517-518,520-520,539-539,", "559-559,593-593,623-623,626-626,631-631,639-639,643-643,657-657,664-664,", "682-689,764-764,767-767,772-776,780-782,786-786,789-789,800-800,814-814,", "826-826,829-829,838-838,902-903,944-944,959-959,965-965,983-983,989-990,", "996-1001,1007-1008,1012-1014,1019-1051,1053-1060,1064-1070,1072-1072," "1080-", "1081,1087-1088,1090-1090,1100-1101,1105-1105,1124-1124,1200-1200,1214-", "1214,1234-1234,1346-1346,1419-1419,1433-1434,1455-1455,1457-1457,1484-", "1485,1524-1524,1645-1646,1701-1701,1718-1719,1761-1761,1782-1782,1804-", "1804,1812-1813,1885-1886,1900-1901,1993-1993,2000-2000,2002-2002,2048-", "2049,2051-2051,2148-2148,2160-2161,2222-2223,2343-2343,2345-2345,2362-", "2362,2967-2967,3052-3052,3130-3130,3283-3283,3296-3296,3343-3343,3389-", "3389,3401-3401,3456-3457,3659-3659,3664-3664,3702-3703,4000-4000,4008-", "4008,4045-4045,4444-4444,4500-4500,4666-4666,4672-4672,5000-5003,5010-", "5010,5050-5050,5060-5060,5093-5093,5351-5351,5353-5353,5355-5355,5500-", "5500,5555-5555,5632-5632,6000-6002,6004-6004,6050-6050,6346-6347,6970-", "6971,7000-7000,7938-7938,8000-8001,8010-8010,8181-8181,8193-8193,8900-", "8900,9000-9001,9020-9020,9103-9103,9199-9200,9370-9370,9876-9877,9950-", "9950,10000-10000,10080-10080,11487-11487,16086-16086,16402-16402,16420-", "16420,16430-16430,16433-16433,16449-16449,16498-16498,16503-16503,16545-", "16545,16548-16548,16573-16573,16674-16674,16680-16680,16697-16697,16700-", "16700,16708-16708,16711-16711,16739-16739,16766-16766,16779-16779,16786-", "16786,16816-16816,16829-16829,16832-16832,16838-16839,16862-16862,16896-", "16896,16912-16912,16918-16919,16938-16939,16947-16948,16970-16970,16972-", "16972,16974-16974,17006-17006,17018-17018,17077-17077,17091-17091,17101-", "17101,17146-17146,17184-17185,17205-17205,17207-17207,17219-17219,17236-", "17237,17282-17282,17302-17302,17321-17321,17331-17332,17338-17338,17359-", "17359,17417-17417,17423-17424,17455-17455,17459-17459,17468-17468,17487-", "17487,17490-17490,17494-17494,17505-17505,17533-17533,17549-17549,17573-", "17573,17580-17580,17585-17585,17592-17592,17605-17605,17615-17616,17629-", "17629,17638-17638,17663-17663,17673-17674,17683-17683,17726-17726,17754-", "17754,17762-17762,17787-17787,17814-17814,17823-17824,17836-17836,17845-", "17845,17888-17888,17939-17939,17946-17946,17989-17989,18004-18004,18081-", "18081,18113-18113,18134-18134,18156-18156,18228-18228,18234-18234,18250-", "18250,18255-18255,18258-18258,18319-18319,18331-18331,18360-18360,18373-", "18373,18449-18449,18485-18485,18543-18543,18582-18582,18605-18605,18617-", "18617,18666-18666,18669-18669,18676-18676,18683-18683,18807-18807,18818-", "18818,18821-18821,18830-18830,18832-18832,18835-18835,18869-18869,18883-", "18883,18888-18888,18958-18958,18980-18980,18985-18985,18987-18987,18991-", "18991,18994-18994,18996-18996,19017-19017,19022-19022,19039-19039,19047-", "19047,19075-19075,19096-19096,19120-19120,19130-19130,19140-19141,19154-", "19154,19161-19161,19165-19165,19181-19181,19193-19193,19197-19197,19222-", "19222,19227-19227,19273-19273,19283-19283,19294-19294,19315-19315,19322-", "19322,19332-19332,19374-19374,19415-19415,19482-19482,19489-19489,19500-", "19500,19503-19504,19541-19541,19600-19600,19605-19605,19616-19616,19624-", "19625,19632-19632,19639-19639,19647-19647,19650-19650,19660-19660,19662-", "19663,19682-19683,19687-19687,19695-19695,19707-19707,19717-19719,19722-", "19722,19728-19728,19789-19789,19792-19792,19933-19933,19935-19936,19956-", "19956,19995-19995,19998-19998,20003-20004,20019-20019,20031-20031,20082-", "20082,20117-20117,20120-20120,20126-20126,20129-20129,20146-20146,20154-", "20154,20164-20164,20206-20206,20217-20217,20249-20249,20262-20262,20279-", "20279,20288-20288,20309-20309,20313-20313,20326-20326,20359-20360,20366-", "20366,20380-20380,20389-20389,20409-20409,20411-20411,20423-20425,20445-", "20445,20449-20449,20464-20465,20518-20518,20522-20522,20525-20525,20540-", "20540,20560-20560,20665-20665,20678-20679,20710-20710,20717-20717,20742-", "20742,20752-20752,20762-20762,20791-20791,20817-20817,20842-20842,20848-", "20848,20851-20851,20865-20865,20872-20872,20876-20876,20884-20884,20919-", "20919,21000-21000,21016-21016,21060-21060,21083-21083,21104-21104,21111-", "21111,21131-21131,21167-21167,21186-21186,21206-21207,21212-21212,21247-", "21247,21261-21261,21282-21282,21298-21298,21303-21303,21318-21318,21320-", "21320,21333-21333,21344-21344,21354-21354,21358-21358,21360-21360,21364-", "21364,21366-21366,21383-21383,21405-21405,21454-21454,21468-21468,21476-", "21476,21514-21514,21524-21525,21556-21556,21566-21566,21568-21568,21576-", "21576,21609-21609,21621-21621,21625-21625,21644-21644,21649-21649,21655-", "21655,21663-21663,21674-21674,21698-21698,21702-21702,21710-21710,21742-", "21742,21780-21780,21784-21784,21800-21800,21803-21803,21834-21834,21842-", "21842,21847-21847,21868-21868,21898-21898,21902-21902,21923-21923,21948-", "21948,21967-21967,22029-22029,22043-22043,22045-22045,22053-22053,22055-", "22055,22105-22105,22109-22109,22123-22124,22341-22341,22692-22692,22695-", "22695,22739-22739,22799-22799,22846-22846,22914-22914,22986-22986,22996-", "22996,23040-23040,23176-23176,23354-23354,23531-23531,23557-23557,23608-", "23608,23679-23679,23781-23781,23965-23965,23980-23980,24007-24007,24279-", "24279,24511-24511,24594-24594,24606-24606,24644-24644,24854-24854,24910-", "24910,25003-25003,25157-25157,25240-25240,25280-25280,25337-25337,25375-", "25375,25462-25462,25541-25541,25546-25546,25709-25709,25931-25931,26407-", "26407,26415-26415,26720-26720,26872-26872,26966-26966,27015-27015,27195-", "27195,27444-27444,27473-27473,27482-27482,27707-27707,27892-27892,27899-", "27899,28122-28122,28369-28369,28465-28465,28493-28493,28543-28543,28547-", "28547,28641-28641,28840-28840,28973-28973,29078-29078,29243-29243,29256-", "29256,29810-29810,29823-29823,29977-29977,30263-30263,30303-30303,30365-", "30365,30544-30544,30656-30656,30697-30697,30704-30704,30718-30718,30975-", "30975,31059-31059,31073-31073,31109-31109,31189-31189,31195-31195,31335-", "31335,31337-31337,31365-31365,31625-31625,31681-31681,31731-31731,31891-", "31891,32345-32345,32385-32385,32528-32528,32768-32780,32798-32798,32815-", "32815,32818-32818,32931-32931,33030-33030,33249-33249,33281-33281,33354-", "33355,33459-33459,33717-33717,33744-33744,33866-33866,33872-33872,34038-", "34038,34079-34079,34125-34125,34358-34358,34422-34422,34433-34433,34555-", "34555,34570-34570,34577-34580,34758-34758,34796-34796,34855-34855,34861-", "34862,34892-34892,35438-35438,35702-35702,35777-35777,35794-35794,36108-", "36108,36206-36206,36384-36384,36458-36458,36489-36489,36669-36669,36778-", "36778,36893-36893,36945-36945,37144-37144,37212-37212,37393-37393,37444-", "37444,37602-37602,37761-37761,37783-37783,37813-37813,37843-37843,38037-", "38037,38063-38063,38293-38293,38412-38412,38498-38498,38615-38615,39213-", "39213,39217-39217,39632-39632,39683-39683,39714-39714,39723-39723,39888-", "39888,40019-40019,40116-40116,40441-40441,40539-40539,40622-40622,40708-", "40708,40711-40711,40724-40724,40732-40732,40805-40805,40847-40847,40866-", "40866,40915-40915,41058-41058,41081-41081,41308-41308,41370-41370,41446-", "41446,41524-41524,41638-41638,41702-41702,41774-41774,41896-41896,41967-", "41967,41971-41971,42056-42056,42172-42172,42313-42313,42431-42431,42434-", "42434,42508-42508,42557-42557,42577-42577,42627-42627,42639-42639,43094-", "43094,43195-43195,43370-43370,43514-43514,43686-43686,43824-43824,43967-", "43967,44101-44101,44160-44160,44179-44179,44185-44185,44190-44190,44253-", "44253,44334-44334,44508-44508,44923-44923,44946-44946,44968-44968,45247-", "45247,45380-45380,45441-45441,45685-45685,45722-45722,45818-45818,45928-", "45928,46093-46093,46532-46532,46836-46836,47624-47624,47765-47765,47772-", "47772,47808-47808,47915-47915,47981-47981,48078-48078,48189-48189,48255-", "48255,48455-48455,48489-48489,48761-48761,49152-49163,49165-49182,49184-", "49202,49204-49205,49207-49216,49220-49220,49222-49222,49226-49226,49259-", "49259,49262-49262,49306-49306,49350-49350,49360-49360,49393-49393,49396-", "49396,49503-49503,49640-49640,49968-49968,50099-50099,50164-50164,50497-", "50497,50612-50612,50708-50708,50919-50919,51255-51255,51456-51456,51554-", "51554,51586-51586,51690-51690,51717-51717,51905-51905,51972-51972,52144-", "52144,52225-52225,52503-52503,53006-53006,53037-53037,53571-53571,53589-", "53589,53838-53838,54094-54094,54114-54114,54281-54281,54321-54321,54711-", "54711,54807-54807,54925-54925,55043-55043,55544-55544,55587-55587,56141-", "56141,57172-57172,57409-57410,57813-57813,57843-57843,57958-57958,57977-", "57977,58002-58002,58075-58075,58178-58178,58419-58419,58631-58631,58640-", "58640,58797-58797,59193-59193,59207-59207,59765-59765,59846-59846,60172-", "60172,60381-60381,60423-60423,61024-61024,61142-61142,61319-61319,61322-", "61322,61370-61370,61412-61412,61481-61481,61550-61550,61685-61685,61961-", "61961,62154-62154,62287-62287,62575-62575,62677-62677,62699-62699,62958-", "62958,63420-63420,63555-63555,64080-64080,64481-64481,64513-64513,64590-", "64590,64727-64727", NULL); ports_nmap_5_51_top_2000_tcp_and_top_100_udp = ports ( "T:1-1,3-4,6-7,9-9,13-13,17-17,19-27,30-30,32-33,37-37,42-43,49-49,53-53,", "55-55,57-57,59-59,70-70,77-77,79-90,98-100,102-102,106-106,109-111,113-", "113,119-119,123-123,125-125,127-127,135-135,139-139,143-144,146-146,157-", "157,161-161,163-163,179-179,199-199,210-212,220-220,222-223,225-225,250-", "252,254-257,259-259,264-264,280-280,301-301,306-306,311-311,333-333,340-", "340,366-366,388-389,406-407,411-411,416-417,419-419,425-425,427-427,441-", "445,447-447,458-458,464-465,475-475,481-481,497-497,500-500,502-502,512-", "515,523-524,540-541,543-545,548-548,554-557,563-563,587-587,593-593,600-", "600,602-602,606-606,610-610,616-617,621-621,623-623,625-625,631-631,636-", "636,639-639,641-641,646-646,648-648,655-655,657-657,659-660,666-669,674-", "674,683-684,687-687,690-691,700-701,705-705,709-711,713-715,720-720,722-", "722,725-726,728-732,740-740,748-749,754-754,757-758,765-765,777-778,780-", "780,782-783,786-787,790-790,792-792,795-795,800-803,805-806,808-808,822-", "823,825-825,829-829,839-840,843-843,846-846,856-856,859-859,862-862,864-", "864,873-874,878-878,880-880,888-888,898-898,900-905,911-913,918-918,921-", "922,924-924,928-928,930-931,943-943,953-953,969-969,971-971,980-981,987-", "987,990-990,992-993,995-996,998-1002,1004-1015,1020-1114,1116-1119,1121-", "1128,1130-1132,1134-1138,1141-1141,1143-1145,1147-1154,1156-1159,1162-", "1169,1173-1176,1179-1180,1182-1188,1190-1192,1194-1196,1198-1201,1204-", "1204,1207-1213,1215-1218,1220-1223,1228-1229,1233-1234,1236-1236,1239-", "1241,1243-1244,1247-1251,1259-1259,1261-1262,1264-1264,1268-1268,1270-", "1272,1276-1277,1279-1279,1282-1282,1287-1287,1290-1291,1296-1297,1299-", "1303,1305-1311,1314-1319,1321-1322,1324-1324,1327-1328,1330-1331,1334-", "1334,1336-1337,1339-1340,1347-1347,1350-1353,1357-1357,1413-1414,1417-", "1417,1433-1434,1443-1443,1455-1455,1461-1461,1494-1494,1500-1501,1503-", "1503,1516-1516,1521-1522,1524-1526,1533-1533,1547-1547,1550-1550,1556-", "1556,1558-1560,1565-1566,1569-1569,1580-1580,1583-1584,1592-1592,1594-", "1594,1598-1598,1600-1600,1605-1605,1607-1607,1615-1615,1620-1620,1622-", "1622,1632-1632,1635-1635,1638-1638,1641-1641,1645-1645,1658-1658,1666-", "1666,1677-1677,1683-1683,1687-1688,1691-1691,1694-1694,1699-1701,1703-", "1703,1707-1709,1711-1713,1715-1715,1717-1723,1730-1730,1735-1736,1745-", "1745,1750-1750,1752-1753,1755-1755,1761-1761,1782-1783,1791-1792,1799-", "1801,1805-1808,1811-1812,1823-1823,1825-1825,1835-1835,1839-1840,1858-", "1858,1861-1864,1871-1871,1875-1875,1900-1901,1911-1912,1914-1914,1918-", "1918,1924-1924,1927-1927,1935-1935,1947-1947,1954-1954,1958-1958,1971-", "1976,1981-1981,1984-1984,1998-2013,2020-2022,2025-2025,2030-2031,2033-", "2035,2038-2038,2040-2049,2062-2062,2065-2065,2067-2070,2080-2083,2086-", "2087,2095-2096,2099-2101,2103-2107,2111-2112,2115-2115,2119-2119,2121-", "2121,2124-2124,2126-2126,2134-2135,2142-2142,2144-2144,2148-2148,2150-", "2150,2160-2161,2170-2170,2179-2179,2187-2187,2190-2191,2196-2197,2200-", "2201,2203-2203,2222-2222,2224-2224,2232-2232,2241-2241,2250-2251,2253-", "2253,2260-2262,2265-2265,2269-2271,2280-2280,2288-2288,2291-2292,2300-", "2302,2304-2304,2312-2313,2323-2323,2325-2326,2330-2330,2335-2335,2340-", "2340,2366-2366,2371-2372,2381-2383,2391-2391,2393-2394,2399-2399,2401-", "2401,2418-2418,2425-2425,2433-2433,2435-2436,2438-2439,2449-2449,2456-", "2456,2463-2463,2472-2472,2492-2492,2500-2501,2505-2505,2522-2522,2525-", "2525,2531-2532,2550-2551,2557-2558,2567-2567,2580-2580,2583-2584,2598-", "2598,2600-2602,2604-2608,2622-2623,2628-2628,2631-2631,2638-2638,2644-", "2644,2691-2691,2700-2702,2706-2706,2710-2712,2717-2718,2723-2723,2725-", "2725,2728-2728,2734-2734,2800-2800,2804-2804,2806-2806,2809-2809,2811-", "2812,2847-2847,2850-2850,2869-2869,2875-2875,2882-2882,2888-2889,2898-", "2898,2901-2903,2908-2910,2920-2920,2930-2930,2957-2958,2967-2968,2973-", "2973,2984-2984,2987-2988,2991-2991,2997-2998,3000-3003,3005-3007,3011-", "3011,3013-3014,3017-3017,3023-3023,3025-3025,3030-3031,3050-3050,3052-", "3052,3057-3057,3062-3063,3071-3071,3077-3077,3080-3080,3089-3089,3102-", "3103,3118-3119,3121-3121,3128-3128,3146-3146,3162-3162,3167-3168,3190-", "3190,3200-3200,3210-3211,3220-3221,3240-3240,3260-3261,3263-3263,3268-", "3269,3280-3281,3283-3283,3291-3291,3299-3301,3304-3304,3306-3307,3310-", "3311,3319-3319,3322-3325,3333-3334,3351-3351,3362-3363,3365-3365,3367-", "3372,3374-3374,3376-3376,3388-3390,3396-3396,3399-3400,3404-3404,3410-", "3410,3414-3415,3419-3419,3425-3425,3430-3430,3439-3439,3443-3443,3456-", "3456,3476-3476,3479-3479,3483-3483,3485-3486,3493-3493,3497-3497,3503-", "3503,3505-3506,3511-3511,3513-3515,3517-3517,3519-3520,3526-3527,3530-", "3530,3532-3532,3546-3546,3551-3551,3577-3577,3580-3580,3586-3586,3599-", "3600,3602-3603,3621-3622,3632-3632,3636-3637,3652-3653,3656-3656,3658-", "3659,3663-3663,3669-3670,3672-3672,3680-3681,3683-3684,3689-3690,3697-", "3697,3700-3700,3703-3703,3712-3712,3728-3728,3731-3731,3737-3737,3742-", "3742,3749-3749,3765-3766,3784-3784,3787-3788,3790-3790,3792-3793,3795-", "3796,3798-3801,3803-3803,3806-3806,3808-3814,3817-3817,3820-3820,3823-", "3828,3830-3831,3837-3837,3839-3839,3842-3842,3846-3853,3856-3856,3859-", "3860,3863-3863,3868-3872,3876-3876,3878-3880,3882-3882,3888-3890,3897-", "3897,3899-3899,3901-3902,3904-3909,3911-3911,3913-3916,3918-3920,3922-", "3923,3928-3931,3935-3937,3940-3941,3943-3946,3948-3949,3952-3952,3956-", "3957,3961-3964,3967-3969,3971-3972,3975-3975,3979-3983,3986-3986,3989-", "4007,4009-4010,4016-4016,4020-4020,4022-4022,4024-4025,4029-4029,4035-", "4036,4039-4040,4045-4045,4056-4056,4058-4058,4065-4065,4080-4080,4087-", "4087,4090-4090,4096-4096,4100-4101,4111-4113,4118-4121,4125-4126,4129-", "4129,4135-4135,4141-4141,4143-4143,4147-4147,4158-4158,4161-4161,4164-", "4164,4174-4174,4190-4190,4192-4192,4200-4200,4206-4206,4220-4220,4224-", "4224,4234-4234,4242-4242,4252-4252,4262-4262,4279-4279,4294-4294,4297-", "4298,4300-4300,4302-4302,4321-4321,4325-4325,4328-4328,4333-4333,4342-", "4343,4355-4358,4369-4369,4374-4376,4384-4384,4388-4388,4401-4401,4407-", "4407,4414-4415,4418-4418,4430-4430,4433-4433,4442-4447,4449-4449,4454-", "4454,4464-4464,4471-4471,4476-4476,4516-4517,4530-4530,4534-4534,4545-", "4545,4550-4550,4555-4555,4558-4559,4567-4567,4570-4570,4599-4602,4606-", "4606,4609-4609,4644-4644,4649-4649,4658-4658,4662-4662,4665-4665,4687-", "4687,4689-4689,4700-4700,4712-4712,4745-4745,4760-4760,4767-4767,4770-", "4771,4778-4778,4793-4793,4800-4800,4819-4819,4848-4848,4859-4860,4875-", "4877,4881-4881,4899-4900,4903-4903,4912-4912,4931-4931,4949-4949,4998-", "5005,5009-5017,5020-5021,5023-5023,5030-5030,5033-5033,5040-5040,5050-", "5055,5060-5061,5063-5063,5066-5066,5070-5070,5074-5074,5080-5081,5087-", "5088,5090-5090,5095-5096,5098-5098,5100-5102,5111-5111,5114-5114,5120-", "5122,5125-5125,5133-5133,5137-5137,5147-5147,5151-5152,5190-5190,5200-", "5202,5212-5212,5214-5214,5219-5219,5221-5223,5225-5226,5233-5235,5242-", "5242,5250-5250,5252-5252,5259-5259,5261-5261,5269-5269,5279-5280,5291-", "5291,5298-5298,5339-5339,5347-5347,5353-5353,5357-5357,5370-5370,5377-", "5377,5405-5405,5414-5414,5423-5423,5431-5433,5440-5442,5444-5444,5457-", "5458,5473-5473,5475-5475,5500-5502,5510-5510,5520-5520,5544-5544,5550-", "5550,5552-5555,5557-5557,5560-5560,5566-5566,5631-5631,5633-5633,5666-", "5666,5678-5680,5718-5718,5730-5730,5800-5803,5807-5807,5810-5812,5815-", "5815,5818-5818,5822-5823,5825-5825,5850-5850,5859-5859,5862-5862,5868-", "5869,5877-5877,5899-5907,5909-5911,5914-5915,5918-5918,5922-5922,5925-", "5925,5938-5938,5940-5940,5950-5950,5952-5952,5959-5963,5968-5968,5981-", "5981,5987-5989,5998-6009,6017-6017,6025-6025,6050-6051,6059-6060,6068-", "6068,6100-6101,6103-6103,6106-6106,6112-6112,6123-6123,6129-6129,6156-", "6156,6203-6203,6222-6222,6247-6247,6346-6346,6389-6389,6481-6481,6500-", "6500,6502-6502,6504-6504,6510-6510,6520-6520,6543-6543,6547-6547,6550-", "6550,6565-6567,6580-6580,6600-6600,6646-6646,6662-6662,6666-6670,6689-", "6689,6692-6692,6699-6699,6711-6711,6732-6732,6779-6779,6788-6789,6792-", "6792,6839-6839,6881-6881,6896-6896,6901-6901,6969-6969,7000-7004,7007-", "7007,7010-7010,7019-7019,7024-7025,7050-7051,7070-7070,7080-7080,7100-", "7100,7103-7103,7106-7106,7123-7123,7200-7201,7241-7241,7272-7272,7278-", "7278,7281-7281,7402-7402,7435-7435,7438-7438,7443-7443,7496-7496,7512-", "7512,7625-7625,7627-7627,7676-7676,7725-7725,7741-7741,7744-7744,7749-", "7749,7770-7770,7777-7778,7800-7800,7878-7878,7900-7900,7911-7911,7913-", "7913,7920-7921,7929-7929,7937-7938,7999-8002,8007-8011,8015-8016,8019-", "8019,8021-8022,8031-8031,8042-8042,8045-8045,8050-8050,8080-8090,8093-", "8093,8095-8095,8097-8100,8118-8118,8180-8181,8189-8189,8192-8194,8200-", "8200,8222-8222,8254-8254,8290-8294,8300-8300,8333-8333,8383-8383,8385-", "8385,8400-8400,8402-8402,8443-8443,8481-8481,8500-8500,8540-8540,8600-", "8600,8648-8649,8651-8652,8654-8654,8675-8676,8686-8686,8701-8701,8765-", "8766,8800-8800,8873-8873,8877-8877,8888-8889,8899-8899,8987-8987,8994-", "8994,8996-8996,9000-9003,9009-9011,9040-9040,9050-9050,9071-9071,9080-", "9081,9090-9091,9098-9103,9110-9111,9152-9152,9191-9191,9197-9198,9200-", "9200,9207-9207,9220-9220,9290-9290,9409-9409,9415-9415,9418-9418,9443-", "9444,9485-9485,9500-9503,9535-9535,9575-9575,9593-9595,9600-9600,9618-", "9618,9621-9621,9643-9643,9666-9666,9673-9673,9815-9815,9876-9878,9898-", "9898,9900-9900,9914-9914,9917-9917,9929-9929,9941-9941,9943-9944,9968-", "9968,9988-9988,9992-9992,9998-10005,10008-10012,10022-10025,10034-10034,", "10058-10058,10082-10083,10160-10160,10180-10180,10215-10215,10243-10243,", "10566-10566,10616-10617,10621-10621,10626-10626,10628-10629,10778-10778,", "10873-10873,11110-11111,11967-11967,12000-12000,12006-12006,12021-12021,", "12059-12059,12174-12174,12215-12215,12262-12262,12265-12265,12345-12346,", "12380-12380,12452-12452,13456-13456,13722-13722,13724-13724,13782-13783,", "14000-14000,14238-14238,14441-14442,15000-15004,15402-15402,15660-15660,", "15742-15742,16000-16001,16012-16012,16016-16016,16018-16018,16080-16080,", "16113-16113,16705-16705,16800-16800,16851-16851,16992-16993,17595-17595,", "17877-17877,17988-17988,18000-18000,18018-18018,18040-18040,18101-18101,", "18264-18264,18988-18988,19101-19101,19283-19283,19315-19315,19350-19350,", "19780-19780,19801-19801,19842-19842,19900-19900,20000-20000,20002-20002,", "20005-20005,20031-20031,20221-20222,20828-20828,21571-21571,21792-21792,", "22222-22222,22939-22939,23052-23052,23502-23502,23796-23796,24444-24444,", "24800-24800,25734-25735,26000-26000,26214-26214,26470-26470,27000-27000,", "27352-27353,27355-27357,27715-27715,28201-28201,28211-28211,29672-29672,", "29831-29831,30000-30000,30005-30005,30704-30704,30718-30718,30951-30951,", "31038-31038,31337-31337,31727-31727,32768-32785,32791-32792,32803-32803,", "32816-32816,32822-32822,32835-32835,33354-33354,33453-33453,33554-33554,", "33899-33899,34571-34573,35500-35500,35513-35513,37839-37839,38037-38037,", "38185-38185,38188-38188,38292-38292,39136-39136,39376-39376,39659-39659,", "40000-40000,40193-40193,40811-40811,40911-40911,41064-41064,41511-41511,", "41523-41523,42510-42510,44176-44176,44334-44334,44442-44443,44501-44501,", "44709-44709,45100-45100,46200-46200,46996-46996,47544-47544,48080-48080,", "49152-49161,49163-49165,49167-49168,49171-49171,49175-49176,49186-49186,", "49195-49195,49236-49236,49400-49401,49999-50003,50006-50006,50050-50050,", "50300-50300,50389-50389,50500-50500,50636-50636,50800-50800,51103-51103,", "51191-51191,51413-51413,51493-51493,52660-52660,52673-52673,52710-52710,", "52735-52735,52822-52822,52847-52851,52853-52853,52869-52869,53211-53211,", "53313-53314,53535-53535,54045-54045,54328-54328,55020-55020,55055-55056,", "55555-55555,55576-55576,55600-55600,56737-56738,57294-57294,57665-57665,", "57797-57797,58001-58002,58080-58080,58630-58630,58632-58632,58838-58838,", "59110-59110,59200-59202,60020-60020,60123-60123,60146-60146,60443-60443,", "60642-60642,61532-61532,61613-61613,61900-61900,62078-62078,63331-63331,", "64623-64623,64680-64680,65000-65000,65129-65129,65310-65310, ", "U:7-7,9-9,17-17,19-19,49-49,53-53,67-69,80-80,88-88,111-111,120-120,123-", "123,135-139,158-158,161-162,177-177,427-427,443-443,445-445,497-497,500-", "500,514-515,518-518,520-520,593-593,623-623,626-626,631-631,996-999,1022-", "1023,1025-1030,1433-1434,1645-1646,1701-1701,1718-1719,1812-1813,1900-", "1900,2000-2000,2048-2049,2222-2223,3283-3283,3456-3456,3703-3703,4444-", "4444,4500-4500,5000-5000,5060-5060,5353-5353,5632-5632,9200-9200,10000-", "10000,17185-17185,20031-20031,30718-30718,31337-31337,32768-32769,32771-", "32771,32815-32815,33281-33281,49152-49154,49156-49156,49181-49182,49185-", "49186,49188-49188,49190-49194,49200-49201", NULL); ports_web_services = ports ("T:80-80,443-443", NULL); assert_that (validate_port_range (ports_all_iana_assigned_tcp_2020_02_12), is_equal_to (0)); assert_that (validate_port_range (ports_all_privileged_tcp), is_equal_to (0)); assert_that (validate_port_range (ports_all_privileged_tcp_and_udp), is_equal_to (0)); assert_that (validate_port_range (ports_all_tcp), is_equal_to (0)); assert_that (validate_port_range (ports_openvas_default), is_equal_to (0)); assert_that ( validate_port_range (ports_all_iana_assigned_tcp_and_udp_2020_02_12), is_equal_to (0)); assert_that (validate_port_range (ports_all_tcp_and_nmap_5_51_top_100_udp), is_equal_to (0)); assert_that (validate_port_range (ports_all_tcp_and_nmap_5_51_top_1000_udp), is_equal_to (0)); assert_that ( validate_port_range (ports_nmap_5_51_top_2000_tcp_and_top_100_udp), is_equal_to (0)); assert_that (validate_port_range (ports_web_services), is_equal_to (0)); g_free (ports_all_privileged_tcp); g_free (ports_all_privileged_tcp_and_udp); g_free (ports_all_tcp); g_free (ports_openvas_default); g_free (ports_all_iana_assigned_tcp_and_udp_2020_02_12); g_free (ports_all_tcp_and_nmap_5_51_top_100_udp); g_free (ports_all_tcp_and_nmap_5_51_top_1000_udp); g_free (ports_nmap_5_51_top_2000_tcp_and_top_100_udp); g_free (ports_all_iana_assigned_tcp_2020_02_12); g_free (ports_web_services); } Ensure (networking, port_range_ranges) { const gchar *valid_portrange1; array_t *valid_portrange1_ranges; range_t *valid_portrange1_range1; range_t *valid_portrange1_range2; range_t *valid_portrange1_range3; range_t *valid_portrange1_range4; range_t *valid_portrange1_range5; /* Valid port ranges. U:,T: are empty ranges which are ignored. */ valid_portrange1 = "1,10-13,10-10,T :1-2,U : 10-12,U:,T:"; assert_that (validate_port_range (valid_portrange1), is_equal_to (0)); assert_that (port_range_ranges (NULL), is_null); assert_that (port_range_ranges (valid_portrange1), is_not_null); valid_portrange1_ranges = port_range_ranges (valid_portrange1); assert_that (valid_portrange1_ranges, is_not_null); assert_that (valid_portrange1_ranges->len, is_equal_to (5)); assert_that (valid_portrange1_ranges->len, is_equal_to (5)); valid_portrange1_range1 = (range_t *) g_ptr_array_index (valid_portrange1_ranges, 0); assert_that (valid_portrange1_range1->start, is_equal_to (1)); assert_that (valid_portrange1_range1->end, is_equal_to (1)); assert_that (valid_portrange1_range1->exclude, is_equal_to (0)); assert_that (valid_portrange1_range1->type, is_equal_to (PORT_PROTOCOL_TCP)); valid_portrange1_range2 = (range_t *) g_ptr_array_index (valid_portrange1_ranges, 1); assert_that (valid_portrange1_range2->start, is_equal_to (10)); assert_that (valid_portrange1_range2->end, is_equal_to (13)); assert_that (valid_portrange1_range2->exclude, is_equal_to (0)); assert_that (valid_portrange1_range2->type, is_equal_to (PORT_PROTOCOL_TCP)); valid_portrange1_range3 = (range_t *) g_ptr_array_index (valid_portrange1_ranges, 2); assert_that (valid_portrange1_range3->start, is_equal_to (10)); assert_that (valid_portrange1_range3->end, is_equal_to (10)); assert_that (valid_portrange1_range3->exclude, is_equal_to (0)); assert_that (valid_portrange1_range3->type, is_equal_to (PORT_PROTOCOL_TCP)); valid_portrange1_range4 = (range_t *) g_ptr_array_index (valid_portrange1_ranges, 3); assert_that (valid_portrange1_range4->start, is_equal_to (1)); assert_that (valid_portrange1_range4->end, is_equal_to (2)); assert_that (valid_portrange1_range4->exclude, is_equal_to (0)); assert_that (valid_portrange1_range4->type, is_equal_to (PORT_PROTOCOL_TCP)); valid_portrange1_range5 = (range_t *) g_ptr_array_index (valid_portrange1_ranges, 4); assert_that (valid_portrange1_range5->start, is_equal_to (10)); assert_that (valid_portrange1_range5->end, is_equal_to (12)); assert_that (valid_portrange1_range5->exclude, is_equal_to (0)); assert_that (valid_portrange1_range5->type, is_equal_to (PORT_PROTOCOL_UDP)); } Ensure (networking, port_in_port_ranges) { const gchar *portrange; array_t *portrange_ranges; /* Valid port ranges. U:,T: are empty ranges which are ignored. */ portrange = "1,10-12,10-10,T:1-2,U:10-14,U:,T:"; assert_that (validate_port_range (portrange), is_equal_to (0)); portrange_ranges = port_range_ranges (portrange); assert_that (portrange_ranges, is_not_null); assert_that (portrange_ranges->len, is_equal_to (5)); assert_that (port_in_port_ranges (1, PORT_PROTOCOL_TCP, portrange_ranges), is_true); assert_that (port_in_port_ranges (10, PORT_PROTOCOL_TCP, portrange_ranges), is_true); assert_that (port_in_port_ranges (11, PORT_PROTOCOL_TCP, portrange_ranges), is_true); assert_that (port_in_port_ranges (12, PORT_PROTOCOL_TCP, portrange_ranges), is_true); assert_that (port_in_port_ranges (10, PORT_PROTOCOL_UDP, portrange_ranges), is_true); assert_that (port_in_port_ranges (11, PORT_PROTOCOL_UDP, portrange_ranges), is_true); assert_that (port_in_port_ranges (12, PORT_PROTOCOL_UDP, portrange_ranges), is_true); assert_that (port_in_port_ranges (13, PORT_PROTOCOL_UDP, portrange_ranges), is_true); assert_that (port_in_port_ranges (-1, PORT_PROTOCOL_TCP, portrange_ranges), is_false); assert_that (port_in_port_ranges (0, PORT_PROTOCOL_TCP, portrange_ranges), is_false); assert_that (port_in_port_ranges (90000, PORT_PROTOCOL_TCP, portrange_ranges), is_false); assert_that (port_in_port_ranges (1, PORT_PROTOCOL_UDP, portrange_ranges), is_false); assert_that (port_in_port_ranges (13, PORT_PROTOCOL_TCP, portrange_ranges), is_false); assert_that (port_in_port_ranges (13, PORT_PROTOCOL_TCP, portrange_ranges), is_false); assert_that (port_in_port_ranges (12, PORT_PROTOCOL_OTHER, portrange_ranges), is_false); } /* Test suite. */ Ensure (networking, ip_islocalhost) { /* IPv4 */ struct in_addr addr; struct sockaddr_storage storage; struct sockaddr_in sin; memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; inet_pton (AF_INET, "127.0.0.1", &(addr.s_addr)); sin.sin_addr.s_addr = addr.s_addr; memcpy (&storage, &sin, sizeof (sin)); assert_that (ip_islocalhost (&storage), is_true); inet_pton (AF_INET, "0.0.0.0", &(addr.s_addr)); sin.sin_addr.s_addr = addr.s_addr; memcpy (&storage, &sin, sizeof (sin)); assert_that (ip_islocalhost (&storage), is_true); inet_pton (AF_INET, "127.100.5.99", &(addr.s_addr)); sin.sin_addr.s_addr = addr.s_addr; memcpy (&storage, &sin, sizeof (sin)); assert_that (ip_islocalhost (&storage), is_true); /* dependent on local environment */ // inet_pton (AF_INET, , &(addr.s_addr)); // sin.sin_addr.s_addr = addr.s_addr; // memcpy (&storage, &sin, sizeof (sin)); // assert_that (ip_islocalhost (&storage), is_true); /* example.com */ inet_pton (AF_INET, "93.184.216.34", &(addr.s_addr)); sin.sin_addr.s_addr = addr.s_addr; memcpy (&storage, &sin, sizeof (sin)); assert_that (ip_islocalhost (&storage), is_false); /* IPv6 */ struct in6_addr addr_6; struct sockaddr_in6 sin6; memset (&sin6, 0, sizeof (struct sockaddr_in6)); sin6.sin6_family = AF_INET6; inet_pton (AF_INET6, "::FFFF:127.0.0.1", &(addr_6)); sin6.sin6_addr = addr_6; memcpy (&storage, &sin6, sizeof (sin6)); assert_that (ip_islocalhost (&storage), is_true); inet_pton (AF_INET6, "::FFFF:0.0.0.0", &(addr_6)); sin6.sin6_addr = addr_6; memcpy (&storage, &sin6, sizeof (sin6)); assert_that (ip_islocalhost (&storage), is_true); inet_pton (AF_INET6, "::FFFF:127.100.5.99", &(addr_6)); sin6.sin6_addr = addr_6; memcpy (&storage, &sin6, sizeof (sin6)); assert_that (ip_islocalhost (&storage), is_true); /* loopback address */ inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &(addr_6)); sin6.sin6_addr = addr_6; memcpy (&storage, &sin6, sizeof (sin6)); assert_that (ip_islocalhost (&storage), is_true); /* dependent on local environment */ // inet_pton (AF_INET6, , &(addr_6)); // sin6.sin6_addr = addr_6; // memcpy (&storage, &sin6, sizeof (sin6)); // assert_that (ip_islocalhost (&storage), is_true); /* example.com */ inet_pton (AF_INET6, "2606:2800:220:1:248:1893:25c8:1946", &(addr_6)); sin6.sin6_addr = addr_6; memcpy (&storage, &sin6, sizeof (sin6)); assert_that (ip_islocalhost (&storage), is_false); } __attribute__ ((weak)) GIOChannel * __real_g_io_channel_new_file (const char *filename, const char *mode, GError **error); gboolean g_g_io_channel_new_file_use_real = TRUE; GIOChannel * __wrap_g_io_channel_new_file (const char *filename, const char *mode, GError **error); GIOChannel * __wrap_g_io_channel_new_file (const char *filename, const char *mode, GError **error) { if (g_g_io_channel_new_file_use_real) return __real_g_io_channel_new_file (filename, mode, error); return (GIOChannel *) mock (filename, mode, error); } __attribute__ ((weak)) GIOStatus __real_g_io_channel_shutdown (GIOChannel *channel, gboolean flush, GError **err); gboolean g_g_io_channel_shutdown_use_real = TRUE; GIOStatus __wrap_g_io_channel_shutdown (GIOChannel *channel, gboolean flush, GError **err); GIOStatus __wrap_g_io_channel_shutdown (GIOChannel *channel, gboolean flush, GError **err) { if (g_g_io_channel_shutdown_use_real) return __real_g_io_channel_shutdown (channel, flush, err); return (GIOStatus) mock (channel, flush, err); } Ensure (networking, get_routes) { int status; int ret; GError *err = NULL; GIOChannel *file_channel; GSList *list = NULL; int list_len; /* Content for mocked file. */ gchar *procnetroute_testfile = "\nIface\tDestination\tGateway " "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT " " " "\nenp0s9\t00000000\t01B2A8C0\t0003\t0\t0\t100\t00000000\t0\t0\t0 " " " "\nenp0s8\t0038A8C0\t00000000\t0001\t0\t0\t0\t00FFFFFF\t0\t0\t0 " " " "\nenp0s9\t00B2A8C0\t00000000\t0001\t0\t0\t100\t00FFFFFF\t0\t0\t0 " " \n"; /* Create mock file. */ file_channel = g_io_channel_new_file ("./myfile", "w+", NULL); if (!file_channel) g_warning ("Not my channel"); g_io_channel_write_chars (file_channel, procnetroute_testfile, -1, NULL, NULL); g_io_channel_seek_position (file_channel, 0, G_SEEK_SET, NULL); /* Test get_routes with mocked "/proc/net/route". */ g_g_io_channel_new_file_use_real = false; g_g_io_channel_shutdown_use_real = false; expect (__wrap_g_io_channel_new_file, when (filename, is_equal_to_string ("/proc/net/route")), will_return (file_channel)); expect (__wrap_g_io_channel_shutdown, will_return (G_IO_STATUS_NORMAL)); list = get_routes (); list_len = g_slist_length (list); assert_that (list, is_not_null); assert_that (list_len, is_equal_to (3)); g_g_io_channel_new_file_use_real = true; g_g_io_channel_shutdown_use_real = true; /* Close channel and delete mock file. */ status = g_io_channel_shutdown (file_channel, TRUE, &err); if ((G_IO_STATUS_NORMAL != status) || err) g_warning ("%s: Could not shutdown channel.", __func__); ret = unlink ("./myfile"); if (0 != ret) g_warning ("%s: Could not delete file \"./myfile\");", __func__); } Ensure (networking, gvm_routethrough_v4) { struct in_addr dst; struct sockaddr_storage storage_src; struct sockaddr_storage storage_dst; struct sockaddr_in sin_src; struct sockaddr_in sin_dst; struct sockaddr_in sin_always_empty; memset (&sin_src, 0, sizeof (struct sockaddr_in)); memset (&sin_dst, 0, sizeof (struct sockaddr_in)); memset (&sin_always_empty, 0, sizeof (struct sockaddr_in)); sin_src.sin_family = AF_INET; sin_dst.sin_family = AF_INET; gchar *interface = NULL; /* No destination address. */ interface = gvm_routethrough (NULL, &storage_src); assert_that (interface, is_null); /* Destination address localhost and no source address. */ inet_pton (AF_INET, "127.0.0.1", &(dst.s_addr)); sin_dst.sin_addr.s_addr = dst.s_addr; memcpy (&storage_dst, &sin_dst, sizeof (sin_dst)); interface = gvm_routethrough (&storage_dst, NULL); assert_that (interface, is_not_null); /* Dependent on local environment. */ // assert_that (interface, is_equal_to_string ("lo")); /* Destination address not localhost and no source address. */ inet_pton (AF_INET, "93.184.216.34", &(dst.s_addr)); // example.com sin_dst.sin_addr.s_addr = dst.s_addr; memcpy (&storage_dst, &sin_dst, sizeof (sin_dst)); interface = gvm_routethrough (&storage_dst, NULL); assert_that (interface, is_not_null); /* Dependent on local environment. */ // assert_that (interface, is_equal_to_string ("enp0s9")); /* Destination address localhost and source address */ inet_pton (AF_INET, "127.0.0.1", &(dst.s_addr)); sin_dst.sin_addr.s_addr = dst.s_addr; memcpy (&storage_dst, &sin_dst, sizeof (sin_dst)); interface = gvm_routethrough (&storage_dst, &storage_src); assert_that (interface, is_not_null); assert_that (((struct sockaddr_in *) (&storage_src))->sin_addr.s_addr == htonl (0x7F000001)); /* Dependent on local environment. */ // assert_that (interface, is_equal_to_string ("lo")); /* Dst address not localhost and src address */ inet_pton (AF_INET, "93.184.216.34", &(dst.s_addr)); sin_dst.sin_addr.s_addr = dst.s_addr; memcpy (&storage_dst, &sin_dst, sizeof (sin_dst)); memcpy (&storage_src, &sin_always_empty, sizeof (struct sockaddr_in)); interface = gvm_routethrough (&storage_dst, &storage_src); assert_that (interface, is_not_null); assert_that (((struct sockaddr_in *) (&storage_src))->sin_addr.s_addr != htonl (0x7F000001)); /* Dependent on local environment. */ // assert_that (((struct sockaddr_in *) (&storage_src))->sin_addr.s_addr != // 0); assert_that (interface, is_equal_to_string ("enp0s9")); } Ensure (networking, gvm_source_addr) { struct in_addr src; /* global source address not set */ gvm_source_iface_init (NULL); gvm_source_addr (&src); assert_that ((src.s_addr == INADDR_ANY)); /* global source address */ gvm_source_iface_init ("lo"); gvm_source_addr (&src); assert_that ((src.s_addr != INADDR_ANY)); } static TestSuite * gvm_routethough () { TestSuite *suite = create_test_suite (); add_test_with_context (suite, networking, ip_islocalhost); add_test_with_context (suite, networking, get_routes); add_test_with_context (suite, networking, gvm_routethrough_v4); return suite; } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_suite (suite, gvm_routethough ()); add_test_with_context (suite, networking, gvm_source_addr); add_test_with_context (suite, networking, validate_port_range); add_test_with_context (suite, networking, port_range_ranges); add_test_with_context (suite, networking, port_in_port_ranges); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/nvti.c000066400000000000000000001350371477470532200154570ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ // One of the files of gvm-libs needs to specify the meta data // for the doxygen documentation. /** * \mainpage * * \section Introduction * \verbinclude README.md * * \section Installation * \verbinclude INSTALL.md * * \section copying License * \verbinclude COPYING */ /** * @file * @brief Implementation of API to handle NVT Info datasets * * This file contains all methods to handle NVT Information datasets * (nvti_t). * * The module consequently uses glib datatypes and api for memory * management etc. */ /* For strptime in time.h. */ #undef _XOPEN_SOURCE #define _XOPEN_SOURCE #include "nvti.h" #include // for sscanf #include // for strcmp #include // for strcasecmp #include // for strptime #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /* VT references */ /** * @brief The structure for a cross reference of a VT. * * The elements of this structure should only be accessed by the * respective functions. */ typedef struct vtref { gchar *type; ///< Reference type ("cve", "bid", ...) gchar *ref_id; ///< Actual reference ID ("CVE-2018-1234", etc) gchar *ref_text; ///< Optional additional text } vtref_t; /** * @brief Create a new vtref structure filled with the given values. * * @param type The type to be set. * * @param ref_id The actual reference to be set. * * @param ref_text The optional text accompanying a reference. * * @return A vtref structure which needs to be * released using @ref vtref_free . */ vtref_t * vtref_new (const gchar *type, const gchar *ref_id, const gchar *ref_text) { vtref_t *ref = g_malloc0 (sizeof (vtref_t)); if (type) ref->type = g_strdup (type); if (ref_id) ref->ref_id = g_strdup (ref_id); if (ref_text) ref->ref_text = g_strdup (ref_text); return ref; } /** * @brief Free memory of a vtref structure. * * @param ref The structure to be freed. */ void vtref_free (vtref_t *ref) { if (!ref) return; g_free (ref->type); g_free (ref->ref_id); g_free (ref->ref_text); g_free (ref); } /** * @brief Get the type of a reference. * * @param r The VT Reference structure of which the type should * be returned. * * @return The type string. Don't free this. */ const gchar * vtref_type (const vtref_t *r) { return r ? r->type : NULL; } /** * @brief Get the id of a reference. * * @param r The VT Reference structure of which the id should * be returned. * * @return The id string. Don't free this. */ const gchar * vtref_id (const vtref_t *r) { return r ? r->ref_id : NULL; } /** * @brief Get the text of a reference. * * @param r The VT Reference structure of which the id should * be returned. * * @return The id string. Don't free this. */ const gchar * vtref_text (const vtref_t *r) { return r ? r->ref_text : NULL; } /* VT severities */ /** * @brief The structure for a severity of a VT. * * VTs can have one or several severities. */ typedef struct vtseverity { gchar *type; ///< Severity type ("cvss_base_v2", ...) gchar *origin; ///< Optional: Where does the severity come from ///< ("CVE-2018-1234", "Greenbone Research") int date; ///< Timestamp in seconds since epoch, defaults to VT creation date. double score; ///< The score derived from the value in range [0.0-10.0] gchar *value; ///< The value which corresponds to the type. } vtseverity_t; /** * @brief Create a new vtseverity structure filled with the given values. * * @param[in] type The severity type to be set. * @param[in] origin The origin reference to be set, can be NULL. * @param[in] date The date to be set. * @param[in] score The score to be set. * @param[in] value The value corresponding to the type. * * @return A vtref structure which needs to be * released using @ref vtref_free . */ vtseverity_t * vtseverity_new (const gchar *type, const gchar *origin, int date, double score, const gchar *value) { vtseverity_t *s = g_malloc0 (sizeof (vtseverity_t)); if (type) s->type = g_strdup (type); if (origin) s->origin = g_strdup (origin); s->date = date; s->score = score; if (value) s->value = g_strdup (value); return s; } /** * @brief Free memory of a vtseverity structure. * * @param s The structure to be freed. */ void vtseverity_free (vtseverity_t *s) { if (!s) return; g_free (s->type); g_free (s->origin); g_free (s->value); g_free (s); } /** * @brief Get the type of a severity. * * @param s The VT Severity structure of which the type should * be returned. * * @return The type string. Don't free this. */ const gchar * vtseverity_type (const vtseverity_t *s) { return s ? s->type : NULL; } /** * @brief Get the origin of a severity. * * @param s The VT Severity structure of which the origin should * be returned. * * @return The origin string. Don't free this. */ const gchar * vtseverity_origin (const vtseverity_t *s) { return s ? s->origin : NULL; } /** * @brief Get the value of a severity. * * @param s The VT Severity structure of which the value should * be returned. * * @return The value string. Don't free this. */ const gchar * vtseverity_value (const vtseverity_t *s) { return s ? s->value : NULL; } /** * @brief Get the date of a severity. * * @param s The VT Severity structure of which the date should * be returned. * * @return The date. */ int vtseverity_date (const vtseverity_t *s) { return s->date; } /** * @brief Get the score of a severity. * * @param s The VT Severity structure of which the score should * be returned. * * @return The score. */ double vtseverity_score (const vtseverity_t *s) { return s->score; } /* Support function for timestamps */ /** * @brief Try convert an NVT tag time string into epoch time * or return 0 upon parse errors. * * @param[in] str_time Time stamp as string in one of the forms used in NVTs. * * @return Time as seconds since the epoch. */ static time_t parse_nvt_timestamp (const gchar *str_time) { time_t epoch_time; int offset; struct tm tm; if (strcmp ((char *) str_time, "") == 0) return 0; /* Parse the time. */ /* 2011-08-09 08:20:34 +0200 (Tue, 09 Aug 2011) */ memset (&tm, 0, sizeof (struct tm)); if (strptime ((char *) str_time, "%F %T %z", &tm) == NULL) { memset (&tm, 0, sizeof (struct tm)); if (strptime ((char *) str_time, "%a %b %d %T %Y %z", &tm) == NULL) { g_warning ("%s: Failed to parse time: %s", __func__, str_time); return 0; } } epoch_time = mktime (&tm); if (epoch_time == -1) { g_warning ("%s: Failed to make time: %s", __func__, str_time); return 0; } /* Get the timezone offset from the str_time. */ if ((sscanf ((char *) str_time, "%*u-%*u-%*u %*u:%*u:%*u %d%*[^]]", &offset) != 1) && (sscanf ((char *) str_time, "%*s %*s %*s %*u:%*u:%*u %*u %d%*[^]]", &offset) != 1)) { g_warning ("%s: Failed to parse timezone offset: %s", __func__, str_time); return 0; } /* Use the offset to convert to UTC. */ if (offset < 0) { epoch_time += ((-offset) / 100) * 60 * 60; epoch_time += ((-offset) % 100) * 60; } else if (offset > 0) { epoch_time -= (offset / 100) * 60 * 60; epoch_time -= (offset % 100) * 60; } return epoch_time; } /* VT Information */ /** * @brief The structure of a information record that corresponds to a NVT. */ typedef struct nvti { gchar *oid; /**< @brief Object ID */ gchar *name; /**< @brief The name */ gchar *summary; /**< @brief The summary */ gchar *insight; /**< @brief The insight */ gchar *affected; /**< @brief Affected systems */ gchar *impact; /**< @brief Impact of vulnerability */ time_t creation_time; /**< @brief Time of creation, seconds since epoch */ time_t modification_time; /**< @brief Time of last change, sec. since epoch */ gchar *solution; /**< @brief The solution */ gchar *solution_type; /**< @brief The solution type */ gchar *solution_method; /**< @brief The solution method */ gchar *tag; /**< @brief List of tags attached to this NVT */ gchar *cvss_base; /**< @brief CVSS base score for this NVT. */ gchar *dependencies; /**< @brief List of dependencies of this NVT */ gchar *required_keys; /**< @brief List of required KB keys of this NVT */ gchar *mandatory_keys; /**< @brief List of mandatory KB keys of this NVT */ gchar *excluded_keys; /**< @brief List of excluded KB keys of this NVT */ gchar *required_ports; /**< @brief List of required ports of this NVT */ gchar *required_udp_ports; /**< @brief List of required UDP ports of this NVT*/ gchar *detection; /**< @brief Detection description */ gchar *qod_type; /**< @brief Quality of detection type */ gchar *qod; /**< @brief Quality of detection */ GSList *refs; /**< @brief Collection of VT references */ GSList *severities; /**< @brief Collection of VT severities */ GSList *prefs; /**< @brief Collection of NVT preferences */ // The following are not settled yet. gint category; /**< @brief The category, this NVT belongs to */ gchar *family; /**< @brief Family the NVT belongs to */ } nvti_t; /** * @brief Add a reference to the VT Info. * * @param vt The VT Info structure. * * @param ref The VT reference to add. * * @return 0 for success. Anything else indicates an error. */ int nvti_add_vtref (nvti_t *vt, vtref_t *ref) { if (!vt) return -1; vt->refs = g_slist_append (vt->refs, ref); return 0; } /** * @brief Add a severity to the VT Info. * * @param vt The VT Info structure. * @param s The VT severity to add. * * @return 0 for success. Anything else indicates an error. */ int nvti_add_vtseverity (nvti_t *vt, vtseverity_t *s) { if (!vt) return -1; vt->severities = g_slist_append (vt->severities, s); return 0; } /* VT preferences */ /** * @brief The structure for a preference of a NVT. */ typedef struct nvtpref { int id; ///< Preference ID gchar *type; ///< Preference type gchar *name; ///< Name of the preference gchar *dflt; ///< Default value of the preference } nvtpref_t; /** * @brief Create a new nvtpref structure filled with the given values. * * @param id The ID to be set. * * @param name The name to be set. A copy will created of this. * * @param type The type to be set. A copy will created of this. * * @param dflt The default to be set. A copy will created of this. * * @return An nvtpref structure which needs to be * released using @ref nvtpref_free . */ nvtpref_t * nvtpref_new (int id, const gchar *name, const gchar *type, const gchar *dflt) { nvtpref_t *np = g_malloc0 (sizeof (nvtpref_t)); np->id = id; if (name) np->name = g_strdup (name); if (type) np->type = g_strdup (type); if (dflt) np->dflt = g_strdup (dflt); return np; } /** * @brief Free memory of a nvtpref structure. * * @param np The structure to be freed. */ void nvtpref_free (nvtpref_t *np) { if (!np) return; g_free (np->name); g_free (np->type); g_free (np->dflt); g_free (np); } /** * @brief Get the ID of a NVT Preference. * * @param np The NVT Pref structure of which the Name should * be returned. * * @return The ID value. */ int nvtpref_id (const nvtpref_t *np) { return np ? np->id : -1; } /** * @brief Get the Name of a NVT Preference. * * @param np The NVT Pref structure of which the Name should * be returned. * * @return The name string. Don't free this. */ gchar * nvtpref_name (const nvtpref_t *np) { return np ? np->name : NULL; } /** * @brief Get the Type of a NVT Preference. * * @param np The NVT Pref structure of which the Type should * be returned. * * @return The type string. Don't free this. */ gchar * nvtpref_type (const nvtpref_t *np) { return np ? np->type : NULL; } /** * @brief Get the Default of a NVT Preference. * * @param np The NVT Pref structure of which the Default should * be returned. * * @return The default string. Don't free this. */ gchar * nvtpref_default (const nvtpref_t *np) { return np ? np->dflt : NULL; } /** * @brief Create a new (empty) nvti structure. * * @return An empty nvti structure which needs to be * released using @ref nvti_free . * The whole struct is initialized with 0's. */ nvti_t * nvti_new (void) { return (nvti_t *) g_malloc0 (sizeof (nvti_t)); } /** * @brief Free memory of a nvti structure. * * @param n The structure to be freed. */ void nvti_free (nvti_t *n) { if (!n) return; g_free (n->oid); g_free (n->name); g_free (n->summary); g_free (n->insight); g_free (n->affected); g_free (n->impact); g_free (n->solution); g_free (n->solution_type); g_free (n->solution_method); g_free (n->tag); g_free (n->cvss_base); g_free (n->dependencies); g_free (n->required_keys); g_free (n->mandatory_keys); g_free (n->excluded_keys); g_free (n->required_ports); g_free (n->required_udp_ports); g_free (n->detection); g_free (n->qod_type); g_free (n->qod); g_free (n->family); g_slist_free_full (n->refs, (void (*) (void *)) vtref_free); g_slist_free_full (n->severities, (void (*) (void *)) vtseverity_free); g_slist_free_full (n->prefs, (void (*) (void *)) nvtpref_free); g_free (n); } /** * @brief Get the OID string. * * @param n The NVT Info structure of which the OID should * be returned. * * @return The OID string. Don't free this. */ gchar * nvti_oid (const nvti_t *n) { return n ? n->oid : NULL; } /** * @brief Get the name. * * @param n The NVT Info structure of which the name should * be returned. * * @return The name string. Don't free this. */ gchar * nvti_name (const nvti_t *n) { return n ? n->name : NULL; } /** * @brief Get the summary. * * @param n The NVT Info structure of which the summary should * be returned. * * @return The summary string. Don't free this. */ gchar * nvti_summary (const nvti_t *n) { return n ? n->summary : NULL; } /** * @brief Get the text about insight. * * @param n The NVT Info structure of which the insight description should * be returned. * * @return The insight string. Don't free this. */ gchar * nvti_insight (const nvti_t *n) { return n ? n->insight : NULL; } /** * @brief Get the text about affected systems. * * @param n The NVT Info structure of which the affected description should * be returned. * * @return The affected string. Don't free this. */ gchar * nvti_affected (const nvti_t *n) { return n ? n->affected : NULL; } /** * @brief Get the text about impact. * * @param n The NVT Info structure of which the impact description should * be returned. * * @return The impact string. Don't free this. */ gchar * nvti_impact (const nvti_t *n) { return n ? n->impact : NULL; } /** * @brief Get the creation time. * * @param n The NVT Info structure of which the creation time should * be returned. * * @return The creation time in seconds since epoch. */ time_t nvti_creation_time (const nvti_t *n) { return n ? n->creation_time : 0; } /** * @brief Get the modification time. * * @param n The NVT Info structure of which the modification time should * be returned. * * @return The modification time in seconds since epoch. */ time_t nvti_modification_time (const nvti_t *n) { return n ? n->modification_time : 0; } /** * @brief Get the number of references of the NVT. * * @param n The NVT Info structure. * * @return The number of references. */ guint nvti_vtref_len (const nvti_t *n) { return n ? g_slist_length (n->refs) : 0; } /** * @brief Get the n'th reference of the NVT. * * @param n The NVT Info structure. * * @param p The position of the reference to return. * * @return The reference. NULL on error. */ vtref_t * nvti_vtref (const nvti_t *n, guint p) { return n ? g_slist_nth_data (n->refs, p) : NULL; } /** * @brief Get references as string. * * @param n The NVT Info structure of which the references should * be returned. * * @param type Optional type to collect. If NULL, all types are collected. * * @param exclude_types Optional CSC list of types to exclude from collection. * If NULL, no types are excluded. * * @param use_types If 0, then a simple comma separated list will be returned. * If not 0, then for each reference the syntax "type:id" is * applied. * * @return The references as string. This needs to be free'd. * The format of the string depends on the "use_types" parameter. * If use_types is 0 it is a comma-separated list "id, id, id" * is returned. * If use_types is not 0 a comma-separated list like * "type:id, type:id, type:id" is returned. * NULL is returned in case n is NULL. */ gchar * nvti_refs (const nvti_t *n, const gchar *type, const gchar *exclude_types, guint use_types) { gchar *refs, *refs2, **exclude_item; vtref_t *ref; guint i, exclude; gchar **exclude_split; if (!n) return NULL; refs = NULL; refs2 = NULL; exclude = 0; if (exclude_types && exclude_types[0]) exclude_split = g_strsplit (exclude_types, ",", 0); else exclude_split = NULL; for (i = 0; i < g_slist_length (n->refs); i++) { ref = g_slist_nth_data (n->refs, i); if (type && strcasecmp (ref->type, type) != 0) continue; if (exclude_split) { exclude = 0; for (exclude_item = exclude_split; *exclude_item; exclude_item++) { if (strcasecmp (g_strstrip (*exclude_item), ref->type) == 0) { exclude = 1; break; } } } if (!exclude) { if (use_types) { if (refs) refs2 = g_strdup_printf ("%s, %s:%s", refs, ref->type, ref->ref_id); else refs2 = g_strdup_printf ("%s:%s", ref->type, ref->ref_id); } else { if (refs) refs2 = g_strdup_printf ("%s, %s", refs, ref->ref_id); else refs2 = g_strdup_printf ("%s", ref->ref_id); } g_free (refs); refs = refs2; } } g_strfreev (exclude_split); return refs; } /** * @brief Get the number of severities of the NVT. * * @param n The NVT Info structure. * * @return The number of severities. */ guint nvti_vtseverities_len (const nvti_t *n) { return n ? g_slist_length (n->severities) : 0; } /** * @brief Get the n'th reference of the NVT. * * @param n The NVT Info structure. * * @param p The position of the reference to return. * * @return The reference. NULL on error. */ vtseverity_t * nvti_vtseverity (const nvti_t *n, guint p) { return n ? g_slist_nth_data (n->severities, p) : NULL; } /** * @brief Get the maximum severity score * * @param n The NVT Info structure. * * @return The severity score, -1 indicates an error. */ double nvti_severity_score (const nvti_t *n) { unsigned int i; double score = -1.0; for (i = 0; i < nvti_vtseverities_len (n); i++) { vtseverity_t *severity; severity = nvti_vtseverity (n, i); if (vtseverity_score (severity) > score) score = vtseverity_score (severity); } return score; } /** * @brief Get the severity score * * Extended severity was introduced but still not all * vts are using it. Therefore it must be checked if * we can calculate the score from the severity_vector tag * or if we have to calculate it from the deprecated * cvss_base_vector tag. * * @param n The NVT Info structure. * * @return The severity_vector if present or cvss_base_vector otherwise. * NULL indicates an error. Must be free()'d by the caller. */ gchar * nvti_severity_vector_from_tag (const nvti_t *n) { gchar *vector; /* Currently, only one severity_vector can be stored as tag. * Therfore we just check this one. */ vector = nvti_get_tag (n, "severity_vector"); if (vector) return vector; vector = nvti_get_tag (n, "cvss_base_vector"); return vector; } /** * @brief Get the solution. * * @param n The NVT Info structure of which the solution should * be returned. * * @return The solution string. Don't free this. */ gchar * nvti_solution (const nvti_t *n) { return n ? n->solution : NULL; } /** * @brief Get the solution type. * * @param n The NVT Info structure of which the solution type should * be returned. * * @return The solution type string. Don't free this. */ gchar * nvti_solution_type (const nvti_t *n) { return n ? n->solution_type : NULL; } /** * @brief Get the solution method. * * @param n The NVT Info structure of which the solution method should * be returned. * * @return The solution method string. Don't free this. */ gchar * nvti_solution_method (const nvti_t *n) { return n ? n->solution_method : NULL; } /** * @brief Get the tags. * * @param n The NVT Info structure of which the tags should * be returned. * * @return The tags string. Don't free this. */ gchar * nvti_tag (const nvti_t *n) { return n ? n->tag : NULL; } /** * @brief Get a tag value by a tag name. * * @param n The NVT Info structure from where to search for the tag name. * * @param name The name of the tag for which to return the value. * * @return The tag value string as a copy or NULL if not found. * Needs to be free'd. */ gchar * nvti_get_tag (const nvti_t *n, const gchar *name) { gchar **split, **point; if (!n || n->tag == NULL || !name) return NULL; split = g_strsplit (n->tag, "|", 0); point = split; while (*point) { if ((strlen (*point) > strlen (name)) && (strncmp (*point, name, strlen (name)) == 0) && ((*point)[strlen (name)] == '=')) { gchar *ret; ret = g_strdup (*point + strlen (name) + 1); g_strfreev (split); return ret; } point++; } g_strfreev (split); return NULL; } /** * @brief Get the CVSS base. * * @param n The NVT Info structure of which the CVSS base should * be returned. * * @return The cvss_base string. Don't free this. */ gchar * nvti_cvss_base (const nvti_t *n) { return n ? n->cvss_base : NULL; } /** * @brief Get the dependencies list. * * @param n The NVT Info structure of which the name should * be returned. * * @return The dependencies string. Don't free this. */ gchar * nvti_dependencies (const nvti_t *n) { return n ? n->dependencies : NULL; } /** * @brief Get the required keys list. * * @param n The NVT Info structure of which the name should * be returned. * * @return The required keys string. Don't free this. */ gchar * nvti_required_keys (const nvti_t *n) { return n ? n->required_keys : NULL; } /** * @brief Get the mandatory keys list. * * @param n The NVT Info structure of which the name should * be returned. * * @return The mandatory keys string. Don't free this. */ gchar * nvti_mandatory_keys (const nvti_t *n) { return n ? n->mandatory_keys : NULL; } /** * @brief Get the excluded keys list. * * @param n The NVT Info structure of which the name should * be returned. * * @return The excluded keys string. Don't free this. */ gchar * nvti_excluded_keys (const nvti_t *n) { return n ? n->excluded_keys : NULL; } /** * @brief Get the required ports list. * * @param n The NVT Info structure of which the name should * be returned. * * @return The required ports string. Don't free this. */ gchar * nvti_required_ports (const nvti_t *n) { return n ? n->required_ports : NULL; } /** * @brief Get the required udp ports list. * * @param n The NVT Info structure of which the name should * be returned. * * @return The required udp ports string. Don't free this. */ gchar * nvti_required_udp_ports (const nvti_t *n) { return n ? n->required_udp_ports : NULL; } /** * @brief Get the text about detection. * * @param n The NVT Info structure of which the detection should * be returned. * * @return The detection string. Don't free this. */ gchar * nvti_detection (const nvti_t *n) { return n ? n->detection : NULL; } /** * @brief Get the QoD type. * * @param n The NVT Info structure of which the QoD type should * be returned. * * @return The QoD type as string. Don't free this. */ gchar * nvti_qod_type (const nvti_t *n) { return n ? n->qod_type : NULL; } /** * @brief Get the QoD. * * @param n The NVT Info structure of which the QoD should * be returned. * * @return The QoD as string. Don't free this. */ gchar * nvti_qod (const nvti_t *n) { return n ? n->qod : NULL; } /** * @brief Get the family name. * * @param n The NVT Info structure of which the name should * be returned. * * @return The family name string. Don't free this. */ gchar * nvti_family (const nvti_t *n) { return n ? n->family : NULL; } /** * @brief Get the number of preferences of the NVT. * * @param n The NVT Info structure. * * @return The number of preferences. */ guint nvti_pref_len (const nvti_t *n) { return n ? g_slist_length (n->prefs) : 0; } /** * @brief Get the n'th preferences of the NVT. * * @param n The NVT Info structure. * * @param p The position of the preference to return. * * @return The preference. NULL on error. */ const nvtpref_t * nvti_pref (const nvti_t *n, guint p) { return n ? g_slist_nth_data (n->prefs, p) : NULL; } /** * @brief Get the category for this NVT. * * @param n The NVT Info structure of which the category should be returned. * * @return The category integer code. A value <= 0 indicates it is not set. */ gint nvti_category (const nvti_t *n) { return n ? n->category : -1; } /** * @brief Set the OID of a NVT Info. * * @param n The NVT Info structure. * * @param oid The OID to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_oid (nvti_t *n, const gchar *oid) { if (!n) return -1; g_free (n->oid); n->oid = g_strdup (oid); return 0; } /** * @brief Set the name of a NVT. * * @param n The NVT Info structure. * * @param name The name to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_name (nvti_t *n, const gchar *name) { if (!n) return -1; g_free (n->name); n->name = g_strdup (name); return 0; } /** * @brief Set the name of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param name The name to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_name (nvti_t *n, gchar *name) { if (!n) return -1; g_free (n->name); n->name = name; return 0; } /** * @brief Set the summary of a NVT. * * @param n The NVT Info structure. * * @param summary The summary to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_summary (nvti_t *n, const gchar *summary) { if (!n) return -1; g_free (n->summary); n->summary = g_strdup (summary); return 0; } /** * @brief Set the summary of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param summary The summary to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_summary (nvti_t *n, gchar *summary) { if (!n) return -1; g_free (n->summary); n->summary = summary; return 0; } /** * @brief Set the insight text of a NVT. * * @param n The NVT Info structure. * * @param insight The insight text to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_insight (nvti_t *n, const gchar *insight) { if (!n) return -1; g_free (n->insight); n->insight = g_strdup (insight); return 0; } /** * @brief Set the insight text of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param insight The insight text to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_insight (nvti_t *n, gchar *insight) { if (!n) return -1; g_free (n->insight); n->insight = insight; return 0; } /** * @brief Set the affected text of a NVT. * * @param n The NVT Info structure. * * @param affected The affected text to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_affected (nvti_t *n, const gchar *affected) { if (!n) return -1; g_free (n->affected); n->affected = g_strdup (affected); return 0; } /** * @brief Set the affected text of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param affected The affected text to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_affected (nvti_t *n, gchar *affected) { if (!n) return -1; g_free (n->affected); n->affected = affected; return 0; } /** * @brief Set the impact text of a NVT. * * @param n The NVT Info structure. * * @param impact The impact text to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_impact (nvti_t *n, const gchar *impact) { if (!n) return -1; g_free (n->impact); n->impact = g_strdup (impact); return 0; } /** * @brief Set the impact text of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param impact The impact text to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_impact (nvti_t *n, gchar *impact) { if (!n) return -1; g_free (n->impact); n->impact = impact; return 0; } /** * @brief Set the creation time of a NVT. * * @param n The NVT Info structure. * * @param creation_time The creation time to set. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_creation_time (nvti_t *n, const time_t creation_time) { if (!n) return -1; n->creation_time = creation_time; return 0; } /** * @brief Set the modification time of a NVT. * * @param n The NVT Info structure. * * @param modification_time The modification time to set. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_modification_time (nvti_t *n, const time_t modification_time) { if (!n) return -1; n->modification_time = modification_time; return 0; } /** * @brief Set the solution of a NVT. * * @param n The NVT Info structure. * * @param solution The solution to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_solution (nvti_t *n, const gchar *solution) { if (!n) return -1; g_free (n->solution); n->solution = g_strdup (solution); return 0; } /** * @brief Set the solution of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param solution The solution to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_solution (nvti_t *n, gchar *solution) { if (!n) return -1; g_free (n->solution); n->solution = solution; return 0; } /** * @brief Set the solution type of a NVT. * * @param n The NVT Info structure. * * @param solution_type The solution type to set. A copy will be created * from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_solution_type (nvti_t *n, const gchar *solution_type) { if (!n) return -1; g_free (n->solution_type); n->solution_type = g_strdup (solution_type); return 0; } /** * @brief Set the solution method of a NVT. * * @param n The NVT Info structure. * * @param solution_method The solution method to set. A copy will be created * from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_solution_method (nvti_t *n, const gchar *solution_method) { if (!n) return -1; g_free (n->solution_method); n->solution_method = g_strdup (solution_method); return 0; } /** * @brief Add a tag to the NVT tags. * The tag names "severity_date", "last_modification" and * "creation_date" are treated special: The value is expected * to be a timestamp and it is being converted to seconds * since epoch before added as a tag value. * The tag name "cvss_base" will be ignored and not added. * * @param n The NVT Info structure. * * @param name The tag name. A copy will be created from this. * * @param value The tag value. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_add_tag (nvti_t *n, const gchar *name, const gchar *value) { gchar *newvalue = NULL; if (!n) return -1; if (!name || !name[0]) return -2; if (!value || !value[0]) return -3; if (!strcmp (name, "last_modification")) { nvti_set_modification_time (n, parse_nvt_timestamp (value)); newvalue = g_strdup_printf ("%i", (int) nvti_modification_time (n)); } else if (!strcmp (name, "creation_date")) { nvti_set_creation_time (n, parse_nvt_timestamp (value)); newvalue = g_strdup_printf ("%i", (int) nvti_creation_time (n)); } else if (!strcmp (name, "severity_date")) newvalue = g_strdup_printf ("%i", (int) parse_nvt_timestamp (value)); else if (!strcmp (name, "cvss_base")) { /* Ignore this tag because it is not being used. * It is redundant with the tag cvss_base_vector from which * it is computed. * Once GOS 6 and GVM 11 are retired, all set_tag commands * in the NASL scripts can be removed that set "cvss_base". * Once this happened this exception can be removed from the code. */ return 0; } if (n->tag) { gchar *newtag; newtag = g_strconcat (n->tag, "|", name, "=", newvalue ? newvalue : value, NULL); g_free (n->tag); n->tag = newtag; } else n->tag = g_strconcat (name, "=", newvalue ? newvalue : value, NULL); g_free (newvalue); return 0; } /** * @brief Set the tags of a NVT. * * @param n The NVT Info structure. * * @param tag The tags to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_tag (nvti_t *n, const gchar *tag) { if (!n) return -1; g_free (n->tag); if (tag && tag[0]) n->tag = g_strdup (tag); else n->tag = NULL; return 0; } /** * @brief Set the CVSS base of an NVT. * * @param n The NVT Info structure. * * @param cvss_base The CVSS base to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_cvss_base (nvti_t *n, const gchar *cvss_base) { if (!n) return -1; g_free (n->cvss_base); if (cvss_base && cvss_base[0]) n->cvss_base = g_strdup (cvss_base); else n->cvss_base = NULL; return 0; } /** * @brief Set the dependencies of a NVT. * * @param n The NVT Info structure. * * @param dependencies The dependencies to set. A copy will be created from * this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_dependencies (nvti_t *n, const gchar *dependencies) { if (!n) return -1; g_free (n->dependencies); if (dependencies && dependencies[0]) n->dependencies = g_strdup (dependencies); else n->dependencies = NULL; return 0; } /** * @brief Set the required keys of a NVT. * * @param n The NVT Info structure. * * @param required_keys The required keys to set. A copy will be created from * this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_required_keys (nvti_t *n, const gchar *required_keys) { if (!n) return -1; g_free (n->required_keys); if (required_keys && required_keys[0]) n->required_keys = g_strdup (required_keys); else n->required_keys = NULL; return 0; } /** * @brief Set the mandatory keys of a NVT. * * @param n The NVT Info structure. * * @param mandatory_keys The mandatory keys to set. A copy will be created from * this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_mandatory_keys (nvti_t *n, const gchar *mandatory_keys) { if (!n) return -1; g_free (n->mandatory_keys); if (mandatory_keys && mandatory_keys[0]) n->mandatory_keys = g_strdup (mandatory_keys); else n->mandatory_keys = NULL; return 0; } /** * @brief Set the excluded keys of a NVT. * * @param n The NVT Info structure. * * @param excluded_keys The excluded keys to set. A copy will be created from * this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_excluded_keys (nvti_t *n, const gchar *excluded_keys) { if (!n) return -1; g_free (n->excluded_keys); if (excluded_keys && excluded_keys[0]) n->excluded_keys = g_strdup (excluded_keys); else n->excluded_keys = NULL; return 0; } /** * @brief Set the required ports of a NVT. * * @param n The NVT Info structure. * * @param required_ports The required ports to set. A copy will be created from * this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_required_ports (nvti_t *n, const gchar *required_ports) { if (!n) return -1; g_free (n->required_ports); if (required_ports && required_ports[0]) n->required_ports = g_strdup (required_ports); else n->required_ports = NULL; return 0; } /** * @brief Set the required udp ports of a NVT. * * @param n The NVT Info structure. * * @param required_udp_ports The required udp ports to set. A copy will be * created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_required_udp_ports (nvti_t *n, const gchar *required_udp_ports) { if (!n) return -1; g_free (n->required_udp_ports); if (required_udp_ports && required_udp_ports[0]) n->required_udp_ports = g_strdup (required_udp_ports); else n->required_udp_ports = NULL; return 0; } /** * @brief Set the detection text of a NVT. * * @param n The NVT Info structure. * * @param detection The detection text to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_detection (nvti_t *n, const gchar *detection) { if (!n) return -1; g_free (n->detection); n->detection = g_strdup (detection); return 0; } /** * @brief Set the detection text of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param detection The detection text to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_detection (nvti_t *n, gchar *detection) { if (!n) return -1; g_free (n->detection); n->detection = detection; return 0; } /** * @brief Set the QoD type of a NVT. * * @param n The NVT Info structure. * * @param qod_type The QoD type to set. A copy will be created from this. * The string is not checked, any string is accepted as type. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_qod_type (nvti_t *n, const gchar *qod_type) { if (!n) return -1; g_free (n->qod_type); if (qod_type && qod_type[0]) n->qod_type = g_strdup (qod_type); else n->qod_type = NULL; return 0; } /** * @brief Set the QoD of a NVT. * * @param n The NVT Info structure. * * @param qod The QoD to set. A copy will be created from this. * The string is not checked, any string is accepted as type. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_qod (nvti_t *n, const gchar *qod) { if (!n) return -1; g_free (n->qod); if (qod && qod[0]) n->qod = g_strdup (qod); else n->qod = NULL; return 0; } /** * @brief Set the family of a NVT. * * @param n The NVT Info structure. * * @param family The family to set. A copy will be created from this. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_family (nvti_t *n, const gchar *family) { if (!n) return -1; g_free (n->family); n->family = g_strdup (family); return 0; } /** * @brief Set the family of a NVT, using the given memory. * * @param n The NVT Info structure. * * @param family The family to set. The string will be used directly. * * @return 0 for success. Anything else indicates an error. */ int nvti_put_family (nvti_t *n, gchar *family) { if (!n) return -1; g_free (n->family); n->family = family; return 0; } /** * @brief Set the category type of a NVT Info. * * @param n The NVT Info structure. * * @param category The category to set. Values <= 0 will indicate it is not set. * * @return 0 for success. Anything else indicates an error. */ int nvti_set_category (nvti_t *n, const gint category) { if (!n) return -1; n->category = category; return 0; } /** * @brief Add many new vtref from a comma-separated list. * * @param n The NVTI where to add the references. * * @param type The type for all references. If NULL, then for ref_ids * a syntax is expected that includes the type like * "type:id,type:id". * * @param ref_ids A CSV of reference to be added. * * @param ref_text The optional text accompanying all references. * * @return 0 for success. 1 if n was NULL, 2 if ref_ids was NULL. */ int nvti_add_refs (nvti_t *n, const gchar *type, const gchar *ref_ids, const gchar *ref_text) { gchar **split, **item; if (!n) return 1; if (!ref_ids) return 2; split = g_strsplit (ref_ids, ",", 0); for (item = split; *item; item++) { gchar *id; id = *item; g_strstrip (id); if (strcmp (id, "") == 0) continue; if (type) { nvti_add_vtref (n, vtref_new (type, id, ref_text)); } else { gchar **split2; split2 = g_strsplit (id, ":", 2); if (split2[0] && split2[1]) nvti_add_vtref (n, vtref_new (split2[0], split2[1], "")); g_strfreev (split2); } } g_strfreev (split); return 0; } /** * @brief Add a required key of a NVT. * * @param n The NVT Info structure. * * @param key The required key to add. A copy will be created from this. * * @return 0 for success. 1 if n was NULL. 2 if key was NULL. */ int nvti_add_required_keys (nvti_t *n, const gchar *key) { gchar *old; if (!n) return 1; if (!key) return 2; old = n->required_keys; if (old) { n->required_keys = g_strdup_printf ("%s, %s", old, key); g_free (old); } else n->required_keys = g_strdup (key); return 0; } /** * @brief Add a mandatory key of a NVT. * * @param n The NVT Info structure. * * @param key The mandatory key to add. A copy will be created from this. * * @return 0 for success. 1 if n was NULL. 2 if key was NULL. */ int nvti_add_mandatory_keys (nvti_t *n, const gchar *key) { gchar *old; if (!n) return 1; if (!key) return 2; old = n->mandatory_keys; if (old) { n->mandatory_keys = g_strdup_printf ("%s, %s", old, key); g_free (old); } else n->mandatory_keys = g_strdup (key); return 0; } /** * @brief Add a excluded key of a NVT. * * @param n The NVT Info structure. * * @param key The excluded key to add. A copy will be created from this. * * @return 0 for success. 1 if n was NULL. 2 if key was NULL. */ int nvti_add_excluded_keys (nvti_t *n, const gchar *key) { gchar *old; if (!n) return 1; if (!key) return 2; old = n->excluded_keys; if (old) { n->excluded_keys = g_strdup_printf ("%s, %s", old, key); g_free (old); } else n->excluded_keys = g_strdup (key); return 0; } /** * @brief Add a required port of a NVT. * * @param n The NVT Info structure. * * @param port The required port to add. A copy will be created from this. * * @return 0 for success. 1 if n was NULL. 2 if port was NULL. */ int nvti_add_required_ports (nvti_t *n, const gchar *port) { gchar *old; if (!n) return 1; if (!port) return 2; old = n->required_ports; if (old) { n->required_ports = g_strdup_printf ("%s, %s", old, port); g_free (old); } else n->required_ports = g_strdup (port); return 0; } /** * @brief Add a required udp port of a NVT. * * @param n The NVT Info structure. * * @param port The required udp port to add. A copy will be created from this. * * @return 0 for success. 1 if n was NULL. 2 if port was NULL. */ int nvti_add_required_udp_ports (nvti_t *n, const gchar *port) { gchar *old; if (!n) return 1; if (!port) return 2; old = n->required_udp_ports; if (old) { n->required_udp_ports = g_strdup_printf ("%s, %s", old, port); g_free (old); } else n->required_udp_ports = g_strdup (port); return 0; } /** * @brief Add a preference to the NVT Info. * * @param n The NVT Info structure. * * @param np The NVT preference to add. * * @return 0 for success. Anything else indicates an error. */ int nvti_add_pref (nvti_t *n, nvtpref_t *np) { if (!n) return -1; n->prefs = g_slist_append (n->prefs, np); return 0; } /* Collections of nvtis. */ /** * @brief Free an NVT Info, for g_hash_table_destroy. * * @param nvti The NVT Info. */ static void free_nvti_for_hash_table (gpointer nvti) { nvti_free ((nvti_t *) nvti); } /** * @brief Make a collection of NVT Infos. * * @return An empty collection of NVT Infos. */ nvtis_t * nvtis_new (void) { return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_nvti_for_hash_table); } /** * @brief Free a collection of NVT Infos. * * @param nvtis The collection of NVT Infos. */ void nvtis_free (nvtis_t *nvtis) { if (nvtis) g_hash_table_destroy (nvtis); } /** * @brief Add an NVT Info to a collection of NVT Infos. * * @param nvtis The collection of NVT Infos. * @param nvti The NVT Info to add. */ void nvtis_add (nvtis_t *nvtis, nvti_t *nvti) { if (nvti) g_hash_table_insert ( nvtis, (gpointer) (nvti_oid (nvti) ? g_strdup (nvti_oid (nvti)) : NULL), (gpointer) nvti); } /** * @brief Add an NVT Info to a collection of NVT Infos. * * @param nvtis The collection of NVT Infos. * @param oid The OID of the NVT. * * @return The NVT Info, if found, else NULL. */ nvti_t * nvtis_lookup (nvtis_t *nvtis, const char *oid) { return g_hash_table_lookup (nvtis, oid); } gvm-libs-22.20.0/base/nvti.h000066400000000000000000000127371477470532200154650ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Protos and data structures for NVT Information data sets. * * This file contains the protos for \ref nvti.c */ #ifndef _NVTI_H #define _NVTI_H #include #define NVTPREF_TIMEOUT_ID 0 typedef struct nvtpref nvtpref_t; nvtpref_t * nvtpref_new (int, const gchar *, const gchar *, const gchar *); void nvtpref_free (nvtpref_t *); gchar * nvtpref_name (const nvtpref_t *); gchar * nvtpref_type (const nvtpref_t *); gchar * nvtpref_default (const nvtpref_t *); int nvtpref_id (const nvtpref_t *); /** * @brief The structure for a cross reference of a VT. */ typedef struct vtref vtref_t; /** * @brief The structure for a severity of a VT. */ typedef struct vtseverity vtseverity_t; /** * @brief The structure of a information record that corresponds to a NVT. */ typedef struct nvti nvti_t; vtref_t * vtref_new (const gchar *, const gchar *, const gchar *); void vtref_free (vtref_t *); const gchar * vtref_type (const vtref_t *); const gchar * vtref_id (const vtref_t *); const gchar * vtref_text (const vtref_t *); vtseverity_t * vtseverity_new (const gchar *, const gchar *, int, double, const gchar *); void vtseverity_free (vtseverity_t *); const gchar * vtseverity_type (const vtseverity_t *); const gchar * vtseverity_origin (const vtseverity_t *); const gchar * vtseverity_value (const vtseverity_t *); int vtseverity_date (const vtseverity_t *); double vtseverity_score (const vtseverity_t *); int nvti_add_vtref (nvti_t *, vtref_t *); guint nvti_vtref_len (const nvti_t *); vtref_t * nvti_vtref (const nvti_t *, guint); int nvti_add_vtseverity (nvti_t *, vtseverity_t *); guint nvti_vtseverities_len (const nvti_t *); vtseverity_t * nvti_vtseverity (const nvti_t *, guint); double nvti_severity_score (const nvti_t *); gchar * nvti_severity_vector_from_tag (const nvti_t *); nvti_t * nvti_new (void); void nvti_free (nvti_t *); gchar * nvti_oid (const nvti_t *); gchar * nvti_name (const nvti_t *); gchar * nvti_summary (const nvti_t *); gchar * nvti_affected (const nvti_t *); gchar * nvti_impact (const nvti_t *); time_t nvti_creation_time (const nvti_t *); time_t nvti_modification_time (const nvti_t *); gchar * nvti_insight (const nvti_t *); gchar * nvti_refs (const nvti_t *, const gchar *, const char *, guint); gchar * nvti_solution (const nvti_t *); gchar * nvti_solution_type (const nvti_t *); gchar * nvti_solution_method (const nvti_t *); gchar * nvti_tag (const nvti_t *); gchar * nvti_get_tag (const nvti_t *, const gchar *); gchar * nvti_cvss_base (const nvti_t *); gchar * nvti_dependencies (const nvti_t *); gchar * nvti_required_keys (const nvti_t *); gchar * nvti_mandatory_keys (const nvti_t *); gchar * nvti_excluded_keys (const nvti_t *); gchar * nvti_required_ports (const nvti_t *); gchar * nvti_required_udp_ports (const nvti_t *); gchar * nvti_detection (const nvti_t *); gchar * nvti_qod_type (const nvti_t *); gchar * nvti_qod (const nvti_t *); gint nvti_timeout (const nvti_t *); gint nvti_category (const nvti_t *); gchar * nvti_family (const nvti_t *); guint nvti_pref_len (const nvti_t *); const nvtpref_t * nvti_pref (const nvti_t *, guint); int nvti_set_oid (nvti_t *, const gchar *); int nvti_set_name (nvti_t *, const gchar *); int nvti_put_name (nvti_t *, gchar *); int nvti_set_summary (nvti_t *, const gchar *); int nvti_put_summary (nvti_t *, gchar *); int nvti_set_insight (nvti_t *, const gchar *); int nvti_put_insight (nvti_t *, gchar *); int nvti_set_affected (nvti_t *, const gchar *); int nvti_put_affected (nvti_t *, gchar *); int nvti_set_impact (nvti_t *, const gchar *); int nvti_put_impact (nvti_t *, gchar *); int nvti_set_creation_time (nvti_t *, const time_t); int nvti_set_modification_time (nvti_t *, const time_t); int nvti_set_solution (nvti_t *, const gchar *); int nvti_put_solution (nvti_t *, gchar *); int nvti_set_solution_type (nvti_t *, const gchar *); int nvti_set_solution_method (nvti_t *, const gchar *); int nvti_add_tag (nvti_t *, const gchar *, const gchar *); int nvti_set_tag (nvti_t *, const gchar *); int nvti_set_cvss_base (nvti_t *, const gchar *); int nvti_set_dependencies (nvti_t *, const gchar *); int nvti_set_required_keys (nvti_t *, const gchar *); int nvti_set_mandatory_keys (nvti_t *, const gchar *); int nvti_set_excluded_keys (nvti_t *, const gchar *); int nvti_set_required_ports (nvti_t *, const gchar *); int nvti_set_required_udp_ports (nvti_t *, const gchar *); int nvti_set_detection (nvti_t *, const gchar *); int nvti_put_detection (nvti_t *, gchar *); int nvti_set_qod_type (nvti_t *, const gchar *); int nvti_set_qod (nvti_t *, const gchar *); int nvti_set_timeout (nvti_t *, const gint); int nvti_set_category (nvti_t *, const gint); int nvti_set_family (nvti_t *, const gchar *); int nvti_put_family (nvti_t *, gchar *); int nvti_add_refs (nvti_t *, const gchar *, const gchar *, const gchar *); int nvti_add_required_keys (nvti_t *, const gchar *); int nvti_add_mandatory_keys (nvti_t *, const gchar *); int nvti_add_excluded_keys (nvti_t *, const gchar *); int nvti_add_required_ports (nvti_t *, const gchar *); int nvti_add_required_udp_ports (nvti_t *, const gchar *); int nvti_add_pref (nvti_t *, nvtpref_t *); /* Collections of NVT Infos. */ /** * @brief A collection of information records corresponding to NVTs. */ typedef GHashTable nvtis_t; nvtis_t * nvtis_new (void); void nvtis_free (nvtis_t *); void nvtis_add (nvtis_t *, nvti_t *); nvti_t * nvtis_lookup (nvtis_t *, const char *); #endif /* not _NVTI_H */ gvm-libs-22.20.0/base/nvti_tests.c000066400000000000000000000117261477470532200166770ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "nvti.c" #include #include Describe (nvti); BeforeEach (nvti) { } AfterEach (nvti) { } /* make_nvti */ Ensure (nvti, nvti_new_never_returns_null) { assert_that (nvti_new (), is_not_null); } /* nvti solution_method */ Ensure (nvti, nvti_parse_timestamp) { setenv ("TZ", "utc 0", 1); tzset (); assert_that ( parse_nvt_timestamp ("2018-09-07 11:08:31 +0200 (Fri, 07 Sep 2018)"), is_equal_to (1536311311)); assert_that_double ( parse_nvt_timestamp ("2022-05-31 20:54:22 +0100 (Tue, 31 May 2022)"), is_equal_to_double (1654026862)); assert_that_double (parse_nvt_timestamp ("2012-09-23 02:15:34 +0400"), is_equal_to_double (1348352134)); assert_that_double (parse_nvt_timestamp ("Fri Feb 10 16:09:30 2023 +0100"), is_equal_to_double (1676041770)); } /* nvti solution_method */ Ensure (nvti, nvti_set_solution_method_correct) { nvti_t *nvti; gchar *solution_method; nvti = nvti_new (); nvti_set_solution_method (nvti, "DebianAPTUpgrade"); solution_method = nvti_solution_method (nvti); assert_that (solution_method, is_equal_to_string ("DebianAPTUpgrade")); nvti_free (nvti); } /* nvti_get_tag */ Ensure (nvti, nvti_get_tag_gets_correct_value_one_tag) { nvti_t *nvti; gchar *tag; nvti = nvti_new (); nvti_set_tag (nvti, "a=1"); tag = nvti_get_tag (nvti, "a"); assert_that (tag, is_equal_to_string ("1")); g_free (tag); nvti_free (nvti); } Ensure (nvti, nvti_get_tag_gets_correct_value_many_tags) { nvti_t *nvti; gchar *tag; nvti = nvti_new (); nvti_set_tag (nvti, "a=1|b=2|c=3"); tag = nvti_get_tag (nvti, "b"); assert_that (tag, is_equal_to_string ("2")); g_free (tag); nvti_free (nvti); } Ensure (nvti, nvti_get_tag_handles_empty_tag) { nvti_t *nvti; nvti = nvti_new (); assert_that (nvti_get_tag (nvti, "b"), is_null); nvti_free (nvti); } Ensure (nvti, nvti_get_tag_handles_null_nvti) { assert_that (nvti_get_tag (NULL, "example"), is_null); } Ensure (nvti, nvti_get_tag_handles_null_name) { nvti_t *nvti; nvti = nvti_new (); nvti_set_tag (nvti, "example=1"); assert_that (nvti_get_tag (nvti, NULL), is_null); nvti_free (nvti); } /* nvtis_add */ Ensure (nvti, nvtis_add_does_not_use_oid_as_key) { nvtis_t *nvtis; nvti_t *nvti; gchar *oid; nvtis = nvtis_new (); nvti = nvti_new (); nvti_set_oid (nvti, "1"); oid = nvti_oid (nvti); /* This should not use the pointer nvti->oid as the key, because nvti_set_oid * could free nvti->oid. */ nvtis_add (nvtis, nvti); /* Change the first character of the OID. */ *oid = '2'; /* To check that the key is not the same pointer as nvti->oid, check * that changing the first character of nvti->oid did not affect the key. */ assert_that (nvtis_lookup (nvtis, "1"), is_not_null); assert_that (nvtis_lookup (nvtis, "2"), is_null); } /* nvti severity vector */ Ensure (nvti, nvti_get_severity_vector_both) { nvti_t *nvti; nvti = nvti_new (); nvti_set_tag (nvti, "cvss_base_vector=DEF"); nvti_set_tag (nvti, "severity_vector=ABC"); assert_that (nvti_severity_vector_from_tag (nvti), is_equal_to_string ("ABC")); nvti_free (nvti); } Ensure (nvti, nvti_get_severity_vector_no_cvss_base) { nvti_t *nvti; nvti = nvti_new (); nvti_set_tag (nvti, "severity_vector=ABC"); assert_that (nvti_severity_vector_from_tag (nvti), is_equal_to_string ("ABC")); nvti_free (nvti); } Ensure (nvti, nvti_get_severity_vector_no_severity_vector) { nvti_t *nvti; nvti = nvti_new (); nvti_set_tag (nvti, "cvss_base_vector=DEF"); assert_that (nvti_severity_vector_from_tag (nvti), is_equal_to_string ("DEF")); nvti_free (nvti); } /* Test suite. */ int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, nvti, nvti_new_never_returns_null); add_test_with_context (suite, nvti, nvti_get_tag_gets_correct_value_one_tag); add_test_with_context (suite, nvti, nvti_get_tag_gets_correct_value_many_tags); add_test_with_context (suite, nvti, nvti_get_tag_handles_empty_tag); add_test_with_context (suite, nvti, nvti_get_tag_handles_null_nvti); add_test_with_context (suite, nvti, nvti_get_tag_handles_null_name); add_test_with_context (suite, nvti, nvti_set_solution_method_correct); add_test_with_context (suite, nvti, nvtis_add_does_not_use_oid_as_key); add_test_with_context (suite, nvti, nvti_get_severity_vector_both); add_test_with_context (suite, nvti, nvti_get_severity_vector_no_severity_vector); add_test_with_context (suite, nvti, nvti_get_severity_vector_no_cvss_base); add_test_with_context (suite, nvti, nvti_parse_timestamp); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/pidfile.c000066400000000000000000000041051477470532200161020ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief PID-file management. */ #include "pidfile.h" #include /* for errno */ #include /* for g_free, gchar */ #include /* for g_unlink, g_fopen */ #include /* for libgen */ #include /* for fclose, FILE */ #include /* for atoi */ #include /* for strerror */ #include /* for getpid */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Create a PID-file. * * A standard PID file will be created for the * given path. * * @param[in] pid_file_path The full path of the pid file. E.g. * "/tmp/service1.pid" * * @return 0 for success, anything else indicates an error. */ int pidfile_create (gchar *pid_file_path) { FILE *pidfile; gchar *copy, *dir; if (pid_file_path == NULL) return -1; copy = g_strdup (pid_file_path); dir = dirname (copy); /* Ensure directory exists. */ if (g_mkdir_with_parents (dir, 0755)) /* "rwxr-xr-x" */ { g_free (copy); g_warning ("Failed to create PID file directory %s: %s", dir, strerror (errno)); return 1; } g_free (copy); /* Create file. */ pidfile = g_fopen (pid_file_path, "w"); if (pidfile == NULL) { g_critical ("%s: failed to open pidfile %s: %s\n", __func__, pid_file_path, strerror (errno)); return 1; } else { g_fprintf (pidfile, "%d\n", getpid ()); fclose (pidfile); } return 0; } /** * @brief Remove PID file. * * @param[in] pid_file_path The full path of the pid file. E.g. * "/tmp/service1.pid" */ void pidfile_remove (gchar *pid_file_path) { gchar *pidfile_contents; if (g_file_get_contents (pid_file_path, &pidfile_contents, NULL, NULL)) { int pid = atoi (pidfile_contents); if (pid == getpid ()) { g_unlink (pid_file_path); } g_free (pidfile_contents); } } gvm-libs-22.20.0/base/pidfile.h000066400000000000000000000004701477470532200161100ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief PID-file management. */ #ifndef _GVM_PIDFILE_H #define _GVM_PIDFILE_H #include int pidfile_create (gchar *); void pidfile_remove (gchar *); #endif /* not _GVM_PIDFILE_H */ gvm-libs-22.20.0/base/prefs.c000066400000000000000000000112731477470532200156110ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2014-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of API to handle globally stored preferences. * * A global store of preferences to scanner and NVTs is handled by this * module. */ #include "prefs.h" #include "settings.h" /* for init_settings_iterator_from_file */ #include /* for gchar */ #include /* for printf() */ #include /* for atoi() */ #include /* for strlen() */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" static GHashTable *global_prefs = NULL; void prefs_set (const gchar *, const gchar *); /** * @brief Initializes the preferences structure. If it was * already initialized, remove old settings and start * from scratch. */ static void prefs_init (void) { if (global_prefs) g_hash_table_destroy (global_prefs); global_prefs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); prefs_set ("cgi_path", "/cgi-bin:/scripts"); prefs_set ("checks_read_timeout", "5"); prefs_set ("unscanned_closed", "yes"); prefs_set ("unscanned_closed_udp", "yes"); prefs_set ("timeout_retry", "3"); prefs_set ("expand_vhosts", "yes"); prefs_set ("test_empty_vhost", "no"); prefs_set ("open_sock_max_attempts", "5"); prefs_set ("time_between_request", "0"); prefs_set ("nasl_no_signature_check", "yes"); prefs_set ("max_hosts", "30"); prefs_set ("max_checks", "10"); prefs_set ("log_whole_attack", "no"); prefs_set ("log_plugins_name_at_load", "no"); prefs_set ("optimize_test", "yes"); prefs_set ("non_simult_ports", "139, 445, 3389, Services/irc"); prefs_set ("safe_checks", "yes"); prefs_set ("auto_enable_dependencies", "yes"); prefs_set ("drop_privileges", "no"); prefs_set ("report_host_details", "yes"); prefs_set ("vendor_version", "\0"); prefs_set ("test_alive_hosts_only", "yes"); prefs_set ("test_alive_wait_timeout", "3"); prefs_set ("debug_tls", "0"); prefs_set ("allow_simultaneous_ips", "yes"); } /** * @brief Get the pointer to the global preferences structure. * Eventually this function should not be used anywhere. * * @return Pointer to the global preferences structure. */ GHashTable * preferences_get (void) { if (!global_prefs) prefs_init (); return global_prefs; } /** * @brief Get a string preference value via a key. * * @param key The identifier for the preference. * * @return A pointer to a string with the value for the preference. * NULL in case for the key no preference was found or the * preference is not of type string. */ const gchar * prefs_get (const gchar *key) { if (!global_prefs) prefs_init (); return g_hash_table_lookup (global_prefs, key); } /** * @brief Get a boolean expression of a preference value via a key. * * @param key The identifier for the preference. * * @return 1 if the value is considered to represent "true" and * 0 if the value is considered to represent "false". * If the preference is of type string, value "yes" is true, * anything else is false. * Any other type or non-existing key is false. */ int prefs_get_bool (const gchar *key) { gchar *str; if (!global_prefs) prefs_init (); str = g_hash_table_lookup (global_prefs, key); if (str && !strcmp (str, "yes")) return 1; return 0; } /** * @brief Set a string preference value via a key. * * @param key The identifier for the preference. A copy of this will * be created if necessary. * * @param value The value to set. A copy of this will be created. */ void prefs_set (const gchar *key, const gchar *value) { if (!global_prefs) prefs_init (); g_hash_table_insert (global_prefs, g_strdup (key), g_strdup (value)); } /** * @brief Apply the configs from given file as preferences. * * @param config Filename of the configuration file. */ void prefs_config (const char *config) { settings_iterator_t settings; if (!global_prefs) prefs_init (); if (!init_settings_iterator_from_file (&settings, config, "Misc")) { while (settings_iterator_next (&settings)) prefs_set (settings_iterator_name (&settings), settings_iterator_value (&settings)); cleanup_settings_iterator (&settings); } prefs_set ("config_file", config); } /** * @brief Dump the preferences to stdout */ void prefs_dump (void) { void *name, *value; GHashTableIter iter; if (global_prefs) { g_hash_table_iter_init (&iter, global_prefs); while (g_hash_table_iter_next (&iter, &name, &value)) { printf ("%s = %s\n", (char *) name, (char *) value); } } } gvm-libs-22.20.0/base/prefs.h000066400000000000000000000011471477470532200156150ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2014-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Protos and data structures for NVT Information data sets. * * This file contains the protos for \ref prefs.c */ #ifndef _GVM_PREFS_H #define _GVM_PREFS_H #include /* for gchar */ void prefs_config (const char *); const gchar * prefs_get (const gchar *key); int prefs_get_bool (const gchar *key); void prefs_set (const gchar *, const gchar *); void prefs_dump (void); int prefs_nvt_timeout (const char *); GHashTable * preferences_get (void); #endif /* not _GVM_PREFS_H */ gvm-libs-22.20.0/base/proctitle.c000066400000000000000000000065331477470532200165020ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2014-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Implementation of an API to set process title. */ #include "proctitle.h" #include /* for g_free, g_malloc0, g_strdup */ #include #include /* for strlen, strdup, bzero, strncpy */ #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Access to the executable's name. */ extern const char *__progname; #ifndef __FreeBSD__ extern const char *__progname_full; #endif static char **old_argv; static int old_argc; extern char **environ; void *current_environ = NULL; static int max_prog_name = 0; /** * @brief Initializes the process setting variables. * * @param[in] argc Argc argument from main. * @param[in] argv Argv argument from main. */ void proctitle_init (int argc, char **argv) { int i; char **envp = environ; #ifndef __FreeBSD__ char *new_progname, *new_progname_full; #else char *new_progname; #endif old_argc = argc; if (argv == NULL) return; // according to c99 argv is defined as when argc is set it follows program // parameter. Since we will override on set_proctitle we know that this // memory is modifiable. // Everything after that is unsafe and can lead to segmentation faults. // Therefore we iterate through argv and append strlen to gather the maximum // safe program name. for (i = 0; i < argc; i++) { max_prog_name += strlen (argv[i]) + 1; } i = 0; new_progname = strdup (__progname); #ifndef __FreeBSD__ new_progname_full = strdup (__progname_full); #endif /* Move environ to new memory, to be able to reuse older one. */ while (envp[i]) i++; environ = g_malloc0 (sizeof (char *) * (i + 1)); if (current_environ) g_free (current_environ); current_environ = environ; for (i = 0; envp[i]; i++) environ[i] = g_strdup (envp[i]); environ[i] = NULL; old_argv = argv; /* Seems like these are in the moved environment, so reset them. Idea from * proctitle.cpp in KDE libs. */ __progname = new_progname; #ifndef __FreeBSD__ __progname_full = new_progname_full; #endif } /** * @brief Sets the process' title. * * @param[in] new_title Format string for new process title. * @param[in] args Format string arguments variable list. */ static void proctitle_set_args (const char *new_title, va_list args) { char *formatted; int tmp; if (old_argv == NULL) /* Called setproctitle before initproctitle ? */ return; if (max_prog_name == 0) // there may no program name set return; // omit previous additional parameter formatted = g_strdup_vprintf (new_title, args); tmp = strlen (formatted); if (tmp >= max_prog_name) { formatted[max_prog_name] = '\0'; tmp = max_prog_name; } // set display name memset (old_argv[0], 0, max_prog_name); memcpy (old_argv[0], formatted, tmp); g_free (formatted); if (old_argc > 1) old_argv[1] = NULL; } /** * @brief Sets the process' title. * * @param[in] new_title Format string for new process title. * @param[in] ... Arguments for format string. */ void proctitle_set (const char *new_title, ...) { va_list args; va_start (args, new_title); proctitle_set_args (new_title, args); va_end (args); } gvm-libs-22.20.0/base/proctitle.h000066400000000000000000000005051477470532200165000ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2014-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief API for process title setting. */ #ifndef _GVM_PROCTITLE_H #define _GVM_PROCTITLE_H void proctitle_init (int, char **); void proctitle_set (const char *, ...); #endif /* not _GVM_PROCTITLE_H */ gvm-libs-22.20.0/base/pwpolicy.c000066400000000000000000000275311477470532200163440ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Check passwords against a list of pattern * * See \ref PWPOLICY_FILE_NAME for a syntax description of the pattern * file. */ #include "pwpolicy.h" #include /* for errno */ #include /* for g_strdup_printf, g_ascii_strcasecmp, g_free, ... */ #include /* for fclose, fgets, fopen, FILE, ferror, EOF, getc */ #include #include /* for strstr, strlen, strncmp */ #ifndef DIM #define DIM(v) (sizeof (v) / sizeof ((v)[0])) #define DIMof(type, member) DIM (((type *) 0)->member) #endif #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief The name of the pattern file * * This file contains pattern with bad passphrases. The file is line * based with maximum length of 255 bytes per line and expected to be * in UTF-8 encoding. Each line may either be a comment line, a * simple string, a regular expression or a processing instruction. * The lines are parsed sequentially. * * *Comments* are indicated by a hash mark ('#') as the first non * white-space character of a line followed immediately by a space or * end of line. Such a comment line is completely ignored. * * *Simple strings* start after optional leading white-space. They * are compared to the password under validation. The comparison is * case insensitive for all ASCII characters. * * *Regular expressions* start after optional leading white-space with * either a single slash ('/') or an exclamation mark ('!') directly * followed by a slash. They extend to the end of the line but may be * terminated with another slash which may then only be followed by * more white-space. The regular expression are Perl Compatible * Regular Expressions (PCRE) and are by default case insensitive. If * the regular expression line starts with the exclamation mark, the * match is reversed; i.e. an error is returned if the password does * not match. * * *Processing instructions* are special comments to control the * operation of the policy checking. The start like a comment but the * hash mark is immediately followed by a plus ('+') signed, a * keyword, an optional colon (':') and an optional value string. The * following processing instructions are supported: * * #+desc[:] STRING * * This is used to return a meaningful error message. STRING is * used a the description for all errors up to the next /desc/ or * /nodesc/ processing instruction. * * #+nodesc * * This is syntactic sugar for /desc/ without a value. It * switches back to a default error description (pattern file name * and line number). * * #+search[:] FILENAME * * This searches the file with name FILENAME for a match. The * comparison is case insensitive for all ASCII characters. This * is a simple linear search and stops at the first match. * Comments are not allowed in that file. A line in that file may * not be longer than 255 characters. An example for such a file * is "/usr/share/dict/words". * * #+username * * This is used to perform checks on the name/password * combination. Currently this checks whether the password * matches or is included in the password. It may eventually be * extended to further tests. */ #define PWPOLICY_FILE_NAME GVM_SYSCONF_DIR "/pwpolicy.conf" /** * @brief Flag indicating that passwords are not checked. */ static gboolean disable_password_policy; /** * @return A malloced string to be returned on read and configuration * errors. */ static char * policy_checking_failed (void) { return g_strdup ("Password policy checking failed (internal error)"); } /** * @brief Check whether a string starts with a keyword * * Note that the keyword may optionally be terminated by a colon. * * @param string The string to check * @param keyword The keyword * * @return NULL if the keyword is not found. If found a pointer into * \p string to the value of the keyword with removed leading * spaces is returned. */ static char * is_keyword (char *string, const char *keyword) { int idx, slen; char *tmp; idx = strlen (keyword); slen = strlen (string); if (!strncmp (string, keyword, idx)) { tmp = string + idx; if (tmp - string > slen) return NULL; // skip optional: if (*tmp == ':') tmp++; if (tmp - string > slen) return NULL; for (; tmp - string < slen && g_ascii_isspace (*tmp); tmp++) { // skip whitespace } return tmp; } return NULL; } /** * @brief Search a file for a matching line * * This is a case insensitive search for a password in a file. The * file is assumed to be a simple LF delimited list of words. * * @param fname Name of the file to search. * @param password Password to search for. * * @return -1 if the file could not be opened or a read error * occurred, 0 if password was not found and 1 if password was found. */ static int search_file (const char *fname, const char *password) { FILE *fp; int c; char line[256]; fp = fopen (fname, "r"); if (!fp) return -1; while (fgets (line, DIM (line) - 1, fp)) { size_t len; len = strlen (line); if (!len || line[len - 1] != '\n') { /* Incomplete last line or line too long. Eat until end of line. */ while ((c = getc (fp)) != EOF && c != '\n') ; continue; } line[--len] = 0; /* Chop the LF. */ if (len && line[len - 1] == '\r') line[--len] = 0; /* Chop an optional CR. */ if (!len) continue; /* Empty */ if (!g_ascii_strcasecmp (line, password)) { fclose (fp); return 1; /* Found. */ } } if (ferror (fp)) { int save_errno = errno; fclose (fp); errno = save_errno; return -1; /* Read error. */ } fclose (fp); return 0; /* Not found. */ } /** * @brief Parse one line of a pettern file * * @param line A null terminated buffer with the content of the line. * The line terminator has already been stripped. It may * be modified after return. * @param fname The name of the pattern file for error reporting * @param lineno The current line number for error reporting * @param descp Pointer to a variable holding the current description * string or NULL for no description. * @param password The password to check. * @param username The username to check. * * @return NULL on success or a malloced string with an error * description. */ static char * parse_pattern_line (char *line, const char *fname, int lineno, char **descp, const char *password, const char *username) { char *ret = NULL; char *p; size_t n; /* Skip leading spaces. */ while (g_ascii_isspace (*line)) line++; if (!*line) /* Empty line. */ { ret = NULL; } else if (*line == '#' && line[1] == '+') /* Processing instruction. */ { line += 2; p = is_keyword (line, "desc"); if (p) { g_free (*descp); if (*p) *descp = g_strdup (p); else *descp = NULL; } else if ((is_keyword (line, "nodesc"))) { g_free (*descp); *descp = NULL; } else if ((p = is_keyword (line, "search"))) { int sret; sret = search_file (p, password); if (sret == -1) { g_warning ("error searching '%s' (requested at line %d): %s", p, lineno, g_strerror (errno)); ret = policy_checking_failed (); } else if (sret && *descp) ret = g_strdup_printf ("Weak password (%s)", *descp); else if (sret) ret = g_strdup_printf ("Weak password (found in '%s')", p); else ret = NULL; } else if (is_keyword (line, "username")) { /* Fixme: The include check is case sensitive and the strcmp does only work with ascii. Changing this required a bit more more (g_utf8_casefold) and also requires checking for valid utf8 sequences in the password and all pattern. */ if (!username) ret = NULL; else if (!g_ascii_strcasecmp (password, username)) ret = g_strdup_printf ("Weak password (%s)", "user name matches password"); else if (strstr (password, username)) ret = g_strdup_printf ("Weak password (%s)", "user name is part of the password"); else if (strstr (username, password)) ret = g_strdup_printf ("Weak password (%s)", "password is part of the user name"); else ret = NULL; } else { g_warning ("error reading '%s', line %d: %s", fname, lineno, "unknown processing instruction"); ret = policy_checking_failed (); } } else if (*line == '#') /* Comment */ { ret = NULL; } else if (*line == '/' || (*line == '!' && line[1] == '/')) /* Regular expression. */ { int rev = (*line == '!'); if (rev) line++; line++; n = strlen (line); if (n && line[n - 1] == '/') line[n - 1] = 0; if (((!g_regex_match_simple (line, password, G_REGEX_CASELESS, 0)) ^ rev)) ret = NULL; else if (*descp) ret = g_strdup_printf ("Weak password (%s)", *descp); else ret = g_strdup_printf ("Weak password (see '%s' line %d)", fname, lineno); } else /* Simple string. */ { if (g_ascii_strcasecmp (line, password)) ret = NULL; else if (*descp) ret = g_strdup_printf ("Weak password (%s)", *descp); else ret = g_strdup_printf ("Weak password (see '%s' line %d)", fname, lineno); } return ret; } /** * @brief Validate a password against the pattern file * * @param[in] password The password to check * @param[in] username The user name or NULL. This is used to check * the passphrase against the user name. * * @return NULL on success or a malloced string with an error * description. */ char * gvm_validate_password (const char *password, const char *username) { const char *patternfile = PWPOLICY_FILE_NAME; char *ret; FILE *fp; int lineno; char line[256]; char *desc = NULL; if (disable_password_policy) return NULL; if (!password || !*password) return g_strdup ("Empty password"); fp = fopen (patternfile, "r"); if (!fp) { g_warning ("error opening '%s': %s", patternfile, g_strerror (errno)); return policy_checking_failed (); } lineno = 0; ret = NULL; while (fgets (line, DIM (line) - 1, fp)) { size_t len; lineno++; len = strlen (line); if (!len || line[len - 1] != '\n') { g_warning ("error reading '%s', line %d: %s", patternfile, lineno, len ? "line too long" : "line without a LF"); ret = policy_checking_failed (); break; } line[--len] = 0; /* Chop the LF. */ if (len && line[len - 1] == '\r') line[--len] = 0; /* Chop an optional CR. */ ret = parse_pattern_line (line, patternfile, lineno, &desc, password, username); if (ret) break; bzero (line, sizeof (line)); } fclose (fp); g_free (desc); return ret; } /** * @brief Disable all password policy checking */ void gvm_disable_password_policy (void) { disable_password_policy = TRUE; g_warning ("Password policy checking has been disabled."); } gvm-libs-22.20.0/base/pwpolicy.h000066400000000000000000000006361477470532200163460ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2013-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Protos and data structures for pwpolicy checking. * * This file contains the protos for \ref pwpolicy.c */ #ifndef _GVM_PWPOLICY_H #define _GVM_PWPOLICY_H char * gvm_validate_password (const char *, const char *); void gvm_disable_password_policy (void); #endif /*_GVM_PWPOLICY_H*/ gvm-libs-22.20.0/base/pwpolicy_tests.c000066400000000000000000000032701477470532200175600ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "pwpolicy.c" #include #include #include #include #include Describe (pwpolicy); BeforeEach (pwpolicy) { } AfterEach (pwpolicy) { } /* parse_pattern_line */ Ensure (pwpolicy, parse_pattern_line_allows) { char *desc, *error, *line; desc = NULL; line = g_strdup ("password"); error = parse_pattern_line (line, "test", 111, &desc, "passw0rd", "name"); assert_that (error, is_null); g_free (desc); g_free (line); } Ensure (pwpolicy, parse_pattern_line_refuses) { char *desc, *error, *line; desc = NULL; line = g_strdup ("password"); error = parse_pattern_line (line, "test", 111, &desc, "password", "name"); assert_that (error, is_not_null); g_free (desc); g_free (error); g_free (line); } Ensure (pwpolicy, parse_pattern_line_comment) { char *desc, *error, *line; desc = NULL; line = g_strdup ("# password"); error = parse_pattern_line (line, "test", 111, &desc, "password", "name"); assert_that (error, is_null); g_free (desc); g_free (error); g_free (line); } /* Test suite. */ int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, pwpolicy, parse_pattern_line_allows); add_test_with_context (suite, pwpolicy, parse_pattern_line_refuses); add_test_with_context (suite, pwpolicy, parse_pattern_line_comment); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/base/settings.c000066400000000000000000000104331477470532200163270ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file settings.c * @brief Implementation of API to handle configuration file management */ #include "settings.h" #include #include /* for strlen */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Initialise a settings struct from a file. * * @param[in] settings Settings. * @param[in] filename Complete name of the configuration file. * @param[in] group Name of the group in the file. * * @return 0 success, -1 error. */ static int settings_init_from_file (settings_t *settings, const gchar *filename, const gchar *group) { GError *error = NULL; if (filename == NULL || group == NULL) return -1; gchar *contents = NULL; if (!g_file_get_contents (filename, &contents, NULL, &error)) { g_error_free (error); return -1; } if (contents != NULL) { gchar *contents_with_group = g_strjoin ("\n", "[Misc]", contents, NULL); settings->key_file = g_key_file_new (); if (!g_key_file_load_from_data ( settings->key_file, contents_with_group, strlen (contents_with_group), G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error)) { g_warning ("Failed to load configuration from %s: %s", filename, error->message); g_error_free (error); g_free (contents_with_group); g_free (contents); return -1; } g_free (contents_with_group); g_free (contents); } settings->group_name = g_strdup (group); settings->file_name = g_strdup (filename); return 0; } /** * @brief Cleanup a settings structure. * * @param[in] settings Settings structure. */ void settings_cleanup (settings_t *settings) { g_free (settings->group_name); g_free (settings->file_name); g_key_file_free (settings->key_file); } /** * @brief Initialise a settings iterator from a file. * * @param[in] iterator Settings iterator. * @param[in] filename Complete name of the configuration file. * @param[in] group Name of the group in the file. * * @return 0 success, -1 error. */ int init_settings_iterator_from_file (settings_iterator_t *iterator, const gchar *filename, const gchar *group) { int ret; gsize keys_length; GError *error = NULL; ret = settings_init_from_file (&iterator->settings, filename, group); if (ret) return ret; iterator->keys = g_key_file_get_keys (iterator->settings.key_file, group, &keys_length, &error); if (iterator->keys == NULL) { if (error) { g_warning ("Failed to retrieve keys of group %s from %s: %s", group, filename, error->message); g_error_free (error); } g_key_file_free (iterator->settings.key_file); return -1; } iterator->current_key = iterator->keys - 1; iterator->last_key = iterator->keys + keys_length - 1; return 0; } /** * @brief Cleanup a settings iterator. * * @param[in] iterator Settings iterator. */ void cleanup_settings_iterator (settings_iterator_t *iterator) { g_strfreev (iterator->keys); settings_cleanup (&iterator->settings); } /** * @brief Increment an iterator. * * @param[in] iterator Settings iterator. * * @return TRUE if there was a next item, else FALSE. */ gboolean settings_iterator_next (settings_iterator_t *iterator) { if (iterator->current_key == iterator->last_key) return FALSE; iterator->current_key++; return TRUE; } /** * @brief Get the name from a settings iterator. * * @param[in] iterator Settings iterator. * * @return Name of current key. */ const gchar * settings_iterator_name (settings_iterator_t *iterator) { return *iterator->current_key; } /** * @brief Get the value from a settings iterator. * * @param[in] iterator Settings iterator. * * @return Value of current key. */ const gchar * settings_iterator_value (settings_iterator_t *iterator) { return g_key_file_get_value (iterator->settings.key_file, iterator->settings.group_name, *iterator->current_key, NULL); } gvm-libs-22.20.0/base/settings.h000066400000000000000000000025771477470532200163460ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2010-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Protos and data structures for configuration file management * * This file contains the protos for \ref settings.c */ #ifndef _GVM_SETTINGS_H #define _GVM_SETTINGS_H #include /** * @brief Struct holding options for settings taken from a key-value * config file. */ typedef struct { gchar *file_name; /**< Filename containing key-value pairs. */ gchar *group_name; /**< Name of the group containing key-value pairs. */ GKeyFile *key_file; /**< GKeyFile object where the file is load. */ } settings_t; void settings_cleanup (settings_t *); /** * @brief Struct holding options to iterate over a GKeyFile. */ typedef struct { gchar **keys; /**< Keys. */ settings_t settings; /**< Settings structure. */ gchar **current_key; /**< Pointer to the current key. */ gchar **last_key; /**< Pointer to the last keys. */ } settings_iterator_t; int init_settings_iterator_from_file (settings_iterator_t *, const gchar *, const gchar *); void cleanup_settings_iterator (settings_iterator_t *); int settings_iterator_next (settings_iterator_t *); const gchar * settings_iterator_name (settings_iterator_t *); const gchar * settings_iterator_value (settings_iterator_t *); #endif /* not _GVM_SETTINGS_H */ gvm-libs-22.20.0/base/strings.c000066400000000000000000000065751477470532200161740ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief String utilities. */ #include "strings.h" #include /* for assert */ #include /* for g_free, g_strconcat, gchar, g_strdup, g_strndup */ #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" /** * @brief Append a string to a string variable. * * When the variable is NULL store a copy of the given string in the variable. * * When the variable already contains a string replace the string with a new * string that is the concatenation of the two, freeing the old string. It is * up to the caller to free the given string if it was dynamically allocated. * * @param[in] var The address of a string variable, that is, a pointer to * a string. * @param[in] string The string to append to the string in the variable. */ void gvm_append_string (gchar **var, const gchar *string) { if (*var) { char *old = *var; *var = g_strconcat (old, string, NULL); g_free (old); } else *var = g_strdup (string); } /** * @brief Append a string of a known length to a string variable. * * When the variable is NULL store a copy of the given string in the variable. * * When the variable already contains a string replace the string with a new * string that is the concatenation of the two, freeing the old string. It is * up to the caller to free the given string if it was dynamically allocated. * * The string must be NULL terminated, and the given length must be the * actual length of the string. * * @param[in] var The address of a string variable, that is, a pointer to * a string. * @param[in] string The string to append to the string in the variable. * @param[in] length The length of string. */ void gvm_append_text (gchar **var, const gchar *string, gsize length) { if (*var) { char *old = *var; *var = g_strconcat (old, string, NULL); g_free (old); } else *var = g_strndup (string, length); } /** * @brief Free a string variable. * * Free the string in the variable and set the variable to NULL. * * @param[in] var The address of a string variable, that is, a pointer to * a string. */ void gvm_free_string_var (gchar **var) { g_free (*var); *var = NULL; } /** * @brief "Strip" space and newline characters from either end of some memory. * * Return the given pointer moved forward past any spaces, replacing the * first of any contiguous spaces at or before the end of the memory with * a terminating NULL. * * This is for use when string points into a static buffers. * * @param[in,out] string The start of the memory. * @param[in] end Pointer to the byte after the end of the memory. * * @return A new pointer into the string. */ char * gvm_strip_space (char *string, char *end) { assert (string <= end); if (string >= end) return string; end--; while (string[0] == ' ' || string[0] == '\n') { string++; if (string >= end) { end[0] = '\0'; return end; } } /* Here string is < end. */ if (end[0] == ' ' || end[0] == '\n') { end--; while (end >= string && (end[0] == ' ' || end[0] == '\n')) { end--; } end[1] = '\0'; } return string; } gvm-libs-22.20.0/base/strings.h000066400000000000000000000006601477470532200161660ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2009-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief String utilities. */ #ifndef _GVM_STRINGS_H #define _GVM_STRINGS_H #include void gvm_append_string (gchar **, const gchar *); void gvm_append_text (gchar **, const gchar *, gsize); void gvm_free_string_var (gchar **); char * gvm_strip_space (char *, char *); #endif /* not _GVM_STRINGS_H */ gvm-libs-22.20.0/base/version.c000066400000000000000000000004341477470532200161540ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "version.h" #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm base" const char * gvm_libs_version (void) { return GVM_LIBS_VERSION; } gvm-libs-22.20.0/base/version.h000066400000000000000000000003631477470532200161620ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief Version utilities. */ #ifndef _GVM_VERSION_H #define _GVM_VERSION_H const char * gvm_libs_version (void); #endif gvm-libs-22.20.0/base/version_tests.c000066400000000000000000000013311477470532200173730ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "version.c" #include #include Describe (version); BeforeEach (version) { } AfterEach (version) { } Ensure (version, gvm_libs_versions_returns_correct_version) { assert_that (strcmp (gvm_libs_version (), GVM_LIBS_VERSION) == 0) } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, version, gvm_libs_versions_returns_correct_version); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/000077500000000000000000000000001477470532200146635ustar00rootroot00000000000000gvm-libs-22.20.0/boreas/CMakeLists.txt000066400000000000000000000130171477470532200174250ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2020-2023 Greenbone AG # # SPDX-License-Identifier: GPL-2.0-or-later include (FindPkgConfig) if (NOT PKG_CONFIG_FOUND) message(FATAL_ERROR "pkg-config executable not found. Aborting.") endif (NOT PKG_CONFIG_FOUND) ## Dependency checks message (STATUS "Looking for libnet...") find_library (NET net) message (STATUS "Looking for net... ${NET}") if (NOT NET) message (SEND_ERROR "The net library is required.") endif (NOT NET) message (STATUS "Looking for libnet-config...") find_program (LIBNET_CONFIG libnet-config) if (LIBNET_CONFIG) message (STATUS "Looking for libnet-config... ${LIBNET_CONFIG}") execute_process (COMMAND libnet-config --libs OUTPUT_VARIABLE LIBNET_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process (COMMAND libnet-config --cflags OUTPUT_VARIABLE LIBNET_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) else (LIBNET_CONFIG) message (STATUS "libnet-config not found, using defaults...") set (LIBNET_LDFLAGS "-L/usr/lib -lnet") set (LIBNET_CFLAGS "-I/usr/include") endif (LIBNET_CONFIG) message (STATUS "Looking for pcap...") find_library (PCAP pcap) message (STATUS "Looking for pcap... ${PCAP}") if (NOT PCAP) message (SEND_ERROR "The pcap library is required.") endif (NOT PCAP) message (STATUS "Looking for pcap-config...") find_program (PCAP_CONFIG pcap-config) if (PCAP_CONFIG) message (STATUS "Looking for pcap-config... ${PCAP_CONFIG}") execute_process (COMMAND pcap-config --libs OUTPUT_VARIABLE PCAP_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) string(STRIP "${PCAP_LDFLAGS}" PCAP_LDFLAGS) execute_process (COMMAND pcap-config --cflags OUTPUT_VARIABLE PCAP_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) else (PCAP_CONFIG) message (STATUS "pcap-config not found, using defaults...") set (PCAP_LDFLAGS "-L/usr/lib -lpcap") set (PCAP_CFLAGS "-I/usr/include") endif (PCAP_CONFIG) find_package (Threads) pkg_check_modules (GLIB REQUIRED glib-2.0>=2.42) include_directories (${GLIB_INCLUDE_DIRS}) set (FILES alivedetection.c arp.c boreas_error.c boreas_io.c cli.c ping.c sniffer.c util.c) set (HEADERS alivedetection.h arp.h boreas_error.h boreas_io.h cli.h ping.h sniffer.h util.h) if (BUILD_STATIC) set (LIBGVM_BOREAS_NAME gvm_boreas_static) add_library (gvm_boreas_static STATIC ${FILES}) set_target_properties (gvm_boreas_static PROPERTIES OUTPUT_NAME "gvm_boreas") set_target_properties (gvm_boreas_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties (gvm_boreas_static PROPERTIES PUBLIC_HEADER "${HEADERS}") endif (BUILD_STATIC) if (BUILD_SHARED) set (LIBGVM_BOREAS_NAME gvm_boreas_shared) add_library (gvm_boreas_shared SHARED ${FILES}) set_target_properties (gvm_boreas_shared PROPERTIES OUTPUT_NAME "gvm_boreas") set_target_properties (gvm_boreas_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1) set_target_properties (gvm_boreas_shared PROPERTIES SOVERSION "${PROJECT_VERSION_MAJOR}") set_target_properties (gvm_boreas_shared PROPERTIES VERSION "${CPACK_PACKAGE_VERSION}") set_target_properties (gvm_boreas_shared PROPERTIES PUBLIC_HEADER "${HEADERS}") target_link_libraries (gvm_boreas_shared LINK_PRIVATE gvm_util_shared ${GLIB_LDFLAGS} ${LIBNET_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) endif (BUILD_SHARED) set (LIBGVM_BOREAS_NAME ${LIBGVM_BOREAS_NAME} PARENT_SCOPE) ## Tests if (BUILD_TESTS) add_unit_test (boreas-alivedetection-test alivedetection_tests.c gvm_boreas_shared gvm_base_shared gvm_util_shared ${GLIB_LDFLAGS} ${PCAP_LDFLAGS} ${LIBNET_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test (boreas-error-test boreas_error_tests.c ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test (boreas-io-test boreas_io_tests.c gvm_boreas_shared gvm_base_shared gvm_util_shared ${PCAP_LDFLAGS} ${LIBNET_LDFLAGS} ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test (boreas-cli-test cli_tests.c gvm_boreas_shared gvm_base_shared gvm_util_shared ${GLIB_LDFLAGS} ${PCAP_LDFLAGS} ${LIBNET_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test (boreas-ping-test ping_tests.c gvm_boreas_shared gvm_base_shared ${GLIB_LDFLAGS} ${PCAP_LDFLAGS} ${LIBNET_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) add_unit_test (boreas-sniffer-test sniffer_tests.c gvm_boreas_shared gvm_base_shared gvm_util_shared ${PCAP_LDFLAGS} ${LIBNET_LDFLAGS} ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) set (UTIL_TEST_LINKER_WRAP_OPTIONS "-Wl,-wrap,socket,-wrap,setsockopt") add_unit_test (util-test util_tests.c gvm_base_shared ${GLIB_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT} ${UTIL_TEST_LINKER_WRAP_OPTIONS}) endif (BUILD_TESTS) ## Install configure_file (libgvm_boreas.pc.in ${CMAKE_BINARY_DIR}/libgvm_boreas.pc @ONLY) install (FILES ${CMAKE_BINARY_DIR}/libgvm_boreas.pc DESTINATION ${LIBDIR}/pkgconfig) if (BUILD_STATIC) install (TARGETS gvm_boreas_static RUNTIME DESTINATION ${BINDIR} ARCHIVE DESTINATION ${LIBDIR} PUBLIC_HEADER DESTINATION "${INCLUDEDIR}/gvm/boreas") endif (BUILD_STATIC) if (BUILD_SHARED) install (TARGETS gvm_boreas_shared RUNTIME DESTINATION ${BINDIR} LIBRARY DESTINATION ${LIBDIR} ARCHIVE DESTINATION ${LIBDIR} PUBLIC_HEADER DESTINATION "${INCLUDEDIR}/gvm/boreas") endif (BUILD_SHARED) ## End gvm-libs-22.20.0/boreas/alivedetection.c000066400000000000000000000456611477470532200200420ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "alivedetection.h" #include "../base/networking.h" /* for validate_port_range(), port_range_ranges() */ #include "../base/prefs.h" /* for prefs_get() */ #include "../util/kb.h" /* for kb_t operations */ #include "boreas_error.h" #include "boreas_io.h" #include "ping.h" #include "sniffer.h" #include "util.h" #include #include #include /* for getifaddrs() */ #include #include /* for if_nametoindex() */ #include #include #include #include #include #include #include /* for sockaddr_ll */ #include #include #include #include #include #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" scanner_t scanner; /** * @brief Scan function starts a sniffing thread which waits for packets to * arrive and sends pings to hosts we want to test. Blocks until Scan is * finished or error occurred. * * Start a sniffer thread. Get what method of alive detection to use. Send * appropriate pings for every host we want to test. * * @return 0 on success, <0 on failure. */ static int scan (alive_test_t alive_test) { int number_of_targets; int number_of_dead_hosts; pthread_t sniffer_thread_id; GHashTableIter target_hosts_iter; gpointer key, value; struct timeval start_time, end_time; int scandb_id; gchar *scan_id; /* Following variables are only relevant if only ICMP was chosen. */ int remaining_batch = 0; int prev_alive = 0; gboolean limit_reached_handled = FALSE; /* Scan restrictions related. */ gettimeofday (&start_time, NULL); number_of_targets = g_hash_table_size (scanner.hosts_data->targethosts); scandb_id = atoi (prefs_get ("ov_maindbid")); scan_id = get_openvas_scan_id (prefs_get ("db_address"), scandb_id); g_message ("Alive scan %s started: Target has %d hosts", scan_id, number_of_targets); /* Check first if consider alive test method is set. In case that * there is no scan restrictions, no other test will be performed, because * it doesn't make sense. * Otherwise, if a scan restriction is set (the max_scan_hosts feature), * the other selected methods must be performed first to fill a list with * alive hosts and not only with the first which we don't now if they are dead * or alive. This will ensure that restricted users will get the max possible * amount of alive hosts before starting to fill the list with dead hosts. */ if (alive_test & ALIVE_TEST_CONSIDER_ALIVE && scanner.scan_restrictions->max_scan_hosts == 0) { g_debug ("%s: Consider Alive", __func__); for (g_hash_table_iter_init (&target_hosts_iter, scanner.hosts_data->targethosts); g_hash_table_iter_next (&target_hosts_iter, &key, &value);) { g_hash_table_add (scanner.hosts_data->alivehosts, g_strdup (key)); handle_scan_restrictions (&scanner, key); } goto finish_alive_test; } /* Sniffer thread needed if any alive test besides ALIVE_TEST_CONSIDER_ALIVE * was chosen. */ if (alive_test != ALIVE_TEST_CONSIDER_ALIVE) { sniffer_thread_id = 0; start_sniffer_thread (&scanner, &sniffer_thread_id); } /* Continuously send dead hosts to ospd if only ICMP was chosen instead of * sending all at once at the end. This is done for displaying a progressbar * that increases gradually. */ if (alive_test == ALIVE_TEST_ICMP) { g_hash_table_iter_init (&target_hosts_iter, scanner.hosts_data->targethosts); int batch = 1000; int curr_alive = 0; prev_alive = 0; /* Number of hosts in last batch. Depending on the total number of hosts * the last batch size maybe be double the normal size. Info about the * last batch is send after all hosts were checked and we waited for last * packets to arrive.*/ remaining_batch = number_of_targets; for (int packets_send = 0; g_hash_table_iter_next (&target_hosts_iter, &key, &value);) { send_icmp (key, value, &scanner); packets_send++; /* Send dead hosts update after batch number of packets were send and * we still have more than batch size packets remaining. */ if (packets_send % batch == 0 && (number_of_targets - packets_send) > batch) { /* The number of dead hosts we have to send to ospd is the batch * size minus the newly found alive hosts. The newly found alive * hosts is the diff between the current total of alive hosts and * the total of the last batch. */ curr_alive = g_hash_table_size (scanner.hosts_data->alivehosts); number_of_dead_hosts = batch - (curr_alive - prev_alive); /* If the max_scan_hosts limit was reached we can not tell ospd * the true number of dead hosts. The number of alive hosts which * are above the max_scan_hosts limit are not to be subtracted * form the dead hosts to send. They are considered as dead hosts * for the progress bar.*/ if (scanner.scan_restrictions->max_scan_hosts_reached) { /* Handle the case where we reach the max_scan_hosts for the * first time. We may have to consider some of the new alive * hosts as dead because of the restriction. E.g * curr_alive=110 prev_alive=90 max_scan_hosts=100 batch=100. * Normally we would send 80 as dead in this batch (20 new * alive hosts) but because of the restriction we send 90 as * dead. The 10 hosts which are over the limit are considered * as dead. * After this limit case was handled we just always send the * complete batch as dead hosts.*/ if (!limit_reached_handled) { /* Number of alive hosts until limit was reached. */ int last_hosts_considered_as_alive = scanner.scan_restrictions->max_scan_hosts - prev_alive; number_of_dead_hosts = batch - last_hosts_considered_as_alive; send_dead_hosts_to_ospd_openvas (number_of_dead_hosts); remaining_batch -= batch; limit_reached_handled = TRUE; } else { send_dead_hosts_to_ospd_openvas (batch); remaining_batch -= batch; } } else { send_dead_hosts_to_ospd_openvas (number_of_dead_hosts); remaining_batch -= batch; } prev_alive = curr_alive; } } } else if (alive_test & ALIVE_TEST_ICMP) { g_debug ("%s: ICMP Ping", __func__); g_hash_table_foreach (scanner.hosts_data->targethosts, send_icmp, &scanner); wait_until_so_sndbuf_empty (scanner.icmpv4soc, 10); wait_until_so_sndbuf_empty (scanner.icmpv6soc, 10); usleep (500000); } if (alive_test & ALIVE_TEST_TCP_SYN_SERVICE) { g_debug ("%s: TCP-SYN Service Ping", __func__); scanner.tcp_flag = TH_SYN; /* SYN */ g_hash_table_foreach (scanner.hosts_data->targethosts, send_tcp, &scanner); wait_until_so_sndbuf_empty (scanner.tcpv4soc, 10); wait_until_so_sndbuf_empty (scanner.tcpv6soc, 10); usleep (500000); } if (alive_test & ALIVE_TEST_TCP_ACK_SERVICE) { g_debug ("%s: TCP-ACK Service Ping", __func__); scanner.tcp_flag = TH_ACK; /* ACK */ g_hash_table_foreach (scanner.hosts_data->targethosts, send_tcp, &scanner); wait_until_so_sndbuf_empty (scanner.tcpv4soc, 10); wait_until_so_sndbuf_empty (scanner.tcpv6soc, 10); usleep (500000); } if (alive_test & ALIVE_TEST_ARP) { g_debug ("%s: ARP Ping", __func__); g_hash_table_foreach (scanner.hosts_data->targethosts, send_arp, &scanner); wait_until_so_sndbuf_empty (scanner.arpv4soc, 10); wait_until_so_sndbuf_empty (scanner.arpv6soc, 10); } if (alive_test & ALIVE_TEST_CONSIDER_ALIVE) { g_debug ("%s: Consider Alive", __func__); for (g_hash_table_iter_init (&target_hosts_iter, scanner.hosts_data->targethosts); g_hash_table_iter_next (&target_hosts_iter, &key, &value);) { g_hash_table_add (scanner.hosts_data->alivehosts, g_strdup (key)); handle_scan_restrictions (&scanner, key); } } /* Stop sniffer thread if any alive test besides ALIVE_TEST_CONSIDER_ALIVE was * chosen. */ if (alive_test != ALIVE_TEST_CONSIDER_ALIVE) { g_debug ( "%s: all ping packets have been sent, wait a bit for rest of replies.", __func__); for (unsigned int i = 0; i < get_alive_test_wait_timeout (); i++) { if (number_of_targets == (int) g_hash_table_size (scanner.hosts_data->alivehosts)) break; sleep (1); // 1 second is the minimum wait time } stop_sniffer_thread (&scanner, sniffer_thread_id); } finish_alive_test: /* If only ICMP was specified we continuously send updates about dead hosts to * ospd while checking the hosts. We now only have to send the dead hosts of * the last batch. This is done here to catch the last alive hosts which may * have arrived after all packets were already sent. * Else send total number of dead host at once.*/ if (alive_test == ALIVE_TEST_ICMP) { if (scanner.scan_restrictions->max_scan_hosts_reached) { /* We reached the max_scan_host limit in the last batch. For detailed * description look at the first time where limit_reached_handled is * used.*/ if (!limit_reached_handled) { /* Number of alive hosts until limit was reached. */ int last_hosts_considered_as_alive = scanner.scan_restrictions->max_scan_hosts - prev_alive; number_of_dead_hosts = remaining_batch - last_hosts_considered_as_alive; send_dead_hosts_to_ospd_openvas (number_of_dead_hosts); } else { send_dead_hosts_to_ospd_openvas (remaining_batch); } } else { int curr_alive = g_hash_table_size (scanner.hosts_data->alivehosts); number_of_dead_hosts = remaining_batch - (curr_alive - prev_alive); send_dead_hosts_to_ospd_openvas (number_of_dead_hosts); } } else { number_of_dead_hosts = number_of_targets - g_hash_table_size (scanner.hosts_data->alivehosts); /* Send number of dead hosts to ospd-openvas. We need to consider the scan * restrictions.*/ if (scanner.scan_restrictions->max_scan_hosts_reached) send_dead_hosts_to_ospd_openvas ( number_of_targets - scanner.scan_restrictions->max_scan_hosts); else send_dead_hosts_to_ospd_openvas (number_of_dead_hosts); } gettimeofday (&end_time, NULL); g_message ("Alive scan %s finished in %ld seconds: %d alive hosts of %d.", scan_id, end_time.tv_sec - start_time.tv_sec, g_hash_table_size (scanner.hosts_data->alivehosts), number_of_targets); g_free (scan_id); return 0; } /** * @brief Initialise the alive detection scanner. * * Fill scanner struct with appropriate values. * * @param hosts gvm_hosts_t list of hosts to alive test. * @param alive_test methods to use for alive detection. * * @return 0 on success, boreas_error_t on error. */ static boreas_error_t alive_detection_init (gvm_hosts_t *hosts, alive_test_t alive_test) { g_debug ("%s: Initialise alive scanner. ", __func__); /* Used for ports array initialisation. */ const gchar *port_list = NULL; GPtrArray *portranges_array = NULL; boreas_error_t error = NO_ERROR; /* Scanner */ /* Sockets */ error = set_all_needed_sockets (&scanner, alive_test); if (error != 0) return error; /* Do not print results in stdout. Only set for command line clients*/ scanner.print_results = 0; /* kb_t redis connection */ int scandb_id = atoi (prefs_get ("ov_maindbid")); scanner.main_kb = kb_direct_conn (prefs_get ("db_address"), scandb_id); if (scanner.main_kb == NULL) return -7; /* TODO: pcap handle */ // scanner.pcap_handle = open_live (NULL, FILTER_STR); // scanner.pcap_handle = NULL; /* is set in ping function */ /* Results data */ /* hashtables */ scanner.hosts_data = g_malloc0 (sizeof (hosts_data_t)); scanner.hosts_data->alivehosts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); scanner.hosts_data->targethosts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* put all hosts we want to check in hashtable */ gvm_host_t *host; for (host = gvm_hosts_next (hosts); host; host = gvm_hosts_next (hosts)) { g_hash_table_insert (scanner.hosts_data->targethosts, gvm_host_value_str (host), host); } /* reset hosts iter */ hosts->current = 0; /* Init ports used for scanning. */ scanner.ports = NULL; port_list = get_alive_test_ports (); if (NULL == port_list) port_list = DEFAULT_PORT_LIST; if (validate_port_range (port_list)) { g_warning ("%s: Invalid port range supplied for alive detection module. " "Using global port range instead.", __func__); /* This port list is also used by openvas for scanning and was already * validated by openvas so we don't do it here again. */ port_list = prefs_get ("port_range"); } /* Use uint16_t for port array elements. tcphdr port type is uint16_t. */ scanner.ports = g_array_new (FALSE, TRUE, sizeof (uint16_t)); if (port_list) portranges_array = port_range_ranges (port_list); else g_warning ( "%s: Port list supplied by user is empty. Alive detection may not find " "any alive hosts when using TCP ACK/SYN scanning methods. ", __func__); /* Fill ports array with ports from the ranges. Duplicate ports are not * removed. */ g_ptr_array_foreach (portranges_array, fill_ports_array, scanner.ports); array_free (portranges_array); /* Scan restrictions. max_scan_hosts related. */ const gchar *pref_str; int max_scan_hosts = INT_MAX, pref_value; /* Check that the max_scan_hosts is set and it is greater than 0 */ pref_str = prefs_get ("max_scan_hosts"); if (pref_str != NULL) { pref_value = atoi (pref_str); if (pref_value > 0) max_scan_hosts = pref_value; else g_debug ("%s: Invalid max_scan_hosts value. It must be an integer " "greater than zero.", __func__); } init_scan_restrictions (&scanner, max_scan_hosts); g_debug ("%s: Initialisation of alive scanner finished.", __func__); return error; } /** * @brief Free all the data used by the alive detection scanner. * * @param[out] error Set to 0 on success, boreas_error_t on error. */ static void alive_detection_free (void *error) { boreas_error_t alive_test_err; boreas_error_t close_err; boreas_error_t error_out; alive_test_t alive_test; error_out = NO_ERROR; alive_test_err = get_alive_test_methods (&alive_test); if (alive_test_err) { g_warning ("%s: %s. Could not get info about which sockets to close.", __func__, str_boreas_error (alive_test_err)); error_out = BOREAS_CLEANUP_ERROR; } else { close_err = close_all_needed_sockets (&scanner, alive_test); if (close_err) error_out = BOREAS_CLEANUP_ERROR; } /*pcap_close (scanner.pcap_handle); //pcap_handle is closed in ping/scan * function for now */ if ((kb_lnk_reset (scanner.main_kb)) != 0) { g_warning ("%s: error in kb_lnk_reset()", __func__); error_out = BOREAS_CLEANUP_ERROR; } /* Ports array. */ g_array_free (scanner.ports, TRUE); g_hash_table_destroy (scanner.hosts_data->alivehosts); /* targethosts: (ipstr, gvm_host_t *) * gvm_host_t are freed by caller of start_alive_detection()! */ g_hash_table_destroy (scanner.hosts_data->targethosts); g_free (scanner.hosts_data); /* Set error. */ *(boreas_error_t *) error = error_out; } /** * @brief Start the scan of all specified hosts in gvm_hosts_t * list. Finish signal is put on Queue if scan is finished or an error occurred. * * @param hosts_to_test gvm_hosts_t list of hosts to alive test. which is to be * freed by caller. */ void * start_alive_detection (void *hosts_to_test) { boreas_error_t init_err; boreas_error_t alive_test_err; boreas_error_t fin_err; boreas_error_t free_err; gvm_hosts_t *hosts; alive_test_t alive_test; alive_test_err = get_alive_test_methods (&alive_test); if (alive_test_err != 0) { g_warning ("%s: %s. Exit Boreas.", __func__, str_boreas_error (alive_test_err)); put_finish_signal_on_queue (&fin_err); if (fin_err) g_warning ("%s: Could not put finish signal on Queue. Openvas needs to " "be stopped manually. ", __func__); pthread_exit (0); } hosts = (gvm_hosts_t *) hosts_to_test; init_err = alive_detection_init (hosts, alive_test); if (init_err != 0) { g_warning ( "%s. Boreas could not initialise alive detection. %s. Exit Boreas.", __func__, str_boreas_error (init_err)); put_finish_signal_on_queue (&fin_err); if (fin_err) g_warning ("%s: Could not put finish signal on Queue. Openvas needs to " "be stopped manually. ", __func__); pthread_exit (0); } /* If alive detection thread returns, is canceled or killed unexpectedly all * used resources are freed and sockets, connections closed.*/ pthread_cleanup_push (alive_detection_free, &free_err); /* If alive detection thread returns, is canceled or killed unexpectedly a * finish signal is put on the queue for openvas to process.*/ pthread_cleanup_push (put_finish_signal_on_queue, &fin_err); /* Start the scan. */ if (scan (alive_test) < 0) g_warning ("%s: error in scan()", __func__); /* Put finish signal on queue. */ pthread_cleanup_pop (1); /* Free memory, close sockets and connections. */ pthread_cleanup_pop (1); if (free_err) g_warning ("%s: %s. Exit Boreas thread nonetheless.", __func__, str_boreas_error (free_err)); pthread_exit (0); } gvm-libs-22.20.0/boreas/alivedetection.h000066400000000000000000000063171477470532200200420ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef ALIVE_DETECTION_H #define ALIVE_DETECTION_H #include "../base/hosts.h" #include "../util/kb.h" #include /* to how many hosts are packets send to at a time. value <= 0 for no rate limit */ #define BURST 100 /* how long (in microseconds) to wait until new BURST of packets is send */ #define BURST_TIMEOUT 100000 /* Src port of outgoing TCP pings. Used for filtering incoming packets. */ #define FILTER_PORT 9910 /* Default port list */ #define DEFAULT_PORT_LIST \ "21-23,25,53,80,110-111,135,139,143,443,445," \ "993,995,1723,3306,3389,5900,8080" /* Redis related */ /* Queue (Redis list) for communicating with openvas main process. */ #define ALIVE_DETECTION_QUEUE "alive_detection" /* Signal to put on ALIVE_DETECTION_QUEUE if alive detection finished. */ #define ALIVE_DETECTION_FINISHED "alive_detection_finished" void * start_alive_detection (void *); typedef struct hosts_data hosts_data_t; typedef struct scan_restrictions scan_restrictions_t; /** * @brief The scanner struct holds data which is used frequently by the alive * detection thread. */ struct scanner { /* sockets */ int tcpv4soc; int tcpv6soc; int icmpv4soc; int icmpv6soc; int arpv4soc; int arpv6soc; /* UDP socket needed for getting the source IP for the TCP header. */ int udpv4soc; int udpv6soc; /* TH_SYN or TH_ACK */ uint8_t tcp_flag; /* ports used for TCP ACK/SYN */ GArray *ports; /* redis connection */ kb_t main_kb; /* pcap handle */ pcap_t *pcap_handle; hosts_data_t *hosts_data; scan_restrictions_t *scan_restrictions; /* 0 do not print in stdout, 1 print in stdout used for cmd line cli. */ int print_results; }; typedef struct scanner scanner_t; /** * @brief The hosts_data struct holds the alive hosts and target hosts in * separate hashtables. */ struct hosts_data { /* Set of the form (ip_str, ip_str). * Target hosts which were detected as alive. */ GHashTable *alivehosts; /* Hashtable of the form (ip_str, gvm_host_t *). The gvm_host_t pointers point * to hosts which are to be freed by the caller of start_alive_detection(). */ GHashTable *targethosts; }; /* Max_scan_hosts related struct. */ struct scan_restrictions { /* Maximum number of hosts allowed to be scanned. No more alive hosts are put * on the queue after max_scan_hosts number of alive hosts is reached. * max_scan_hosts_reached is set to true and the finish signal is put on the * queue if max_scan_hosts is reached. */ int max_scan_hosts; /* Count of unique identified alive hosts. */ int alive_hosts_count; gboolean max_scan_hosts_reached; }; /** * @brief Alive tests. * * These numbers are used in the database by gvmd, so if the number associated * with any symbol changes in gvmd we need to change them here too. */ typedef enum { ALIVE_TEST_TCP_ACK_SERVICE = 1, ALIVE_TEST_ICMP = 2, ALIVE_TEST_ARP = 4, ALIVE_TEST_CONSIDER_ALIVE = 8, ALIVE_TEST_TCP_SYN_SERVICE = 16 } alive_test_t; /** * @brief Type of socket. */ typedef enum { TCPV4, TCPV6, ICMPV4, ICMPV6, ARPV4, ARPV6, UDPV4, UDPV6, } socket_type_t; #endif /* not ALIVE_DETECTION_H */ gvm-libs-22.20.0/boreas/alivedetection_tests.c000066400000000000000000000012141477470532200212460ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "alivedetection.c" #include #include Describe (alivedetection); BeforeEach (alivedetection) { } AfterEach (alivedetection) { } Ensure (alivedetection, dummy_test) { assert_that (0, is_equal_to (0)); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, alivedetection, dummy_test); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/arp.c000066400000000000000000000223431477470532200156150ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2021-2023 Greenbone AG * SPDX-FileCopyrightText: 2000 Thomas Habets * * SPDX-License-Identifier: GPL-2.0-or-later */ /** * @file * @brief implementation of arp ping. * * Most of the functions are modified versions of functions found in * https://github.com/ThomasHabets/arping/tree/arping-2.19/src. */ #include "arp.h" #include "../base/networking.h" /* for gvm_source_addr() */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IP_ALEN #define IP_ALEN 4 #endif #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" static libnet_t *libnet = 0; static uint32_t dstip; /* target IP */ static uint8_t dstmac[ETH_ALEN]; /* ethxmas */ /* autodetected, overridden by gvm_source_addr if openvas source_iface was set*/ static uint32_t srcip; static uint8_t srcmac[ETH_ALEN]; /* autodetected */ static const uint8_t ethnull[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; static const uint8_t ethxmas[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const char *ip_broadcast = "255.255.255.255"; /** * @brief Strip newline at end of string. * * Some Libnet error messages end with a newline. Strip that in place. * * @param s String to strip newline from. */ static void strip_newline (char *s) { size_t n; for (n = strlen (s); n && (s[n - 1] == '\n'); --n) { s[n - 1] = 0; } } /** * @brief Init libnet. * * Init libnet with specified ifname. Destroy if already inited. * If this function retries with different parameter it will preserve * the original error message and print that. * Call with recursive=0. * * @param ifname Interface name to use * @param recursive Only used inside do_libnet_init. Use 0. * * @return -1 on failure, 0 on success. */ static int do_libnet_init (const char *ifname, int recursive) { char ebuf[LIBNET_ERRBUF_SIZE]; ebuf[0] = 0; if (libnet) { /* Probably going to switch interface from temp to real. */ libnet_destroy (libnet); libnet = 0; } /* Try libnet_init() even though we aren't root. We may have * a capability or something. */ if (!(libnet = libnet_init (LIBNET_LINK, (char *) ifname, ebuf))) { strip_newline (ebuf); if (!ifname) { /* Sometimes libnet guesses an interface that it then * can't use. Work around that by attempting to * use "lo". */ do_libnet_init ("lo", 1); if (libnet != NULL) { return 0; } } else if (recursive) { /* Continue original execution to get that * error message. */ return 0; } g_debug ("%s: libnet_init(LIBNET_LINK, %s): %s", __func__, ifname ? ifname : "", ebuf); if (getuid () && geteuid ()) { g_warning ("%s: you may need to run as root", __func__); } return -1; } return 0; } /** * @brief Resolve address. * * @param[in] l libnet_t. * @param[in] name IP string or addr name. * @param[out] addr Resolved ipv4 addr. * * @return 1 on success, 0 on failure. */ static int xresolve (libnet_t *l, const char *name, int r, uint32_t *addr) { if (!strcmp (ip_broadcast, name)) { *addr = 0xffffffff; return 1; } *addr = libnet_name2addr4 (l, (char *) name, r); return *addr != 0xffffffff; } /** * @brief Format a MAC address to human readable format. * * @param[in] mac MAC to format. * @param[in] buf Buffer to store formatted MAC in. * @param[in] bufze Size of Buffer. * * @return Formatted MAC string stored in buf. */ static char * format_mac (const unsigned char *mac, char *buf, size_t bufsize) { snprintf (buf, bufsize, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return buf; } /** * @brief Send ARP who-has. */ static void pingip_send () { libnet_ptag_t arp = 0, eth = 0; // Padding size chosen fairly arbitrarily. // Without this padding some systems (e.g. Raspberry Pi 3 // wireless interface) failed. dmesg said: // arping: packet size is too short (42 <= 50) const uint8_t padding[16] = {0}; if (-1 == (libnet_build_arp (ARPHRD_ETHER, ETHERTYPE_IP, ETH_ALEN, IP_ALEN, ARPOP_REQUEST, srcmac, (uint8_t *) &srcip, (uint8_t *) ethnull, (uint8_t *) &dstip, padding, sizeof padding, libnet, arp))) { g_warning ("%s: libnet_build_arp(): %s", __func__, libnet_geterror (libnet)); } eth = libnet_build_ethernet (dstmac, srcmac, ETHERTYPE_ARP, NULL, // payload 0, // payload size libnet, eth); if (-1 == eth) { g_warning ("%s: %s: %s", __func__, "libnet_build_ethernet()", libnet_geterror (libnet)); } if (-1 == libnet_write (libnet)) { g_warning ("%s: libnet_write(): %s", __func__, libnet_geterror (libnet)); } } /** * @brief Send arp ping using libnet. * * @param dst Destination address as string. * */ void send_arp_v4 (const char *dst_str) { char ebuf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE]; char *cp; char *ifname = NULL; char *target = NULL; char mac_debug_buf[128]; char pcap_ebuf[PCAP_ERRBUF_SIZE]; pcap_if_t *alldevsp = NULL; /* default interface when no interface is found via arp_lookupdev() */ static char ifname_default[IF_NAMESIZE] = {0}; /* interface used for previous ping */ static char ifname_prev[IF_NAMESIZE] = {0}; ebuf[0] = 0; /* set globals */ srcip = 0; dstip = 0xffffffff; memcpy (dstmac, ethxmas, ETH_ALEN); /* set src IP if we have global openvas src ip */ gvm_source_addr (&srcip); /* init libnet if not already done */ if (NULL == libnet) { do_libnet_init (ifname, 0); } /* init default interface if not already done */ if (!*ifname_default) { if (pcap_findalldevs (&alldevsp, pcap_ebuf) < 0) g_message ("%s: Error pcap_findalldevs(): %s", __func__, pcap_ebuf); if (alldevsp != NULL) { memcpy (ifname_default, alldevsp->name, IF_NAMESIZE); pcap_freealldevs (alldevsp); } } /* Make sure dstip and dst_str like each other */ if (!xresolve (libnet, dst_str, LIBNET_DONT_RESOLVE, &dstip)) { g_warning ("%s: Can't resolve %s. No ARP ping done for this addr.", __func__, dst_str); return; } target = g_strdup (libnet_addr2name4 (dstip, 0)); /* Get some good iface. */ if (!ifname) { struct sockaddr_storage target_addr; struct sockaddr_in sin_dst; sin_dst.sin_family = AF_INET; sin_dst.sin_addr.s_addr = dstip; memcpy (&target_addr, &sin_dst, sizeof (sin_dst)); ifname = gvm_get_outgoing_iface (&target_addr); strip_newline (ebuf); if (!ifname) { g_debug ("%s: %s Trying to use guessed interface instead.", __func__, ebuf); } if (!ifname) { /* Only set ifname if ifname_default str is not empty. */ if (*ifname_default) ifname = g_strdup (ifname_default); } if (!ifname) { g_warning ("%s: Gave up looking for interface" " to use: %s. Address '%s' will be skipped.", __func__, ebuf, target); g_free (target); return; } /* check for other probably-not interfaces */ if (!strcmp (ifname, "ipsec") || !strcmp (ifname, "lo")) { g_warning ("%s: %s looks like the wrong " "interface to use. Using it anyway this time.", __func__, ifname); } } /* * Init libnet again if the interface is not the same as the previously used * one. */ if (!*ifname_prev || 0 != g_strcmp0 (ifname, ifname_prev)) { memcpy (ifname_prev, ifname, IF_NAMESIZE); do_libnet_init (ifname, 0); } if (!(cp = (char *) libnet_get_hwaddr (libnet))) { g_warning ("%s: libnet_get_hwaddr(): %s. Address '%s' will be skipped.", __func__, libnet_geterror (libnet), target); g_free (target); g_free (ifname); return; } memcpy (srcmac, cp, ETH_ALEN); if (srcip == INADDR_ANY) { srcip = libnet_get_ipaddr4 (libnet); if ((uint32_t) -1 == srcip) { g_warning ("%s: Unable to get the IPv4 address of default " "interface %s: %s. Address '%s' will be skipped.", __func__, ifname, libnet_geterror (libnet), target); g_free (target); g_free (ifname); return; } } g_debug ("%s: Ping %s Interface: %s Src IP: %s Src MAC: %s", __func__, dst_str, ifname, libnet_addr2name4 (libnet_get_ipaddr4 (libnet), 0), format_mac (srcmac, mac_debug_buf, sizeof (mac_debug_buf))); pingip_send (); libnet_clear_packet (libnet); g_free (target); g_free (ifname); } gvm-libs-22.20.0/boreas/arp.h000066400000000000000000000002751477470532200156220ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2021-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef ARP_H #define ARP_H void send_arp_v4 (const char *); #endif /* not ARP_H */ gvm-libs-22.20.0/boreas/boreas_error.c000066400000000000000000000024621477470532200175170ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "boreas_error.h" #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" /** * @brief Transform Boreas error code into human readable error message. * * @param boreas_error Boreas error code. * * @return String representation of supplied error code. */ const char * str_boreas_error (boreas_error_t boreas_error) { const gchar *msg; msg = NULL; switch (boreas_error) { case BOREAS_OPENING_SOCKET_FAILED: msg = "Boreas was not able to open a new socket"; break; case BOREAS_SETTING_SOCKET_OPTION_FAILED: msg = "Boreas was not able to set socket option for socket"; break; case BOREAS_NO_VALID_ALIVE_TEST_SPECIFIED: msg = "No valid alive detection method was specified for Boreas by the user"; break; case BOREAS_CLEANUP_ERROR: msg = "Boreas encountered an error during clean up."; break; case BOREAS_NO_SRC_ADDR_FOUND: msg = "Boreas was not able to determine a source address for the given " "destination."; break; case NO_ERROR: msg = "No error was encountered by Boreas"; break; default: break; } return msg; } gvm-libs-22.20.0/boreas/boreas_error.h000066400000000000000000000007611477470532200175240ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef BOREAS_ERROR_H #define BOREAS_ERROR_H /** * @brief Alive detection error codes. */ typedef enum { BOREAS_OPENING_SOCKET_FAILED = -100, BOREAS_SETTING_SOCKET_OPTION_FAILED, BOREAS_NO_VALID_ALIVE_TEST_SPECIFIED, BOREAS_CLEANUP_ERROR, BOREAS_NO_SRC_ADDR_FOUND, NO_ERROR = 0, } boreas_error_t; const char *str_boreas_error (boreas_error_t); #endif /* not BOREAS_ERROR_H */ gvm-libs-22.20.0/boreas/boreas_error_tests.c000066400000000000000000000012001477470532200207260ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "boreas_error.c" #include #include Describe (boreas_error); BeforeEach (boreas_error) { } AfterEach (boreas_error) { } Ensure (boreas_error, dummy_test) { assert_that (0, is_equal_to (0)); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, boreas_error, dummy_test); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/boreas_io.c000066400000000000000000000333311477470532200167740ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "boreas_io.h" #include "../base/prefs.h" /* for prefs_get() */ #include "alivedetection.h" #include "util.h" #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" /* how long (in sec) to wait for replies after last packet was sent */ #define WAIT_FOR_REPLIES_TIMEOUT 3 scan_restrictions_t scan_restrictions; /** * @brief Check if max_scan_hosts alive hosts reached. * * @return TRUE if max_scan_hosts alive hosts reached, else FALSE. */ static gboolean max_scan_hosts_reached () { return scan_restrictions.max_scan_hosts_reached; } /** * @brief Set max_scan_hosts_reached to TRUE. */ static void set_max_scan_hosts_reached () { scan_restrictions.max_scan_hosts_reached = TRUE; } /** * @brief Get number of identified alive hosts. * * @return Number of identified alive hosts. * */ int get_alive_hosts_count () { return scan_restrictions.alive_hosts_count; } /** * @brief Get set number of maximum alive hosts to be scanned. * * @return Number of maximum alive hosts to be scanned. */ static int get_max_scan_hosts () { return scan_restrictions.max_scan_hosts; } /** * @brief Increment the number of alive hosts by one. */ static void inc_alive_hosts_count () { scan_restrictions.alive_hosts_count++; return; } /** * @brief Send Message about not vuln scanned alive hosts to ospd-openvas. * * @param num_not_scanned Number of alive hosts which were not vuln scanned. * @return 0 on success, else Error. */ static int send_limit_msg (int num_not_scanned_hosts) { int err; int dbid; kb_t main_kb = NULL; err = 0; if (num_not_scanned_hosts < 0) return -1; dbid = atoi (prefs_get ("ov_maindbid")); main_kb = kb_direct_conn (prefs_get ("db_address"), dbid); if (main_kb) { char buf[256]; g_snprintf (buf, 256, "ERRMSG||| ||| ||| ||| |||Maximum number of allowed scans " "reached. There may still be alive hosts available which are " "not scanned. Number of alive hosts not scanned: [%d]", num_not_scanned_hosts); if (kb_item_push_str (main_kb, "internal/results", buf) != 0) { g_warning ("%s: kb_item_push_str() failed to push " "error message.", __func__); err = -2; } kb_lnk_reset (main_kb); } else { g_warning ("%s: Boreas was unable to connect to the Redis db.Info about " "number of alive hosts could not be sent.", __func__); err = -3; } return err; } /** * @brief Get new host from alive detection scanner. * * Check if an alive host was found by the alive detection scanner. If an alive * host is found it is packed into a gvm_host_t and returned. If no host was * found or an error occurred NULL is returned. If alive detection finished * scanning all hosts, NULL is returned and the status flag * alive_detection_finished is set to TRUE. * * @param alive_hosts_kb Redis connection for accessing the queue on which the * alive detection scanner puts found hosts. * @param alive_deteciton_finished Status of alive detection process. * @return If valid alive host is found return a gvm_host_t. If alive scanner * finished NULL is returened and alive_deteciton_finished set. On error or if * no host was found return NULL. */ gvm_host_t * get_host_from_queue (kb_t alive_hosts_kb, gboolean *alive_deteciton_finished) { /* redis connection not established yet */ if (!alive_hosts_kb) { g_debug ("%s: connection to redis is not valid", __func__); return NULL; } /* string representation of an ip address or ALIVE_DETECTION_FINISHED */ gchar *host_str = NULL; /* complete host to be returned */ gvm_host_t *host = NULL; /* try to get item from db, string needs to be freed, NULL on empty or * error */ host_str = kb_item_pop_str (alive_hosts_kb, (ALIVE_DETECTION_QUEUE)); if (!host_str) { return NULL; } /* got some string from redis queue */ else { /* check for finish signal/string */ if (g_strcmp0 (host_str, ALIVE_DETECTION_FINISHED) == 0) { /* Send Error message if max_scan_hosts was reached. */ if (max_scan_hosts_reached ()) { int num_not_scanned_hosts; num_not_scanned_hosts = get_alive_hosts_count () - get_max_scan_hosts (); if (0 != num_not_scanned_hosts) { send_limit_msg (num_not_scanned_hosts); } } g_debug ("%s: Boreas already finished scanning and we reached the " "end of the Queue of alive hosts.", __func__); g_free (host_str); *alive_deteciton_finished = TRUE; return NULL; } /* probably got host */ else { host = gvm_host_from_str (host_str); if (!host) { g_warning ("%s: Could not transform IP string \"%s\" into " "internal representation.", __func__, host_str); g_free (host_str); return NULL; } else { g_free (host_str); return host; } } } } /** * @brief Put host value string on queue of hosts to be considered as alive. * * @param kb KB to use. * @param addr_str IP addr in str representation to put on queue. */ void put_host_on_queue (kb_t kb, char *addr_str) { if (kb_item_push_str (kb, ALIVE_DETECTION_QUEUE, addr_str) != 0) g_debug ("%s: kb_item_push_str() failed. Could not push \"%s\" on queue of " "hosts to be considered as alive.", __func__, addr_str); } /** * @brief Checks if the finish signal is already set. * * @param main_kb kb to use * @return 1 if it is already set. 0 otherwise. */ int finish_signal_on_queue (kb_t main_kb) { static gboolean fin_msg_already_on_queue = FALSE; struct kb_item *queue_items = NULL; int ret = 0; if (fin_msg_already_on_queue) return 1; /* Check if it was already set through the whole items under the key. If so, set the static variable to avoid querying redis unnecessarily. */ queue_items = kb_item_get_all (main_kb, ALIVE_DETECTION_QUEUE); if (queue_items) { while (queue_items) { if (!g_strcmp0 (queue_items->v_str, ALIVE_DETECTION_FINISHED)) { fin_msg_already_on_queue = TRUE; ret = 1; } queue_items = queue_items->next; } kb_item_free (queue_items); } return ret; } /** * @brief Reallocate finish signal in last position of the alive detection * queue. * * @param main_kb kb to use */ void realloc_finish_signal_on_queue (kb_t main_kb) { int kb_item_push_str_err, pos; /* The alive test queue is a FIFO queue. Alive hosts are taken from the * right side of the queue. Therefore the finish signal is put in the * left end of queue, being the last item to be fetch.*/ pos = 1; kb_item_push_str_err = kb_item_add_str_unique ( main_kb, ALIVE_DETECTION_QUEUE, ALIVE_DETECTION_FINISHED, 0, pos); if (kb_item_push_str_err) g_debug ("%s: Could not push the Boreas finish signal on the alive " "detection Queue.", __func__); } /** * @brief Put finish signal on alive detection queue. * * If the finish signal (a string) was already put on the queue it is not put on * it again. * * @param error Set to 0 on success. Is set to -1 if finish signal was already * put on queue. Set to -2 if function was no able to push finish string on * queue. */ void put_finish_signal_on_queue (void *error) { static gboolean fin_msg_already_on_queue = FALSE; boreas_error_t error_out; int kb_item_push_str_err; error_out = NO_ERROR; if (fin_msg_already_on_queue) { g_debug ("%s: Finish signal was already put on queue.", __func__); error_out = -1; } else { kb_t main_kb; int scandb_id; scandb_id = atoi (prefs_get ("ov_maindbid")); main_kb = kb_direct_conn (prefs_get ("db_address"), scandb_id); kb_item_push_str_err = kb_item_push_str (main_kb, ALIVE_DETECTION_QUEUE, ALIVE_DETECTION_FINISHED); if (kb_item_push_str_err) { g_debug ("%s: Could not push the Boreas finish signal on the alive " "detection Queue.", __func__); error_out = -2; } else fin_msg_already_on_queue = TRUE; if ((kb_lnk_reset (main_kb)) != 0) { g_warning ("%s: error in kb_lnk_reset()", __func__); error_out = -3; } } /* Set error. */ *(boreas_error_t *) error = error_out; } /** * @brief Init scan restrictions. * * @param scanner Pointer to scanner struct. * @param max_scan_hosts Maximum number of hosts allowed to scan. 0 equals no * scan limit. */ void init_scan_restrictions (scanner_t *scanner, int max_scan_hosts) { scan_restrictions.alive_hosts_count = 0; scan_restrictions.max_scan_hosts_reached = FALSE; scan_restrictions.max_scan_hosts = max_scan_hosts; scanner->scan_restrictions = &scan_restrictions; return; } /** * @brief Handle restrictions imposed by max_scan_hosts. * * Put host address string on alive detection queue if max_scan_hosts was not * reached already. If max_scan_hosts was reached only count alive hosts and * don't put them on the queue. Put finish signal on queue if max_scan_hosts is * reached. * * @param scanner Scanner struct. * @param add_str Host address string to put on queue. */ void handle_scan_restrictions (scanner_t *scanner, gchar *addr_str) { kb_t kb = scanner->main_kb; inc_alive_hosts_count (); /* Put alive hosts on queue as long as max_scan_hosts not reached. */ if (!max_scan_hosts_reached ()) { /* Print host on command line if no kb is available. No kb available could * mean that boreas is used as commandline tool.*/ if (kb != NULL) put_host_on_queue (kb, addr_str); else { if (scanner->print_results == 1) g_printf ("%s\n", addr_str); } } /* Set max_scan_hosts_reached if not already set and max_scan_hosts was * reached. */ if (!max_scan_hosts_reached () && (get_alive_hosts_count () == get_max_scan_hosts ())) { set_max_scan_hosts_reached (); } } /** * @brief Send the number of dead hosts to ospd-openvas. * * This information is needed for the calculation of the progress bar for gsa in * ospd-openvas. The number of dead hosts sent to ospd-openvas may not * necessarily reflect the actual number of dead hosts in the target list. * * @param hosts_data Includes all data which is needed for calculating the * number of dead hosts. * * @return number of dead hosts, or -1 in case of an error. */ void send_dead_hosts_to_ospd_openvas (int count_dead_hosts) { kb_t main_kb; int maindbid; char dead_host_msg_to_ospd_openvas[2048]; maindbid = atoi (prefs_get ("ov_maindbid")); main_kb = kb_direct_conn (prefs_get ("db_address"), maindbid); if (!main_kb) { g_debug ("%s: Could not connect to main_kb for sending dead hosts to " "ospd-openvas.", __func__); } snprintf (dead_host_msg_to_ospd_openvas, sizeof (dead_host_msg_to_ospd_openvas), "DEADHOST||| ||| ||| ||| |||%d", count_dead_hosts); kb_item_push_str (main_kb, "internal/results", dead_host_msg_to_ospd_openvas); kb_lnk_reset (main_kb); } /** * @brief Get the openvas scan id of the current task. * * @param db_address Address of the Redis db. * @param db_id ID of the scan main db. * * @return Scan id of current task or NULL on error. */ gchar * get_openvas_scan_id (const gchar *db_address, int db_id) { kb_t main_kb; gchar *scan_id; main_kb = kb_direct_conn (db_address, db_id); if (main_kb) { scan_id = kb_item_get_str (main_kb, ("internal/scanid")); kb_lnk_reset (main_kb); return scan_id; } return NULL; } /** * @brief Get the bitflag which describes the methods to use for alive * deteciton. * * @param[out] alive_test Bitflag of all specified alive detection methods. * * @return 0 on success, boreas_error_t on failure. */ boreas_error_t get_alive_test_methods (alive_test_t *alive_test) { boreas_error_t error = NO_ERROR; const gchar *alive_test_pref_as_str; alive_test_pref_as_str = prefs_get ("ALIVE_TEST"); if (alive_test_pref_as_str == NULL) { g_warning ("%s: No valid alive_test specified.", __func__); error = BOREAS_NO_VALID_ALIVE_TEST_SPECIFIED; } else { *alive_test = atoi (alive_test_pref_as_str); } return error; } /** * @brief Get ports which should be used for alive detection in case of TCP-ACK * or TCP-SYN ping. * * @return string containing the ports. NULL otherwise. */ const gchar * get_alive_test_ports (void) { if (prefs_get ("alive_test_ports")) return prefs_get ("alive_test_ports"); return prefs_get ("ALIVE_TEST_PORTS"); } /** * @brief Get the max time in seconds that boreas waits for replies. * Minimum is 1 second. Max is 20. If a given value is invalid or greather * than 20, it is set to WAIT_FOR_REPLIES_TIMEOUT * * @return unsigned integer for the time in seconds. */ unsigned int get_alive_test_wait_timeout (void) { unsigned int timeout = -1; const gchar *str_timeout = NULL; str_timeout = prefs_get ("test_alive_wait_timeout"); if (str_timeout != NULL) timeout = atoi (str_timeout); if (timeout > 0 && timeout <= 20) return timeout; return WAIT_FOR_REPLIES_TIMEOUT; } gvm-libs-22.20.0/boreas/boreas_io.h000066400000000000000000000015631477470532200170030ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef BOREAS_IO_H #define BOREAS_IO_H #include "../base/hosts.h" #include "../util/kb.h" #include "alivedetection.h" #include "boreas_error.h" gvm_host_t * get_host_from_queue (kb_t, gboolean *); void put_host_on_queue (kb_t, char *); void put_finish_signal_on_queue (void *); void realloc_finish_signal_on_queue (kb_t); int finish_signal_on_queue (kb_t); void send_dead_hosts_to_ospd_openvas (int); void init_scan_restrictions (scanner_t *, int); void handle_scan_restrictions (scanner_t *, gchar *); gchar * get_openvas_scan_id (const gchar *, int); boreas_error_t get_alive_test_methods (alive_test_t *); const gchar * get_alive_test_ports (void); unsigned int get_alive_test_wait_timeout (void); int get_alive_hosts_count (void); #endif /* not BOREAS_IO_H */ gvm-libs-22.20.0/boreas/boreas_io_tests.c000066400000000000000000000011561477470532200202160ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "boreas_io.c" #include #include Describe (boreas_io); BeforeEach (boreas_io) { } AfterEach (boreas_io) { } Ensure (boreas_io, dummy_test) { assert_that (0, is_equal_to (0)); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, boreas_io, dummy_test); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/cli.c000066400000000000000000000163401477470532200156020ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "cli.h" #include "../base/networking.h" #include "../base/prefs.h" #include "alivedetection.h" #include "boreas_io.h" #include "ping.h" #include "sniffer.h" #include "util.h" #include #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" static unsigned int wait_timeout = 0; static boreas_error_t init_cli (scanner_t *scanner, gvm_hosts_t *hosts, alive_test_t alive_test, const gchar *port_list, const int print_results) { GPtrArray *portranges_array; gvm_host_t *host; int error; portranges_array = NULL; /* No kb used for cli mode.*/ scanner->main_kb = NULL; scanner->print_results = print_results; /* hosts_data */ scanner->hosts_data = g_malloc0 (sizeof (hosts_data_t)); scanner->hosts_data->alivehosts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); scanner->hosts_data->targethosts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (host = gvm_hosts_next (hosts); host; host = gvm_hosts_next (hosts)) g_hash_table_insert (scanner->hosts_data->targethosts, gvm_host_value_str (host), host); /* Sockets. */ error = set_all_needed_sockets (scanner, alive_test); if (error != 0) return error; /* Only init portlist if either TCP-ACK or TCP-SYN ping is used. */ if (alive_test & ALIVE_TEST_TCP_SYN_SERVICE || alive_test & ALIVE_TEST_TCP_ACK_SERVICE) { scanner->ports = g_array_new (FALSE, TRUE, sizeof (uint16_t)); if (port_list) portranges_array = port_range_ranges (port_list); g_ptr_array_foreach (portranges_array, fill_ports_array, scanner->ports); array_free (portranges_array); } /* No scan restrictions. */ init_scan_restrictions (scanner, 0); return error; } static boreas_error_t free_cli (scanner_t *scanner, alive_test_t alive_test) { int close_err; close_err = close_all_needed_sockets (scanner, alive_test); if (alive_test & ALIVE_TEST_TCP_SYN_SERVICE || alive_test & ALIVE_TEST_TCP_ACK_SERVICE) { g_array_free (scanner->ports, TRUE); } g_hash_table_destroy (scanner->hosts_data->alivehosts); g_hash_table_destroy (scanner->hosts_data->targethosts); g_free (scanner->hosts_data); return close_err; } static boreas_error_t run_cli_scan (scanner_t *scanner, alive_test_t alive_test) { int error; int number_of_dead_hosts; int number_of_targets; pthread_t sniffer_thread_id; struct timeval start_time, end_time; gettimeofday (&start_time, NULL); number_of_targets = g_hash_table_size (scanner->hosts_data->targethosts); if (scanner->print_results == 1) printf ("Alive scan started: Target has %d hosts.\n", number_of_targets); error = start_sniffer_thread (scanner, &sniffer_thread_id); if (error) return error; if (alive_test & (ALIVE_TEST_ICMP)) { g_hash_table_foreach (scanner->hosts_data->targethosts, send_icmp, scanner); wait_until_so_sndbuf_empty (scanner->icmpv4soc, 10); wait_until_so_sndbuf_empty (scanner->icmpv6soc, 10); usleep (500000); } if (alive_test & (ALIVE_TEST_TCP_SYN_SERVICE)) { scanner->tcp_flag = 0x02; /* SYN */ g_hash_table_foreach (scanner->hosts_data->targethosts, send_tcp, scanner); wait_until_so_sndbuf_empty (scanner->tcpv4soc, 10); wait_until_so_sndbuf_empty (scanner->tcpv6soc, 10); usleep (500000); } if (alive_test & (ALIVE_TEST_TCP_ACK_SERVICE)) { scanner->tcp_flag = 0x10; /* ACK */ g_hash_table_foreach (scanner->hosts_data->targethosts, send_tcp, scanner); wait_until_so_sndbuf_empty (scanner->tcpv4soc, 10); wait_until_so_sndbuf_empty (scanner->tcpv6soc, 10); usleep (500000); } if (alive_test & (ALIVE_TEST_ARP)) { g_hash_table_foreach (scanner->hosts_data->targethosts, send_arp, scanner); wait_until_so_sndbuf_empty (scanner->arpv4soc, 10); wait_until_so_sndbuf_empty (scanner->arpv6soc, 10); usleep (500000); } if (wait_timeout > 0 && wait_timeout <= 20) sleep (wait_timeout); else sleep (get_alive_test_wait_timeout ()); stop_sniffer_thread (scanner, sniffer_thread_id); number_of_dead_hosts = count_difference (scanner->hosts_data->targethosts, scanner->hosts_data->alivehosts); gettimeofday (&end_time, NULL); if (scanner->print_results == 1) printf ("Alive scan finished in %ld seconds: %d alive hosts of %d.\n", end_time.tv_sec - start_time.tv_sec, number_of_targets - number_of_dead_hosts, number_of_targets); return error; } boreas_error_t run_cli (gvm_hosts_t *hosts, alive_test_t alive_test, const gchar *port_list) { return run_cli_extended (hosts, alive_test, port_list, 3); } boreas_error_t run_cli_extended (gvm_hosts_t *hosts, alive_test_t alive_test, const gchar *port_list, const unsigned int timeout) { scanner_t scanner = {0}; boreas_error_t init_err; boreas_error_t run_err; boreas_error_t free_err; int print_results = 1; wait_timeout = timeout; init_err = init_cli (&scanner, hosts, alive_test, port_list, print_results); if (init_err) { printf ("Error initializing scanner.\n"); return init_err; } run_err = run_cli_scan (&scanner, alive_test); if (run_err) { printf ("Error while running the scan.\n"); return run_err; } free_err = free_cli (&scanner, alive_test); if (free_err) { printf ("Error freeing scan data.\n"); return free_err; } return NO_ERROR; } /** * @brief Scan all specified hosts in ip_str list. * * @param[in] ip_str list of hosts to alive test. * @param[out] count amount of alive host which were found alived. * * @return NO_ERROR (0) on success, boreas_error_t on error. */ boreas_error_t is_host_alive (const char *ip_str, int *count) { scanner_t scanner = {0}; boreas_error_t init_err; boreas_error_t run_err; boreas_error_t free_err; boreas_error_t alive_test_err; alive_test_t alive_test; gvm_hosts_t *hosts; const int print_results = 0; const gchar *port_list = NULL; hosts = gvm_hosts_new (ip_str); alive_test_err = get_alive_test_methods (&alive_test); if (alive_test_err != 0) { g_warning ("%s: %s. Exit Boreas.", __func__, str_boreas_error (alive_test_err)); pthread_exit (0); } /* This port list is also used by openvas for scanning and was already * validated by openvas so we don't do it here again. */ port_list = prefs_get ("port_range"); init_err = init_cli (&scanner, hosts, alive_test, port_list, print_results); if (init_err) { printf ("Error initializing scanner.\n"); return init_err; } run_err = run_cli_scan (&scanner, alive_test); if (run_err) { printf ("Error while running the scan.\n"); return run_err; } *count = get_alive_hosts_count (); free_err = free_cli (&scanner, alive_test); if (free_err) { printf ("Error freeing scan data.\n"); return free_err; } return NO_ERROR; } gvm-libs-22.20.0/boreas/cli.h000066400000000000000000000007021477470532200156020ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef CLI_H #define CLI_H #include "alivedetection.h" #include "boreas_error.h" boreas_error_t run_cli_extended (gvm_hosts_t *, alive_test_t, const gchar *, const unsigned int); boreas_error_t run_cli (gvm_hosts_t *, alive_test_t, const gchar *); boreas_error_t is_host_alive (const char *, int *); #endif /* not CLI_H */ gvm-libs-22.20.0/boreas/cli_tests.c000066400000000000000000000011201477470532200170120ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "ping.c" #include #include Describe (ping); BeforeEach (ping) { } AfterEach (ping) { } Ensure (ping, dummy_test) { assert_that (0, is_equal_to (0)); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, ping, dummy_test); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/libgvm_boreas.pc.in000066400000000000000000000004731477470532200204330ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@EXEC_PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: gvmlibs-boreas Description: Greenbone ALive Detection Module Boreas Version: @LIBGVMCONFIG_VERSION@ Requires.private: glib-2.0 >= 2.42.0 Cflags: -I${includedir} -I${includedir}/gvm Libs: -L${libdir} -lgvm_boreas gvm-libs-22.20.0/boreas/ping.c000066400000000000000000000407421477470532200157730ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "ping.h" #include "../base/prefs.h" /* for prefs_get() */ #include "arp.h" #include "util.h" #include #include #include #include /* for getifaddrs() */ #include #include #include #include #include #include #include #include #include #include #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" struct v6pseudohdr { struct in6_addr s6addr; struct in6_addr d6addr; u_short length; u_char zero1; u_char zero2; u_char zero3; u_char protocol; struct tcphdr tcpheader; }; struct pseudohdr { struct in_addr saddr; struct in_addr daddr; u_char zero; u_char protocol; u_short length; struct tcphdr tcpheader; }; // Return a random uint16 avoiding the 0. static uint16_t get_echo_id (void) { uint16_t upper_bound = 65534; uint16_t lower_bound = 1; return rand () % (upper_bound - lower_bound + 1) + lower_bound; } /** * @brief Get the size of the socket send buffer. * * @param[in] soc The socket to get the send buffer for. * @param[out] so_sndbuf The size of the send buffer. * * @return 0 on success, -1 on error. so_sndbuf is set to -1 on error. */ static int get_so_sndbuf (int soc, int *so_sndbuf) { unsigned int optlen = sizeof (*so_sndbuf); if (getsockopt (soc, SOL_SOCKET, SO_SNDBUF, (void *) so_sndbuf, &optlen) == -1) { g_warning ("%s: getsockopt error: %s", __func__, strerror (errno)); *so_sndbuf = -1; return -1; } return 0; } /** * @brief Wait until output queue is small enough for sending new packets. * * If calls to ioctl fail in this function we might not throttle as expected * and only delay by a fixed amount of time. * * @param soc Socket. * @param so_sndbuf Size of the socket send buffer we do not want to exceed. */ static void throttle (int soc, int so_sndbuf) { // g_warning ("%s: so_sndbuf %d", __func__, so_sndbuf); int cur_so_sendbuf = -1; /* Get the current size of the output queue size */ if (ioctl (soc, SIOCOUTQ, &cur_so_sendbuf) == -1) { g_warning ("%s: ioctl error: %s", __func__, strerror (errno)); usleep (100000); return; } /* If setting of so_sndbuf or cur_so_sendbuf failed we do not enter the * throttling loop. Normally this should not occur but we really do not want * to get into an infinite loop here. */ if (cur_so_sendbuf != -1 && so_sndbuf != -1) { /* Wait until output queue is empty enough. */ while (cur_so_sendbuf >= so_sndbuf) { usleep (100000); if (ioctl (soc, SIOCOUTQ, &cur_so_sendbuf) == -1) { g_warning ("%s: ioctl error: %s", __func__, strerror (errno)); usleep (100000); /* Do not risk getting into infinite loop */ return; } } } return; } /** * @brief Send icmp ping. * * @param soc Socket to use for sending. * @param dst Destination address to send to. * @param type Type of imcp. e.g. ND_NEIGHBOR_SOLICIT or ICMP6_ECHO_REQUEST. */ static void send_icmp_v6 (int soc, struct in6_addr *dst, int type) { struct sockaddr_in6 soca; char sendbuf[1500]; int len; int datalen = 56; struct icmp6_hdr *icmp6; /* Throttling related variables */ static int so_sndbuf = -1; // socket send buffer static int init = -1; icmp6 = (struct icmp6_hdr *) sendbuf; icmp6->icmp6_type = type; /* ND_NEIGHBOR_SOLICIT or ICMP6_ECHO_REQUEST */ icmp6->icmp6_code = 0; icmp6->icmp6_id = get_echo_id (); icmp6->icmp6_seq = 0x0100; memset ((icmp6 + 1), 0xa5, datalen); gettimeofday ((struct timeval *) (icmp6 + 1), NULL); // only for testing len = 8 + datalen; /* send packet */ memset (&soca, 0, sizeof (struct sockaddr_in6)); soca.sin6_family = AF_INET6; soca.sin6_addr = *dst; /* Get size of empty SO_SNDBUF */ if (init == -1) { if (get_so_sndbuf (soc, &so_sndbuf) == 0) init = 1; } /* Throttle speed if needed */ throttle (soc, so_sndbuf); if (sendto (soc, sendbuf, len, MSG_NOSIGNAL, (struct sockaddr *) &soca, sizeof (struct sockaddr_in6)) < 0) { g_warning ("%s: sendto(): %s", __func__, strerror (errno)); } } /** * @brief Send icmp ping. * * @param soc Socket to use for sending. * @param dst Destination address to send to. */ static void send_icmp_v4 (int soc, struct in_addr *dst) { /* datalen + MAXIPLEN + MAXICMPLEN */ char sendbuf[56 + 60 + 76]; struct sockaddr_in soca; int len; int datalen = 56; struct icmphdr *icmp; /* Throttling related variables */ static int so_sndbuf = -1; // socket send buffer static int init = -1; icmp = (struct icmphdr *) sendbuf; icmp->type = ICMP_ECHO; icmp->code = 0; icmp->un.echo.id = get_echo_id (); icmp->un.echo.sequence = 0x0100; len = 8 + datalen; icmp->checksum = 0; icmp->checksum = in_cksum ((u_short *) icmp, len); memset (&soca, 0, sizeof (soca)); soca.sin_family = AF_INET; soca.sin_addr = *dst; /* Get size of empty SO_SNDBUF */ if (init == -1) { if (get_so_sndbuf (soc, &so_sndbuf) == 0) init = 1; } /* Throttle speed if needed */ throttle (soc, so_sndbuf); if (sendto (soc, sendbuf, len, MSG_NOSIGNAL, (const struct sockaddr *) &soca, sizeof (struct sockaddr_in)) < 0) { g_warning ("%s: sendto(): %s", __func__, strerror (errno)); } } /** * @brief Is called in g_hash_table_foreach(). Check if ipv6 or ipv4, get * correct socket and start appropriate ping function. * * @param key Ip string. * @param value Pointer to gvm_host_t. * @param scanner_p Pointer to scanner struct. */ void send_icmp (gpointer key, gpointer value, gpointer scanner_p) { scanner_t *scanner; struct in6_addr dst6; struct in6_addr *dst6_p = &dst6; struct in_addr dst4; struct in_addr *dst4_p = &dst4; static int count = 0; int icmp_retries, grace_period = 0; const char *tmp; if ((icmp_retries = (tmp = prefs_get ("icmp_retries")) != NULL ? atoi (tmp) : 1) <= 0) icmp_retries = 1; else if (icmp_retries > 1) grace_period = (tmp = prefs_get ("icmp_grace_period")) != NULL ? atoi (tmp) : 0; scanner = (scanner_t *) scanner_p; // we may send multiple icmp message to reduce to chance of unwanted drops for (int i = 0; i < icmp_retries; i++) { if (g_hash_table_contains (scanner->hosts_data->alivehosts, key)) return; if (++count % BURST == 0) usleep (BURST_TIMEOUT); if (gvm_host_get_addr6 ((gvm_host_t *) value, dst6_p) < 0) g_warning ("%s: could not get addr6 from gvm_host_t", __func__); if (dst6_p == NULL) { g_warning ("%s: destination address is NULL", __func__); return; } if (IN6_IS_ADDR_V4MAPPED (dst6_p) != 1) { send_icmp_v6 (scanner->icmpv6soc, dst6_p, ICMP6_ECHO_REQUEST); } else { dst4.s_addr = dst6_p->s6_addr32[3]; send_icmp_v4 (scanner->icmpv4soc, dst4_p); } if (grace_period > 0) usleep (grace_period); } } /** * @brief Send tcp ping. * * @param soc Socket to use for sending. * @param dst Destination address to send to. * @param tcp_flag TH_SYN or TH_ACK. */ static void send_tcp_v6 (scanner_t *scanner, struct in6_addr *dst_p) { boreas_error_t error; struct sockaddr_in6 soca; struct in6_addr src; /* Throttling related variables */ static int so_sndbuf = -1; // socket send buffer static int init = -1; GArray *ports = scanner->ports; int *udpv6soc = &(scanner->udpv6soc); int soc = scanner->tcpv6soc; uint8_t tcp_flag = scanner->tcp_flag; u_char packet[sizeof (struct ip6_hdr) + sizeof (struct tcphdr)]; struct ip6_hdr *ip = (struct ip6_hdr *) packet; struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof (struct ip6_hdr)); /* Get source address for TCP header. */ error = get_source_addr_v6 (udpv6soc, dst_p, &src); if (error) { char destination_str[INET_ADDRSTRLEN]; inet_ntop (AF_INET6, (const void *) dst_p, destination_str, INET_ADDRSTRLEN); g_debug ("%s: Destination: %s. %s", __func__, destination_str, str_boreas_error (error)); return; } /* No ports in portlist. */ if (ports->len == 0) return; /* For ports in ports array send packet. */ for (guint i = 0; i < ports->len; i++) { memset (packet, 0, sizeof (packet)); /* IPv6 */ ip->ip6_flow = htonl ((6 << 28) | (0 << 20) | 0); ip->ip6_plen = htons (20); // TCP_HDRLEN ip->ip6_nxt = IPPROTO_TCP; ip->ip6_hops = 255; // max value ip->ip6_src = src; ip->ip6_dst = *dst_p; /* TCP */ tcp->th_sport = htons (FILTER_PORT); tcp->th_dport = htons (g_array_index (ports, uint16_t, i)); tcp->th_seq = htonl (0); tcp->th_ack = htonl (0); tcp->th_x2 = 0; tcp->th_off = 20 / 4; // TCP_HDRLEN / 4 (size of tcphdr in 32 bit words) tcp->th_flags = tcp_flag; // TH_SYN or TH_ACK tcp->th_win = htons (65535); tcp->th_urp = htons (0); tcp->th_sum = 0; /* CKsum */ { struct v6pseudohdr pseudoheader; memset (&pseudoheader, 0, 38 + sizeof (struct tcphdr)); memcpy (&pseudoheader.s6addr, &ip->ip6_src, sizeof (struct in6_addr)); memcpy (&pseudoheader.d6addr, &ip->ip6_dst, sizeof (struct in6_addr)); pseudoheader.protocol = IPPROTO_TCP; pseudoheader.length = htons (sizeof (struct tcphdr)); memcpy ((char *) &pseudoheader.tcpheader, (char *) tcp, sizeof (struct tcphdr)); tcp->th_sum = in_cksum ((unsigned short *) &pseudoheader, 38 + sizeof (struct tcphdr)); } memset (&soca, 0, sizeof (soca)); soca.sin6_family = AF_INET6; soca.sin6_addr = ip->ip6_dst; /* Get size of empty SO_SNDBUF */ if (init == -1) { if (get_so_sndbuf (soc, &so_sndbuf) == 0) init = 1; } /* Throttle speed if needed */ throttle (soc, so_sndbuf); /* TCP_HDRLEN(20) IP6_HDRLEN(40) */ if (sendto (soc, (const void *) ip, 40 + 20, MSG_NOSIGNAL, (struct sockaddr *) &soca, sizeof (struct sockaddr_in6)) < 0) { g_warning ("%s: sendto(): %s", __func__, strerror (errno)); } } } /** * @brief Send tcp ping. * * @param scanner Scanner struct which includes all needed data for tcp_v4 ping. * @param dst Destination address to send to. */ static void send_tcp_v4 (scanner_t *scanner, struct in_addr *dst_p) { boreas_error_t error; struct sockaddr_in soca; struct in_addr src; /* Throttling related variables */ static int so_sndbuf = -1; // socket send buffer static int init = -1; int soc = scanner->tcpv4soc; /* Socket used for sending. */ GArray *ports = scanner->ports; /* Ports to ping. */ int *udpv4soc = &(scanner->udpv4soc); /* Socket used for getting src addr */ uint8_t tcp_flag = scanner->tcp_flag; /* SYN or ACK tcp flag. */ u_char packet[sizeof (struct ip) + sizeof (struct tcphdr)]; struct ip *ip = (struct ip *) packet; struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof (struct ip)); /* No ports in portlist. */ if (ports->len == 0) return; /* Get source address for TCP header. */ error = get_source_addr_v4 (udpv4soc, dst_p, &src); if (error) { char destination_str[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &(dst_p->s_addr), destination_str, INET_ADDRSTRLEN); g_debug ("%s: Destination: %s. %s", __func__, destination_str, str_boreas_error (error)); return; } /* For ports in ports array send packet. */ for (guint i = 0; i < ports->len; i++) { memset (packet, 0, sizeof (packet)); /* IP */ ip->ip_hl = 5; ip->ip_off = htons (0); ip->ip_v = 4; ip->ip_tos = 0; ip->ip_p = IPPROTO_TCP; ip->ip_id = rand (); ip->ip_ttl = 0x40; ip->ip_src = src; ip->ip_dst = *dst_p; ip->ip_sum = 0; /* TCP */ tcp->th_sport = htons (FILTER_PORT); tcp->th_flags = tcp_flag; // TH_SYN TH_ACK; tcp->th_dport = htons (g_array_index (ports, uint16_t, i)); tcp->th_seq = rand (); tcp->th_ack = 0; tcp->th_x2 = 0; tcp->th_off = 5; tcp->th_win = 2048; tcp->th_urp = 0; tcp->th_sum = 0; /* CKsum */ { struct in_addr source, dest; struct pseudohdr pseudoheader; source.s_addr = ip->ip_src.s_addr; dest.s_addr = ip->ip_dst.s_addr; memset (&pseudoheader, 0, 12 + sizeof (struct tcphdr)); pseudoheader.saddr.s_addr = source.s_addr; pseudoheader.daddr.s_addr = dest.s_addr; pseudoheader.protocol = IPPROTO_TCP; pseudoheader.length = htons (sizeof (struct tcphdr)); memcpy ((char *) &pseudoheader.tcpheader, (char *) tcp, sizeof (struct tcphdr)); tcp->th_sum = in_cksum ((unsigned short *) &pseudoheader, 12 + sizeof (struct tcphdr)); } memset (&soca, 0, sizeof (soca)); soca.sin_family = AF_INET; soca.sin_addr = ip->ip_dst; /* Get size of empty SO_SNDBUF */ if (init == -1) { if (get_so_sndbuf (soc, &so_sndbuf) == 0) init = 1; } /* Throttle speed if needed */ throttle (soc, so_sndbuf); if (sendto (soc, (const void *) ip, 40, MSG_NOSIGNAL, (struct sockaddr *) &soca, sizeof (soca)) < 0) { g_warning ("%s: sendto(): %s", __func__, strerror (errno)); } } } /** * @brief Is called in g_hash_table_foreach(). Check if ipv6 or ipv4, get * correct socket and start appropriate ping function. * * @param key Ip string. * @param value Pointer to gvm_host_t. * @param scanner_p Pointer to scanner struct. */ void send_tcp (gpointer key, gpointer value, gpointer scanner_p) { scanner_t *scanner; struct in6_addr dst6; struct in6_addr *dst6_p = &dst6; struct in_addr dst4; struct in_addr *dst4_p = &dst4; static int count = 0; scanner = (scanner_t *) scanner_p; if (g_hash_table_contains (scanner->hosts_data->alivehosts, key)) return; count++; if (count % BURST == 0) usleep (BURST_TIMEOUT); if (gvm_host_get_addr6 ((gvm_host_t *) value, dst6_p) < 0) g_warning ("%s: could not get addr6 from gvm_host_t", __func__); if (dst6_p == NULL) { g_warning ("%s: destination address is NULL", __func__); return; } if (IN6_IS_ADDR_V4MAPPED (dst6_p) != 1) { send_tcp_v6 (scanner, dst6_p); } else { dst4.s_addr = dst6_p->s6_addr32[3]; send_tcp_v4 (scanner, dst4_p); } } /** * @brief Is called in g_hash_table_foreach(). Check if ipv6 or ipv4, get * correct socket and start appropriate ping function. * * @param host_value_str Ip string. * @param value Pointer to gvm_host_t. * @param scanner_p Pointer to scanner struct. */ void send_arp (gpointer host_value_str, gpointer value, gpointer scanner_p) { scanner_t *scanner; struct in6_addr dst6; struct in6_addr *dst6_p = &dst6; static int count = 0; scanner = (scanner_t *) scanner_p; if (g_hash_table_contains (scanner->hosts_data->alivehosts, host_value_str)) return; count++; if (count % BURST == 0) usleep (BURST_TIMEOUT); if (gvm_host_get_addr6 ((gvm_host_t *) value, dst6_p) < 0) g_warning ("%s: could not get addr6 from gvm_host_t", __func__); if (dst6_p == NULL) { g_warning ("%s: destination address is NULL", __func__); return; } if (IN6_IS_ADDR_V4MAPPED (dst6_p) != 1) { /* IPv6 does simulate ARP by using the Neighbor Discovery Protocol with * ICMPv6. */ send_icmp_v6 (scanner->arpv6soc, dst6_p, ND_NEIGHBOR_SOLICIT); } else { char ipv4_str[INET_ADDRSTRLEN]; /* Need to transform the IPv6 mapped IPv4 address back to an IPv4 string. * We can not just use the host_value_str as it might be an IPv4 mapped * IPv6 string. */ if (inet_ntop (AF_INET, &(dst6_p->s6_addr32[3]), ipv4_str, sizeof (ipv4_str)) == NULL) { g_warning ("%s: Error: %s. Skipping ARP ping for '%s'", __func__, strerror (errno), (char *) host_value_str); } send_arp_v4 (ipv4_str); } } gvm-libs-22.20.0/boreas/ping.h000066400000000000000000000005241477470532200157720ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef BOREAS_PING_H #define BOREAS_PING_H #include void send_icmp (gpointer, gpointer, gpointer); void send_tcp (gpointer, gpointer, gpointer); void send_arp (gpointer, gpointer, gpointer); #endif /* not BOREAS_PING_H */ gvm-libs-22.20.0/boreas/ping_tests.c000066400000000000000000000011201477470532200172000ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "ping.c" #include #include Describe (ping); BeforeEach (ping) { } AfterEach (ping) { } Ensure (ping, dummy_test) { assert_that (0, is_equal_to (0)); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, ping, dummy_test); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/sniffer.c000066400000000000000000000226161477470532200164720ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "sniffer.h" #include "alivedetection.h" #include "boreas_io.h" #include #include #include #include #include #include #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" /* for using int value in #defined string */ #define STR(X) #X #define ASSTR(X) STR (X) #define FILTER_STR \ "(ip6 or ip or arp) and (ip6[40]=129 or icmp[icmptype] == icmp-echoreply " \ "or dst port " ASSTR (FILTER_PORT) " or arp[6:2]=2)" /* Conditional variable and mutex to make sure sniffer thread already started * before sending out pings. */ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; /** * @brief open a new pcap handle ad set provided filter. * * @param iface interface to use. * @param filter pcap filter to use. * * @return pcap_t handle or NULL on error */ static pcap_t * open_live (char *iface, char *filter) { /* iface considerations: * pcap_open_live(iface, ...) sniffs on all interfaces(linux) if iface * argument is NULL pcap_lookupnet(iface, ...) is used to set ipv4 network * number and mask associated with iface pcap_compile(..., mask) netmask * specifies the IPv4 netmask of the network on which packets are being * captured; it is used only when checking for IPv4 broadcast addresses in the * filter program * * If we are not checking for IPv4 broadcast addresses in the filter program * we do not need an iface (if we also want to listen on all interface) and we * do not need to call pcap_lookupnet */ char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *pcap_handle; struct bpf_program filter_prog; /* iface, snapshot length of handle, promiscuous mode, packet buffer timeout * (ms), errbuff */ errbuf[0] = '\0'; pcap_handle = pcap_open_live (iface, 1500, 0, 100, errbuf); if (pcap_handle == NULL) { g_warning ("%s: %s", __func__, errbuf); return NULL; } if (g_utf8_strlen (errbuf, -1) != 0) { g_warning ("%s: %s", __func__, errbuf); } /* handle, struct bpf_program *fp, int optimize, bpf_u_int32 netmask */ if (pcap_compile (pcap_handle, &filter_prog, filter, 1, PCAP_NETMASK_UNKNOWN) < 0) { char *msg = pcap_geterr (pcap_handle); g_warning ("%s: %s", __func__, msg); pcap_close (pcap_handle); return NULL; } if (pcap_setfilter (pcap_handle, &filter_prog) < 0) { char *msg = pcap_geterr (pcap_handle); g_warning ("%s: %s", __func__, msg); pcap_close (pcap_handle); return NULL; } pcap_freecode (&filter_prog); return pcap_handle; } /** * @brief Processes single packets captured by pcap. Is a callback function. * * For every packet we check if it is ipv4 ipv6 or arp and extract the sender ip * address. This ip address is then inserted into the alive_hosts table if not * already present and if in the target table. * * @param user_data Pointer to scanner. * @param header * @param packet Packet to process. * * TODO: simplify and read https://tools.ietf.org/html/rfc826 */ static void got_packet (u_char *user_data, __attribute__ ((unused)) const struct pcap_pkthdr *header, const u_char *packet) { struct ip *ip; unsigned int version; scanner_t *scanner; hosts_data_t *hosts_data; gchar *addr_str = NULL; ip = (struct ip *) (packet + 16); version = ip->ip_v; scanner = (scanner_t *) user_data; hosts_data = (hosts_data_t *) scanner->hosts_data; if (version == 4) { addr_str = g_malloc0 (INET_ADDRSTRLEN); struct in_addr sniffed_addr; /* was +26 (14 ETH + 12 IP) originally but was off by 2 somehow */ memcpy (&sniffed_addr.s_addr, packet + 26 + 2, 4); if (inet_ntop (AF_INET, (const char *) &sniffed_addr, addr_str, INET_ADDRSTRLEN) == NULL) g_debug ( "%s: Failed to transform IPv4 address into string representation: %s", __func__, strerror (errno)); } else if (version == 6) { addr_str = g_malloc0 (INET6_ADDRSTRLEN); struct in6_addr sniffed_addr; /* (14 ETH + 8 IP + offset 2) */ memcpy (&sniffed_addr.s6_addr, packet + 24, 16); if (inet_ntop (AF_INET6, (const char *) &sniffed_addr, addr_str, INET6_ADDRSTRLEN) == NULL) g_debug ("%s: Failed to transform IPv6 into string representation: %s", __func__, strerror (errno)); } /* TODO: check collision situations. * everything not ipv4/6 is regarded as arp. * It may be possible to get other types then arp replies in which case the * ip from inet_ntop should be bogus. */ else { /* TODO: at the moment offset of 6 is set but arp header has variable * sized field. */ /* read rfc https://tools.ietf.org/html/rfc826 for exact length or how to get it */ struct arphdr *arp = (struct arphdr *) (packet + 14 + 2 + 6 + sizeof (struct arphdr)); addr_str = g_malloc0 (INET_ADDRSTRLEN); if (inet_ntop (AF_INET, (const char *) arp, addr_str, INET_ADDRSTRLEN) == NULL) g_debug ("%s: Failed to transform IP into string representation: %s", __func__, strerror (errno)); } /* Only put unique hosts on queue and in hash table. Use short circuit * evaluation to not add hosts to the hash table which are not in our * target list.*/ if ((g_hash_table_contains (hosts_data->targethosts, addr_str) == TRUE) && (g_hash_table_add (hosts_data->alivehosts, g_strdup (addr_str)))) { /* handle max_scan_hosts related restrictions. */ handle_scan_restrictions (scanner, addr_str); } g_free (addr_str); } /** * @brief Sniff packets by starting pcap_loop with callback function. * * @param scanner_p Pointer to scanner struct. */ static void * sniffer_thread (void *scanner_p) { int ret; scanner_t *scanner = (scanner_t *) scanner_p; pthread_mutex_lock (&mutex); pthread_cond_signal (&cond); pthread_mutex_unlock (&mutex); /* reads packets until error or pcap_breakloop() */ if ((ret = pcap_loop (scanner->pcap_handle, -1, got_packet, (u_char *) scanner)) == PCAP_ERROR) g_debug ("%s: pcap_loop error %s", __func__, pcap_geterr (scanner->pcap_handle)); else if (ret == 0) g_debug ("%s: count of packets is exhausted", __func__); else if (ret == PCAP_ERROR_BREAK) g_debug ("%s: Loop was successfully broken after call to pcap_breakloop", __func__); pthread_exit (0); } /** * @brief Stop the sniffer thread. * * @param scanner Pointer to scanner struct. * @param sniffer_thread_id pthread_t thread id. * * @return 0 on success, other on Error. */ int stop_sniffer_thread (scanner_t *scanner, pthread_t sniffer_thread_id) { // wait period for grace in microseconds const int wait = 5000; // maximum grace period in microseconds const int max_grace = 2 * 1000 * 1000; int err, waited; void *retval; g_debug ("%s: Try to stop thread which is sniffing for alive hosts. ", __func__); /* Try to break loop in sniffer thread. */ pcap_breakloop (scanner->pcap_handle); /* Give thread chance to exit on its own. */ for (waited = 0; waited < max_grace && pthread_kill (sniffer_thread_id, 0) != ESRCH; waited += wait) usleep (wait); /* Cancel thread. May be necessary if pcap_breakloop() does not break the * loop. */ err = pthread_cancel (sniffer_thread_id); if (err == ESRCH) g_debug ("%s: pthread_cancel() returned ESRCH; No thread with the " "supplied ID could be found.", __func__); /* join sniffer thread*/ err = pthread_join (sniffer_thread_id, &retval); if (err == EDEADLK) g_warning ("%s: pthread_join() returned EDEADLK.", __func__); if (err == EINVAL) g_warning ("%s: pthread_join() returned EINVAL.", __func__); if (err == ESRCH) g_warning ("%s: pthread_join() returned ESRCH.", __func__); if (retval == PTHREAD_CANCELED) g_debug ("%s: pthread_join() returned PTHREAD_CANCELED.", __func__); g_debug ("%s: Stopped thread which was sniffing for alive hosts.", __func__); /* close handle */ if (scanner->pcap_handle != NULL) { pcap_close (scanner->pcap_handle); } return err; } /** * @brief Start up the sniffer thread. * * @param scanner Pointer to scanner struct. * @param sniffer_thread_id pthread_t thread id. * * @return 0 on success, other on Error. */ int start_sniffer_thread (scanner_t *scanner, pthread_t *sniffer_thread_id) { int err; scanner->pcap_handle = open_live (NULL, FILTER_STR); if (scanner->pcap_handle == NULL) { g_warning ("%s: Unable to open valid pcap handle.", __func__); return -1; } /* Start sniffer thread. */ pthread_mutex_lock (&mutex); err = pthread_create (sniffer_thread_id, NULL, sniffer_thread, scanner); if (err == EAGAIN) g_warning ("%s: pthread_create() returned EAGAIN: Insufficient resources " "to create thread.", __func__); /* Wait for thread to start up before sending out pings. */ pthread_cond_wait (&cond, &mutex); pthread_mutex_unlock (&mutex); /* Mutex and cond not needed anymore. */ pthread_mutex_destroy (&mutex); pthread_cond_destroy (&cond); return err; } gvm-libs-22.20.0/boreas/sniffer.h000066400000000000000000000005251477470532200164720ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef BOREAS_SNIFFER_H #define BOREAS_SNIFFER_H #include "alivedetection.h" #include int start_sniffer_thread (scanner_t *, pthread_t *); int stop_sniffer_thread (scanner_t *, pthread_t); #endif /* not BOREAS_SNIFFER_H */ gvm-libs-22.20.0/boreas/sniffer_tests.c000066400000000000000000000011421477470532200177030ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "sniffer.c" #include #include Describe (sniffer); BeforeEach (sniffer) { } AfterEach (sniffer) { } Ensure (sniffer, dummy_test) { assert_that (0, is_equal_to (0)); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, sniffer, dummy_test); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/boreas/util.c000066400000000000000000000432571477470532200160170ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "util.h" #include "../base/networking.h" /* for range_t */ #include #include #include /* for getifaddrs() */ #include #include #include /* for if_nametoindex() */ #include /* for sockaddr_ll */ #include #include #include #include #include #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "libgvm boreas" static boreas_error_t set_socket (socket_type_t, int *); /** * @brief Checksum calculation. * * From W.Richard Stevens "UNIX NETWORK PROGRAMMING" book. libfree/in_cksum.c * TODO: Section 8.7 of TCPv2 has more efficient implementation * * @param[in] addr Data to checksum over. * @param[in] len Length of data in bytes. * * @return Checksum in bytes. **/ uint16_t in_cksum (uint16_t *addr, int len) { int nleft = len; uint32_t sum = 0; uint16_t *w = addr; uint16_t answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(unsigned char *) (&answer) = *(unsigned char *) w; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return answer; } /** * @brief Get the source mac address of the given interface * or of the first non lo interface. * * @param interface Interface to get mac address from or NULL if first non lo * interface should be used. * @param[out] mac Location where to store mac address. * * @return 0 on success, -1 on error. */ int get_source_mac_addr (char *interface, uint8_t *mac) { struct ifaddrs *ifaddr = NULL; struct ifaddrs *ifa = NULL; int interface_provided = 0; if (interface) interface_provided = 1; if (getifaddrs (&ifaddr) == -1) { g_debug ("%s: getifaddr failed: %s", __func__, strerror (errno)); return -1; } else { for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if ((ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_PACKET) && !(ifa->ifa_flags & (IFF_LOOPBACK))) { if (interface_provided) { if (g_strcmp0 (interface, ifa->ifa_name) == 0) { struct sockaddr_ll *s = (struct sockaddr_ll *) ifa->ifa_addr; memcpy (mac, s->sll_addr, 6 * sizeof (uint8_t)); } } else { struct sockaddr_ll *s = (struct sockaddr_ll *) ifa->ifa_addr; memcpy (mac, s->sll_addr, 6 * sizeof (uint8_t)); } } } freeifaddrs (ifaddr); } return 0; } /** * @brief Figure out source address for given destination. * * This function uses a well known trick for getting the source address used * for a given destination by calling connect() and getsockname() on an udp * socket. * * @param[in] udpv6soc Location of the socket to use. * @param[in] dst Destination address. * @param[out] src Source address. * * @return 0 on success, boreas_error_t on failure. */ boreas_error_t get_source_addr_v6 (int *udpv6soc, struct in6_addr *dst, struct in6_addr *src) { struct sockaddr_storage storage; struct sockaddr_in6 sin; socklen_t sock_len; boreas_error_t error; memset (&sin, 0, sizeof (struct sockaddr_in6)); sin.sin6_family = AF_INET6; sin.sin6_addr = *dst; sin.sin6_port = htons (9); /* discard port (see RFC 863) */ memcpy (&storage, &sin, sizeof (sin)); error = NO_ERROR; sock_len = sizeof (storage); if (connect (*udpv6soc, (const struct sockaddr *) &storage, sock_len) < 0) { g_warning ("%s: connect() on udpv6soc failed: %s %d", __func__, strerror (errno), errno); /* State of the socket is unspecified. Close the socket and create a new * one. */ if ((close (*udpv6soc)) != 0) { g_debug ("%s: Error in close(): %s", __func__, strerror (errno)); } set_socket (UDPV6, udpv6soc); error = BOREAS_NO_SRC_ADDR_FOUND; } else { if (getsockname (*udpv6soc, (struct sockaddr *) &storage, &sock_len) < 0) { g_debug ("%s: getsockname() on updv6soc failed: %s", __func__, strerror (errno)); error = BOREAS_NO_SRC_ADDR_FOUND; } } if (!error) { /* Set source address. */ memcpy (src, &((struct sockaddr_in6 *) (&storage))->sin6_addr, sizeof (struct in6_addr)); /* Dissolve association so we can connect() on same socket again in later * call to get_source_addr_v4(). */ sin.sin6_family = AF_UNSPEC; sock_len = sizeof (storage); memcpy (&storage, &sin, sizeof (sin)); if (connect (*udpv6soc, (const struct sockaddr *) &storage, sock_len) < 0) g_debug ("%s: connect() on udpv6soc to dissolve association failed: %s", __func__, strerror (errno)); } return error; } /** * @brief Figure out source address for given destination. * * This function uses a well known trick for getting the source address used * for a given destination by calling connect() and getsockname() on an udp * socket. * * @param[in] udpv4soc Location of the socket to use. * @param[in] dst Destination address. * @param[out] src Source address. * * @return 0 on success, boreas_error_t on failure. */ boreas_error_t get_source_addr_v4 (int *udpv4soc, struct in_addr *dst, struct in_addr *src) { struct sockaddr_storage storage; struct sockaddr_in sin; socklen_t sock_len; boreas_error_t error; memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = dst->s_addr; sin.sin_port = htons (9); /* discard port (see RFC 863) */ memcpy (&storage, &sin, sizeof (sin)); error = NO_ERROR; sock_len = sizeof (storage); if (connect (*udpv4soc, (const struct sockaddr *) &storage, sock_len) < 0) { g_warning ("%s: connect() on udpv4soc failed: %s", __func__, strerror (errno)); /* State of the socket is unspecified. Close the socket and create a new * one. */ if ((close (*udpv4soc)) != 0) { g_debug ("%s: Error in close(): %s", __func__, strerror (errno)); } set_socket (UDPV4, udpv4soc); error = BOREAS_NO_SRC_ADDR_FOUND; } else { if (getsockname (*udpv4soc, (struct sockaddr *) &storage, &sock_len) < 0) { g_debug ("%s: getsockname() on updv4soc failed: %s", __func__, strerror (errno)); error = BOREAS_NO_SRC_ADDR_FOUND; } } if (!error) { /* Set source address. */ memcpy (src, &((struct sockaddr_in *) (&storage))->sin_addr, sizeof (struct in_addr)); /* Dissolve association so we can connect() on same socket again in later * call to get_source_addr_v4(). */ sin.sin_family = AF_UNSPEC; sock_len = sizeof (storage); memcpy (&storage, &sin, sizeof (sin)); if (connect (*udpv4soc, (const struct sockaddr *) &storage, sock_len) < 0) g_debug ("%s: connect() on udpv4soc to dissolve association failed: %s", __func__, strerror (errno)); } return error; } /** * @brief Put all ports of a given port range into the ports array. * * @param range Pointer to a range_t. * @param ports_array Pointer to an GArray. */ void fill_ports_array (gpointer range, gpointer ports_array) { gboolean range_exclude; int range_start; int range_end; int i; /* Use uint16_t for port array elements. tcphdr port type is uint16_t. */ uint16_t port_sized; range_start = ((range_t *) range)->start; range_end = ((range_t *) range)->end; range_exclude = ((range_t *) range)->exclude; /* If range should be excluded do not use it. */ if (range_exclude) return; /* Only single port in range. */ if (range_end == 0 || (range_start == range_end)) { port_sized = (uint16_t) range_start; g_array_append_val (ports_array, port_sized); return; } else { for (i = range_start; i <= range_end; i++) { port_sized = (uint16_t) i; g_array_append_val (ports_array, port_sized); } } } boreas_error_t close_all_needed_sockets (scanner_t *scanner, alive_test_t alive_test) { boreas_error_t error; error = NO_ERROR; if (alive_test & ALIVE_TEST_ICMP) { if ((close (scanner->icmpv4soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } if ((close (scanner->icmpv6soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } } if ((alive_test & ALIVE_TEST_TCP_ACK_SERVICE) || (alive_test & ALIVE_TEST_TCP_SYN_SERVICE)) { if ((close (scanner->tcpv4soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } if ((close (scanner->tcpv6soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } if ((close (scanner->udpv4soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } if ((close (scanner->udpv6soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } } if ((alive_test & ALIVE_TEST_ARP)) { if ((close (scanner->arpv4soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } if ((close (scanner->arpv6soc)) != 0) { g_warning ("%s: Error in close(): %s", __func__, strerror (errno)); error = -1; } } return error; } /** * @brief Set the SO_BROADCAST socket option for given socket. * * @param socket The socket to apply the option to. * * @return 0 on success, boreas_error_t on error. */ static boreas_error_t set_broadcast (int socket) { boreas_error_t error = NO_ERROR; int broadcast = 1; if (setsockopt (socket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof (broadcast)) < 0) { g_warning ("%s: failed to set socket option SO_BROADCAST: %s", __func__, strerror (errno)); error = BOREAS_SETTING_SOCKET_OPTION_FAILED; } return error; } /** * @brief Set a new socket of specified type. * * @param[in] socket_type What type of socket to get. * * @param[out] scanner_socket Location to save the socket into. * * @return 0 on success, boreas_error_t on error. */ static boreas_error_t set_socket (socket_type_t socket_type, int *scanner_socket) { boreas_error_t error = NO_ERROR; int soc = -1; switch (socket_type) { case UDPV4: { soc = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (soc < 0) { g_warning ("%s: failed to open UDPV4 socket: %s", __func__, strerror (errno)); error = BOREAS_OPENING_SOCKET_FAILED; } } break; case UDPV6: { soc = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (soc < 0) { g_warning ("%s: failed to open UDPV4 socket: %s", __func__, strerror (errno)); error = BOREAS_OPENING_SOCKET_FAILED; } } break; case TCPV4: { soc = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (soc < 0) { g_warning ("%s: failed to open TCPV4 socket: %s", __func__, strerror (errno)); error = BOREAS_OPENING_SOCKET_FAILED; } else { int opt = 1; if (setsockopt (soc, IPPROTO_IP, IP_HDRINCL, (char *) &opt, sizeof (opt)) < 0) { g_warning ( "%s: failed to set socket options on TCPV4 socket: %s", __func__, strerror (errno)); error = BOREAS_SETTING_SOCKET_OPTION_FAILED; } } } break; case TCPV6: { soc = socket (AF_INET6, SOCK_RAW, IPPROTO_RAW); if (soc < 0) { g_warning ("%s: failed to open TCPV6 socket: %s", __func__, strerror (errno)); error = BOREAS_OPENING_SOCKET_FAILED; } else { int opt_on = 1; if (setsockopt (soc, IPPROTO_IPV6, IP_HDRINCL, (char *) &opt_on, // IPV6_HDRINCL sizeof (opt_on)) < 0) { g_warning ( "%s: failed to set socket options on TCPV6 socket: %s", __func__, strerror (errno)); error = BOREAS_SETTING_SOCKET_OPTION_FAILED; } } } break; case ICMPV4: { soc = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (soc < 0) { g_warning ("%s: failed to open ICMPV4 socket: %s", __func__, strerror (errno)); error = BOREAS_OPENING_SOCKET_FAILED; } } break; case ARPV6: case ICMPV6: { soc = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (soc < 0) { g_warning ("%s: failed to open ARPV6/ICMPV6 socket: %s", __func__, strerror (errno)); error = BOREAS_OPENING_SOCKET_FAILED; } } break; case ARPV4: { soc = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)); if (soc < 0) { g_warning ("%s: failed to open ARPV4 socket: %s", __func__, strerror (errno)); return BOREAS_OPENING_SOCKET_FAILED; } } break; default: error = BOREAS_OPENING_SOCKET_FAILED; break; } /* set SO_BROADCAST socket option. If not set we get permission denied error * on pinging broadcast address */ if (!error) { error = set_broadcast (soc); if (error != 0) return error; } *scanner_socket = soc; return error; } /** * @brief Set all sockets needed for the chosen detection methods. * * @param scanner Reference to scanner struct. * @param alive_test Methods of alive detection to use provided as bitflag. * * @return 0 on success, boreas_error_t on error. */ boreas_error_t set_all_needed_sockets (scanner_t *scanner, alive_test_t alive_test) { boreas_error_t error = NO_ERROR; if (alive_test & ALIVE_TEST_ICMP) { error = set_socket (ICMPV4, &(scanner->icmpv4soc)); if (error != 0) return error; error = set_socket (ICMPV6, &(scanner->icmpv6soc)); if (error != 0) return error; } if ((alive_test & ALIVE_TEST_TCP_ACK_SERVICE) || (alive_test & ALIVE_TEST_TCP_SYN_SERVICE)) { error = set_socket (TCPV4, &(scanner->tcpv4soc)); if (error != 0) return error; error = set_socket (TCPV6, &(scanner->tcpv6soc)); if (error != 0) return error; error = set_socket (UDPV4, &(scanner->udpv4soc)); if (error != 0) return error; error = set_socket (UDPV6, &(scanner->udpv6soc)); if (error != 0) return error; } if ((alive_test & ALIVE_TEST_ARP)) { error = set_socket (ARPV4, &(scanner->arpv4soc)); if (error != 0) return error; error = set_socket (ARPV6, &(scanner->arpv6soc)); if (error != 0) return error; } return error; } /** * @brief Subtract two hashtables and count the remaining elements. * * The original hashtables are not changed during or after the count operation. * * @param A Base Hashtable. * @param B Hashtable to be subtracted from A. * * @return count of remaining elements in A-B. */ int count_difference (GHashTable *hashtable_A, GHashTable *hashtable_B) { int count = 0; GHashTableIter target_hosts_iter; gpointer key, value; for (g_hash_table_iter_init (&target_hosts_iter, hashtable_A); g_hash_table_iter_next (&target_hosts_iter, &key, &value);) { if (!g_hash_table_contains (hashtable_B, key)) { count++; } } return count; } /** * @brief Check if socket send buffer is empty. * * @param[in] soc Socket. * @param[out] err Set to -1 on error. * * @return 1 if so_sndbug is empyt, else 0. */ static int so_sndbuf_empty (int soc, int *err) { int cur_so_sendbuf = -1; if (ioctl (soc, SIOCOUTQ, &cur_so_sendbuf) == -1) { g_warning ("%s: ioctl error: %s", __func__, strerror (errno)); *err = -1; return 0; } return cur_so_sendbuf ? 0 : 1; } /** * @brief Wait until socket send buffer empty or timeout reached. * * @param soc Socket. * @param timeout Timeout in seconds. */ void wait_until_so_sndbuf_empty (int soc, int timeout) { int cnt = 0; int err = 0; int empty; empty = so_sndbuf_empty (soc, &err); for (; !empty && (err != -1) && (cnt / 10 != timeout); empty = so_sndbuf_empty (soc, &err), cnt++) { usleep (100000); } } gvm-libs-22.20.0/boreas/util.h000066400000000000000000000014661477470532200160200ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef BOREAS_UTIL_H #define BOREAS_UTIL_H #include "alivedetection.h" #include "boreas_error.h" #include uint16_t in_cksum (uint16_t *addr, int len); int get_source_mac_addr (char *, uint8_t *); boreas_error_t get_source_addr_v6 (int *, struct in6_addr *, struct in6_addr *); boreas_error_t get_source_addr_v4 (int *, struct in_addr *, struct in_addr *); void fill_ports_array (gpointer, gpointer); boreas_error_t set_all_needed_sockets (scanner_t *, alive_test_t); boreas_error_t close_all_needed_sockets (scanner_t *, alive_test_t); void wait_until_so_sndbuf_empty (int, int); /* Misc hashtable functions. */ int count_difference (GHashTable *, GHashTable *); #endif /* not BOREAS_UTIL_H */ gvm-libs-22.20.0/boreas/util_tests.c000066400000000000000000000176131477470532200172360ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2020-2023 Greenbone AG * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "util.c" #include #include #include Describe (util); BeforeEach (util) { } AfterEach (util) { } __attribute__ ((weak)) int __real_socket (__attribute__ ((unused)) int domain, __attribute__ ((unused)) int type, __attribute__ ((unused)) int protocol); __attribute__ ((weak)) int __real_setsockopt (__attribute__ ((unused)) int sockfd, __attribute__ ((unused)) int level, __attribute__ ((unused)) int optname, __attribute__ ((unused)) const void *optval, __attribute__ ((unused)) socklen_t optlen); bool g_socket_use_real = true; int __wrap_socket (__attribute__ ((unused)) int domain, __attribute__ ((unused)) int type, __attribute__ ((unused)) int protocol); int __wrap_socket (__attribute__ ((unused)) int domain, __attribute__ ((unused)) int type, __attribute__ ((unused)) int protocol) { if (g_socket_use_real) return __real_socket (domain, type, protocol); return (int) mock (domain, type, protocol); } bool g_setsockopt_use_real = true; int __wrap_setsockopt (__attribute__ ((unused)) int sockfd, __attribute__ ((unused)) int level, __attribute__ ((unused)) int optname, __attribute__ ((unused)) const void *optval, __attribute__ ((unused)) socklen_t optlen); int __wrap_setsockopt (__attribute__ ((unused)) int sockfd, __attribute__ ((unused)) int level, __attribute__ ((unused)) int optname, __attribute__ ((unused)) const void *optval, __attribute__ ((unused)) socklen_t optlen) { if (g_setsockopt_use_real) return __real_setsockopt (sockfd, level, optname, optval, optlen); return (int) mock (sockfd, level, optname, optval, optlen); } /* in_cksum */ Ensure (util, in_cksum_small) { int len; // https://web.archive.org/web/20020916085726/http://www.netfor2.com/checksum.html uint16_t data[] = {0x0100, 0xF203, 0xF4F5, 0xF6F7}; len = sizeof (data); // len is in bytes assert_that (in_cksum ((uint16_t *) data, len), is_equal_to (0x210E)); } Ensure (util, in_cksum_bigger) { int len; // https://en.wikipedia.org/wiki/Internet_checksum uint16_t data[] = {0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0xC0A8, 0x0001, 0xC0A8, 0x00C7}; len = sizeof (data); // len is in bytes assert_that (in_cksum ((uint16_t *) data, len), is_equal_to (0xB861)); } /* set_all_needed_sockets */ Ensure (util, set_all_needed_sockets) { g_socket_use_real = false; g_setsockopt_use_real = false; alive_test_t alive_test; scanner_t scanner = {0}; /* All methods set. */ alive_test = ALIVE_TEST_TCP_ACK_SERVICE | ALIVE_TEST_ICMP | ALIVE_TEST_ARP | ALIVE_TEST_CONSIDER_ALIVE | ALIVE_TEST_TCP_SYN_SERVICE; expect (__wrap_socket, will_return (5), times (8)); expect (__wrap_setsockopt, will_return (5), times (10)); set_all_needed_sockets (&scanner, alive_test); /* Only one method set. */ alive_test = ALIVE_TEST_TCP_ACK_SERVICE; expect (__wrap_socket, will_return (5), times (4)); expect (__wrap_setsockopt, will_return (5), times (6)); set_all_needed_sockets (&scanner, alive_test); /* ALIVE_TEST_CONSIDER_ALIVE set. */ alive_test = ALIVE_TEST_CONSIDER_ALIVE; never_expect (__wrap_socket); never_expect (__wrap_setsockopt); never_expect (set_socket); set_all_needed_sockets (&scanner, alive_test); g_socket_use_real = true; g_setsockopt_use_real = true; } Ensure (util, set_socket) { g_setsockopt_use_real = false; g_socket_use_real = false; int socket_location; /* socket() successful. */ expect (__wrap_socket, will_return (5)); expect (__wrap_setsockopt); expect (__wrap_setsockopt); assert_that (set_socket (TCPV4, &socket_location), is_equal_to (0)); /* socket() error. */ expect (__wrap_socket, will_return (-5)); never_expect (__wrap_setsockopt); assert_that (set_socket (TCPV4, &socket_location), is_equal_to (BOREAS_OPENING_SOCKET_FAILED)); g_socket_use_real = true; g_setsockopt_use_real = true; } Ensure (util, get_source_addr_v4) { int udpv4soc; struct in_addr dst; struct in_addr src; /* Open socket. */ set_socket (UDPV4, &udpv4soc); /* Destination is localhost. */ src.s_addr = INADDR_ANY; dst.s_addr = inet_addr ("127.0.0.1"); get_source_addr_v4 (&udpv4soc, &dst, &src); assert_that (src.s_addr, is_not_equal_to (INADDR_ANY)); /* Destination is example.com. */ src.s_addr = INADDR_ANY; dst.s_addr = inet_addr ("93.184.216.34"); get_source_addr_v4 (&udpv4soc, &dst, &src); assert_that (src.s_addr, is_not_equal_to (INADDR_ANY)); /* Close socket. */ close (udpv4soc); } Ensure (util, get_source_addr_v6) { int udpv6soc; struct in6_addr dst; struct in6_addr src; boreas_error_t error; /* Open socket. */ set_socket (UDPV6, &udpv6soc); /* Localhost. */ inet_pton (AF_INET6, "::FFFF:127.0.0.1", &(dst)); error = get_source_addr_v6 (&udpv6soc, &dst, &src); assert_that (error, is_equal_to (NO_ERROR)); assert_that (!IN6_IS_ADDR_UNSPECIFIED (&src)); /* Dependent on local IPv6 configuration. */ // inet_pton (AF_INET6, "2001:0db8:0:f101::2", &(dst)); // error = get_source_addr_v6 (&udpv6soc, &dst, &src); // assert_that (error, is_equal_to (NO_ERROR)); // assert_that (!IN6_IS_ADDR_UNSPECIFIED (&src)); /* Close socket. */ close (udpv6soc); } Ensure (util, fill_ports_array) { GArray *ports_garray = NULL; const gchar *port_list = NULL; GPtrArray *portranges_array = NULL; /* Port list used in alivedetection.c. */ port_list = "80,137,587,3128,8081"; assert_that (validate_port_range (port_list), is_equal_to (0)); ports_garray = g_array_new (FALSE, TRUE, sizeof (uint16_t)); portranges_array = port_range_ranges (port_list); assert_that (portranges_array, is_not_null); /* Fill ports array with ports from the ranges. */ g_ptr_array_foreach (portranges_array, fill_ports_array, ports_garray); array_free (portranges_array); assert_that (ports_garray->len, is_equal_to (5)); assert_that (g_array_index (ports_garray, uint16_t, 0), is_equal_to (80)); assert_that (g_array_index (ports_garray, uint16_t, 4), is_equal_to (8081)); g_array_free (ports_garray, TRUE); /* Random port list. Duplicates are not removed. */ /* 1,2,5,6,10,11,12,10,10 */ port_list = "1-2,T:5-6,U:10-12,T:10,10"; assert_that (validate_port_range (port_list), is_equal_to (0)); ports_garray = g_array_new (FALSE, TRUE, sizeof (uint16_t)); portranges_array = port_range_ranges (port_list); assert_that (portranges_array, is_not_null); /* Fill ports array with ports from the ranges. */ g_ptr_array_foreach (portranges_array, fill_ports_array, ports_garray); array_free (portranges_array); assert_that (ports_garray->len, is_equal_to (9)); assert_that (g_array_index (ports_garray, uint16_t, 0), is_equal_to (1)); assert_that (g_array_index (ports_garray, uint16_t, 4), is_equal_to (10)); assert_that (g_array_index (ports_garray, uint16_t, 7), is_equal_to (10)); assert_that (g_array_index (ports_garray, uint16_t, 8), is_equal_to (10)); g_array_free (ports_garray, TRUE); } int main (int argc, char **argv) { TestSuite *suite; suite = create_test_suite (); add_test_with_context (suite, util, in_cksum_small); add_test_with_context (suite, util, in_cksum_bigger); add_test_with_context (suite, util, fill_ports_array); add_test_with_context (suite, util, set_all_needed_sockets); add_test_with_context (suite, util, set_socket); add_test_with_context (suite, util, get_source_addr_v4); add_test_with_context (suite, util, get_source_addr_v6); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); } gvm-libs-22.20.0/cliff.toml000066400000000000000000000070321477470532200153720ustar00rootroot00000000000000[changelog] # template for the changelog header header = """ # Changelog\n 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).\n """ # template for the changelog body # https://keats.github.io/tera/docs/#introduction body = """ {%- macro remote_url() -%} https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} {%- endmacro -%} {% if version -%} ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else -%} ## [Unreleased] {% endif -%} {% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} {% for commit in commits %} - {{ commit.message | split(pat="\n") | first | upper_first | trim }}\ {% if commit.remote.username %} by [@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }}){%- endif -%} {% if commit.remote.pr_number %} in \ [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \ {% elif commit.id %} in \ [{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }})\ {%- endif -%} {% endfor %} {% endfor -%} """ # template for the changelog footer footer = """ {%- macro remote_url() -%} https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} {%- endmacro -%} {% for release in releases %} {% if release.version -%} {% if release.previous.version -%} [{{ release.version | trim_start_matches(pat="v") }}]: \ {{ self::remote_url() }}/compare/{{ release.previous.version }}..{{ release.version }} {% endif -%} {% else -%} [unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}..HEAD {% endif -%} {%- endfor -%} """ # remove the leading and trailing whitespace from the templates trim = true [git] # parse the commits based on https://www.conventionalcommits.org conventional_commits = true # filter out the commits that are not following the conventional commits format filter_unconventional = false # process each line of a commit as an individual commit split_commits = false # regex for preprocessing the commit messages commit_preprocessors = [ # remove issue numbers from commits { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" }, ] # regex for parsing and grouping commits commit_parsers = [ { message = "^[a|A]dd", group = ":sparkles: Added" }, { message = "^[c|C]hange", group = ":construction_worker: Changed" }, { message = "^[f|F]ix", group = ":bug: Bug Fixes" }, { message = "^[r|R]emove", group = ":fire: Removed" }, { message = "^[d|D]rop", group = ":fire: Removed" }, { message = "^[d|D]oc", group = ":books: Documentation" }, { message = "^[t|T]est", group = ":white_check_mark: Testing" }, { message = "^[c|C]hore", group = ":wrench: Miscellaneous" }, { message = "^[c|C]i", group = "️:wrench: Miscellaneous" }, { message = "^[m|M]isc", group = ":wrench: Miscellaneous" }, { message = "^[d|D]eps", group = ":ship: Dependencies" }, ] # filter out the commits that are not matched by commit parsers filter_commits = true # sort the tags topologically topo_order = false # sort the commits inside sections by oldest/newest order sort_commits = "oldest" gvm-libs-22.20.0/cmake/000077500000000000000000000000001477470532200144705ustar00rootroot00000000000000gvm-libs-22.20.0/cmake/MacroAddUnitTest.cmake000066400000000000000000000005161477470532200206460ustar00rootroot00000000000000macro (ADD_UNIT_TEST _testName _testSource) add_executable(${_testName} ${_testSource}) target_link_libraries(${_testName} ${CGREEN_LIBRARIES} ${ARGN}) target_include_directories(${_testName} PRIVATE ${CGREEN_INCLUDE_DIRS}) add_test(NAME ${_testName} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${_testName}) endmacro (ADD_UNIT_TEST) gvm-libs-22.20.0/doc/000077500000000000000000000000001477470532200141555ustar00rootroot00000000000000gvm-libs-22.20.0/doc/CMakeLists.txt000066400000000000000000000027341477470532200167230ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2011-2023 Greenbone AG # # SPDX-License-Identifier: GPL-2.0-or-later ## build include (FindDoxygen) if (NOT DOXYGEN_EXECUTABLE) message (STATUS "WARNING: Doxygen is required to build the HTML docs.") else (NOT DOXYGEN_EXECUTABLE) add_custom_target (doc COMMENT "Building documentation..." DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ${CMAKE_CURRENT_BINARY_DIR}/.built-html) add_custom_command (OUTPUT .built-html COMMAND sh ARGS -c \"${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile && touch ${CMAKE_CURRENT_BINARY_DIR}/.built-html\;\" DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) add_custom_target (doc-full COMMENT "Building documentation..." DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_full ${CMAKE_CURRENT_BINARY_DIR}/.built-html_full) add_custom_command (OUTPUT .built-html_full COMMAND sh ARGS -c \"${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_full && touch ${CMAKE_CURRENT_BINARY_DIR}/.built-html_full\;\" DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_full) add_custom_target (doc-xml COMMENT "Building documentation (XML)..." DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_xml ${CMAKE_CURRENT_BINARY_DIR}/.built-xml) add_custom_command (OUTPUT .built-xml COMMAND sh ARGS -c \"${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_xml && touch ${CMAKE_CURRENT_BINARY_DIR}/.built-xml\;\" DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile_xml) endif (NOT DOXYGEN_EXECUTABLE) gvm-libs-22.20.0/doc/Doxyfile.in000066400000000000000000003113471477470532200163010ustar00rootroot00000000000000# Doxyfile 1.8.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "Greenbone Vulnerability Management Libraries" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @CPACK_PACKAGE_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = @CMAKE_BINARY_DIR@/doc/generated # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = "TODO=\todo" # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = YES # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = @CMAKE_SOURCE_DIR@/base \ @CMAKE_SOURCE_DIR@/gmp \ @CMAKE_SOURCE_DIR@/openvasd \ @CMAKE_SOURCE_DIR@/osp \ @CMAKE_SOURCE_DIR@/util # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ \ @CMAKE_SOURCE_DIR@/doc # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was # compiled with the --with-libclang option. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /