From 7753f897ce53ec94c09fd8b3730985e7ce668aa5 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Thu, 11 Jul 2024 09:30:53 +0200 Subject: [PATCH 1/7] Add: Added conversion routines for different CPE notation formats. Added routines to read a v2.2-conformant URI of a CPE or a formatted string binding of a CPE into some kind of WFN struct. Added routines to convert the WFN struct into a formatted string binding or a CPE v2.2-conformant URI. Added routines to convert a formatted string binding into a v2.2-conformant URI and vice versa. --- CMakeLists.txt | 2 +- util/CMakeLists.txt | 22 +- util/cpeutils.c | 1108 +++++++++++++++++++++++++++++++++++++++++ util/cpeutils.h | 108 ++++ util/cpeutils_tests.c | 188 +++++++ 5 files changed, 1425 insertions(+), 3 deletions(-) create mode 100644 util/cpeutils.c create mode 100644 util/cpeutils.h create mode 100644 util/cpeutils_tests.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 05fe9ac2..100da742 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,7 +229,7 @@ if (BUILD_TESTS AND NOT SKIP_SRC) add_custom_target (tests DEPENDS array-test alivedetection-test boreas_error-test boreas_io-test - cli-test cvss-test ping-test sniffer-test util-test networking-test + cli-test cpeutils-test cvss-test ping-test sniffer-test util-test networking-test passwordbasedauthentication-test xmlutils-test version-test osp-test nvti-test hosts-test) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 4e8378b2..95c94235 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -109,11 +109,11 @@ endif (BUILD_WITH_LDAP) include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIRS}) -set (FILES passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c +set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c xmlutils.c) -set (HEADERS passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h +set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h uuidutils.h xmlutils.h) @@ -161,6 +161,24 @@ if (BUILD_TESTS) add_custom_target (tests-passwordbasedauthentication DEPENDS passwordbasedauthentication-test) + add_executable (cpeutils-test + EXCLUDE_FROM_ALL + cpeutils_tests.c) + + add_test (cpeutils-test cpeutils-test) + + target_include_directories (cpeutils-test PRIVATE ${CGREEN_INCLUDE_DIRS}) + + target_link_libraries (cpeutils-test ${CGREEN_LIBRARIES} + ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} + ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} + ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} + ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} + ${LINKER_HARDENING_FLAGS}) + + add_custom_target (tests-cpeutils + DEPENDS cpeutils-test) + add_executable (xmlutils-test EXCLUDE_FROM_ALL xmlutils_tests.c) diff --git a/util/cpeutils.c b/util/cpeutils.c new file mode 100644 index 00000000..fc66c9aa --- /dev/null +++ b/util/cpeutils.c @@ -0,0 +1,1108 @@ +/* SPDX-FileCopyrightText: 2009-2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/** + * @file + * @brief Functions to convert different CPE notations into each other. + * + * This library provides functions to read the CPE 2.2 URI binding of a + * CPE or the CPE 2.3 formatted string binding of a CPE into a CPE struct + * that corresponds to the WFN naming of a CPE. Further functions to convert + * the CPE struct into the different bindings are provided. + */ + +#include "cpeutils.h" + +#include +#include +#include +#include +#include + +#undef G_LOG_DOMAIN +/** + * @brief GLib logging domain. + */ +#define G_LOG_DOMAIN "libgvm util" + +/** + * @brief Convert a URI CPE to a formatted string CPE. + * + * @param[in] uri_cpe A CPE v2.2-conformant URI. + * + * @return A formatted string CPE. + */ +char * +uri_cpe_to_fs_cpe (const char *uri_cpe) +{ + cpe_struct_t cpe; + + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + return(cpe_struct_to_fs_cpe (&cpe)); +} + +/** + * @brief Convert a formatted string CPE to a URI CPE. + * + * @param[in] fs_cpe A formatted string CPE. + * + * @return A CPE v2.2-conformant URI. + */ +char * +fs_cpe_to_uri_cpe (const char *fs_cpe) +{ + cpe_struct_t cpe; + + cpe_struct_init (&cpe); + fs_cpe_to_cpe_struct (fs_cpe, &cpe); + return(cpe_struct_to_uri_cpe (&cpe)); +} + +/** + * @brief Read a URI CPE into the CPE struct. + * + * @param[in] uri_cpe A CPE v2.2-conformant URI. + * + * @param[out] cpe Pointer to the filled CPE struct. + */ +void +uri_cpe_to_cpe_struct (const char *uri_cpe, cpe_struct_t *cpe) +{ + char *uri_component; + + uri_component = get_uri_component (uri_cpe, 1); + cpe->part = decode_uri_component (uri_component); + g_free (uri_component); + uri_component = get_uri_component (uri_cpe, 2); + cpe->vendor = decode_uri_component (uri_component); + g_free (uri_component); + uri_component = get_uri_component (uri_cpe, 3); + cpe->product = decode_uri_component (uri_component); + g_free (uri_component); + uri_component = get_uri_component (uri_cpe, 4); + cpe->version = decode_uri_component (uri_component); + g_free (uri_component); + uri_component = get_uri_component (uri_cpe, 5); + cpe->update = decode_uri_component (uri_component); + g_free (uri_component); + uri_component = get_uri_component (uri_cpe, 6); + if (strcmp (uri_component, "") == 0 || + strcmp (uri_component, "-") == 0 || + *uri_component != '~') + cpe->edition = decode_uri_component (uri_component); + else + unpack_sixth_uri_component (uri_component, cpe); + g_free (uri_component); + + uri_component = get_uri_component (uri_cpe, 7); + cpe->language = decode_uri_component (uri_component); + g_free (uri_component); +} + +/** + * @brief Convert a CPE struct into a URI CPE. + * + * @param[in] cpe A pointer to the CPE struct. + * + * @return A CPE v2.2-conformant URI. + */ +char * +cpe_struct_to_uri_cpe (const cpe_struct_t *cpe) +{ + GString *uri_cpe; + char *bind_cpe_component; + uri_cpe = g_string_new ("cpe:/"); + + bind_cpe_component = bind_cpe_component_for_uri (cpe->part); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->vendor); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->product); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->version); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->update); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = pack_sixth_uri_component (cpe); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->language); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + + char *result = g_string_free (uri_cpe, FALSE); + trim_pct (result); + return (result); +} + +/** + * @brief Read a formatted string CPE into the CPE struct. + * + * @param[in] fs_cpe A formatted string CPE. + * + * @param[out] cpe Pointer to the filled CPE struct. + */ +void +fs_cpe_to_cpe_struct (const char *fs_cpe, cpe_struct_t *cpe) +{ + char *fs_component; + + fs_component = get_fs_component (fs_cpe, 2); + cpe->part = unbind_fs_component (fs_component); + fs_component = get_fs_component (fs_cpe, 3); + cpe->vendor = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 4); + cpe->product = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 5); + cpe->version = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 6); + cpe->update = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 7); + cpe->edition = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 8); + cpe->language = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 9); + cpe->sw_edition = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 10); + cpe->target_sw = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 11); + cpe->target_hw = unbind_fs_component (fs_component); + g_free (fs_component); + fs_component = get_fs_component (fs_cpe, 12); + cpe->other = unbind_fs_component (fs_component); + g_free (fs_component); +} + +/** + * @brief Convert a CPE struct into a formatted string CPE. + * + * @param[in] cpe A pointer to the CPE struct. + * + * @return A formatted string CPE. + */ +char * +cpe_struct_to_fs_cpe (const cpe_struct_t *cpe) +{ + GString *fs_cpe; + char *bind_cpe_component; + + fs_cpe = g_string_new ("cpe:2.3:"); + + bind_cpe_component = bind_cpe_component_for_fs (cpe->part); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->vendor); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->product); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->version); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->update); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->edition); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->language); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->sw_edition); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->target_sw); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->target_hw); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->other); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s", bind_cpe_component); + g_free (bind_cpe_component); + } + return (g_string_free (fs_cpe, FALSE)); +} + +/** + * @brief Get the indexth component of a URI CPE. + * + * @param[in] uri_cpe The URI CPE. + * @param[in] index The number of the component to get. + * + * @return The indexth component of the URI CPE. + */ +static char * +get_uri_component(const char *uri_cpe, int index) +{ + char *component = NULL; + char *c; + char *component_start, *component_end; + + if (!uri_cpe) + return NULL; + + c = (char *) uri_cpe; + + /* find start of component */ + for (int i = 0; *c != '\0' && i < index; c++) + { + if (*c == ':') + i++; + } + + if (index == 1 && *c != '\0') + c++; + + component_start = c; + + /* find end of component */ + if (*component_start == '\0') + component_end = component_start; + else + { + for (c = component_start; *c != '\0' && *c != ':'; c++); + } + + component_end = c; + + if (component_start >= component_end || component_end == 0) + component = (char*) g_strdup (""); + else + str_cpy (&component, component_start, component_end-component_start); + + return component; +} + +/** + * @brief Decode a component of a URI CPE. + * + * @param[in] component The component to decode. + * + * @return The decoded component of the URI CPE. + */ +static char * +decode_uri_component (const char *component) +{ + GString *decoded_component; + char *tmp_component; + char code_a[4], code_b[4], code_c[4]; + long unsigned int index; + gboolean embedded; + + if (!component) + return (NULL); + + if (strcmp (component, "") == 0 || strcmp (component, " ") == 0) + { + return (g_strdup ("ANY")); + } + if (strcmp (component, "-") == 0) + { + return (g_strdup ("NA")); + } + + tmp_component = g_strdup (component); + + /* set all characters to lowercase */ + char *c = tmp_component; + for ( ; *c; c++) *c = tolower (*c); + + index = 0; + embedded = FALSE; + decoded_component = g_string_new (""); + + char l; + while (index < strlen (tmp_component)) + { + l = *(tmp_component+index); + + if (l == '.' || l == '-' || l == '~') + { + g_string_append_printf (decoded_component, "\\%c", l); + index++; + embedded = TRUE; + continue; + } + if (l != '%') + { + g_string_append_printf (decoded_component, "%c", l); + index++; + embedded = TRUE; + continue; + } + + get_code (code_a, tmp_component+index); + if (strcmp (code_a, "%01") == 0) + { + if (index >= 3) + get_code (code_b, tmp_component+index-3); + else + code_b[0] = '0'; + if (strlen (tmp_component) >= index + 6) + get_code (code_c, tmp_component+index+3); + else + code_c[0] = '0'; + if ((index == 0 || index == strlen (tmp_component)-3) || + (!embedded && strcmp (code_b, "%01")) || + (embedded && strcmp (code_c, "%01"))) + { + g_string_append_printf (decoded_component, "%c", '?'); + index = index + 3; + continue; + } + else + { + g_free (tmp_component); + return (NULL); + } + } + + if (strcmp (code_a, "%02") == 0) + { + if (index == 0 || index == strlen (tmp_component)-3) + { + g_string_append_printf (decoded_component, "%c", '*'); + index = index + 3; + continue; + } + else + { + g_free (tmp_component); + return (NULL); + } + } + if (strcmp (code_a, "%21") == 0) + g_string_append_printf (decoded_component, "%s", "\\!"); + else if (strcmp (code_a, "%22") == 0) + g_string_append_printf (decoded_component, "%s", "\\\""); + else if (strcmp (code_a, "%23") == 0) + g_string_append_printf (decoded_component, "%s", "\\#"); + else if (strcmp (code_a, "%24") == 0) + g_string_append_printf (decoded_component, "%s", "\\$"); + else if (strcmp (code_a, "%25") == 0) + g_string_append_printf (decoded_component, "%s", "\\%"); + else if (strcmp (code_a, "%26") == 0) + g_string_append_printf (decoded_component, "%s", "\\&"); + else if (strcmp (code_a, "%27") == 0) + g_string_append_printf (decoded_component, "%s", "\\'"); + else if (strcmp (code_a, "%28") == 0) + g_string_append_printf (decoded_component, "%s", "\\("); + else if (strcmp (code_a, "%29") == 0) + g_string_append_printf (decoded_component, "%s", "\\)"); + else if (strcmp (code_a, "%2a") == 0) + g_string_append_printf (decoded_component, "%s", "\\*"); + else if (strcmp (code_a, "%2b") == 0) + g_string_append_printf (decoded_component, "%s", "\\+"); + else if (strcmp (code_a, "%2c") == 0) + g_string_append_printf (decoded_component, "%s", "\\,"); + else if (strcmp (code_a, "%2f") == 0) + g_string_append_printf (decoded_component, "%s", "\\/"); + else if (strcmp (code_a, "%3a") == 0) + g_string_append_printf (decoded_component, "%s", "\\:"); + else if (strcmp (code_a, "%3b") == 0) + g_string_append_printf (decoded_component, "%s", "\\;"); + else if (strcmp (code_a, "%3c") == 0) + g_string_append_printf (decoded_component, "%s", "\\<"); + else if (strcmp (code_a, "%3d") == 0) + g_string_append_printf (decoded_component, "%s", "\\="); + else if (strcmp (code_a, "%3e") == 0) + g_string_append_printf (decoded_component, "%s", "\\>"); + else if (strcmp (code_a, "%3f") == 0) + g_string_append_printf (decoded_component, "%s", "\\?"); + else if (strcmp (code_a, "%40") == 0) + g_string_append_printf (decoded_component, "%s", "\\@"); + else if (strcmp (code_a, "%5b") == 0) + g_string_append_printf (decoded_component, "%s", "\\["); + else if (strcmp (code_a, "%5c") == 0) + g_string_append_printf (decoded_component, "%s", "\\\\"); + else if (strcmp (code_a, "%5d") == 0) + g_string_append_printf (decoded_component, "%s", "\\]"); + else if (strcmp (code_a, "%5e") == 0) + g_string_append_printf (decoded_component, "%s", "\\^"); + else if (strcmp (code_a, "%60") == 0) + g_string_append_printf (decoded_component, "%s", "\\`"); + else if (strcmp (code_a, "%7b") == 0) + g_string_append_printf (decoded_component, "%s", "\\{"); + else if (strcmp (code_a, "%7c") == 0) + g_string_append_printf (decoded_component, "%s", "\\|"); + else if (strcmp (code_a, "%7d") == 0) + g_string_append_printf (decoded_component, "%s", "\\}"); + else if (strcmp (code_a, "%7e") == 0) + g_string_append_printf (decoded_component, "%s", "\\~"); + else + { + g_free (tmp_component); + return (NULL); + } + index = index+3; + embedded = TRUE; + } + + g_free (tmp_component); + return (g_string_free (decoded_component, FALSE)); +} + +/** + * @brief Unpack the sixth component of a URI CPE. + * + * @param[in] component The component to unpack. + * + * @param[out] cpe Pointer to the CPE struct where the unpacked and + * decoded values of the component are stored. + */ +static void +unpack_sixth_uri_component (const char *component, cpe_struct_t *cpe) +{ + const char *start = component+1; + const char *end; + + char *edition, *sw_edition, *target_sw, *target_hw, *other; + + end = strchr (start, '~'); + if (start >= end || end == NULL) + edition = strdup (""); + else + str_cpy (&edition, start, end-start); + + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + sw_edition = strdup (""); + else + str_cpy (&sw_edition, start, end-start); + + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + target_sw = strdup (""); + else + str_cpy (&target_sw, start, end-start); + + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + target_hw = strdup (""); + else + str_cpy (&target_hw, start, end-start); + + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + other = strdup (""); + else + str_cpy (&other, start, end-start); + + cpe->edition = decode_uri_component (edition); + g_free (edition); + cpe->sw_edition = decode_uri_component (sw_edition); + g_free (sw_edition); + cpe->target_sw = decode_uri_component (target_sw); + g_free (target_sw); + cpe->target_hw = decode_uri_component (target_hw); + g_free (target_hw); + cpe->other = decode_uri_component (other); + g_free (other); +} + +/** + * @brief Get the indexth component of a formatted string CPE. + * + * @param[in] fs_cpe The formatted string CPE. + * @param[in] index The number of the component to get. + * + * @return The indexth component of the formatted string CPE. + */ +static char * +get_fs_component(const char *fs_cpe, int index) +{ + char *component = NULL; + char *c; + char *component_start, *component_end; + + if (!fs_cpe) + return NULL; + + if (*fs_cpe == '\0') + return ((char*) g_strdup ("")); + + c = (char *) fs_cpe; + + /* find start of component */ + if (index == 0) + component_start = c; + else + { + for (int i = 0; *c != '\0' && i < index; c++) + { + if (*c == ':' && c == fs_cpe) + i++; + else if (c > fs_cpe && *c == ':' && *(c-1) != '\\') + i++; + } + component_start = c; + } + + /* find end of component */ + if (*component_start == '\0') + component_end = component_start; + else + { + for (c = component_start; *c != '\0' && *c != ':'; c++); + } + + component_end = c; + + if (component_start >= component_end || component_end == NULL) + component = (char*) g_strdup (""); + else + str_cpy (&component, component_start, component_end-component_start); + + return component; +} + +/** + * @brief Unbind a formatted string CPE component. + * + * @param[in] component The component to unbind. + * + * @return The unbound component of the formatted string CPE. + */ +static char * +unbind_fs_component (char *component) +{ + if (strcmp (component, "*") == 0) + return ((char *) g_strdup("ANY")); + if (strcmp (component, "-") == 0) + return ((char *) g_strdup("NA")); + return (add_quoting (component)); +} + +/** + * @brief Handle the quoting for an unbind formatted string CPE component. + * + * @param[in] component The component to add the quotings to. + * + * @return The component of the formatted string CPE with all necessary + * quotes added. + */ +static char * +add_quoting (const char *component) +{ + GString *quoted_component; + char *tmp_component; + char *c; + gboolean embedded; + + if (!component) + return (NULL); + + quoted_component = g_string_new (""); + tmp_component = (char *) g_strdup (component); + embedded = FALSE; + + /* set all characters to lowercase */ + for (c = tmp_component; *c; c++) *c = tolower (*c); + + c = tmp_component; + while (*c != '\0') + { + if (is_alpha_num(*c)) + { + g_string_append_printf (quoted_component, "%c", *c); + c++; + embedded = TRUE; + continue; + } + if (*c == '\\') + { + c++; + if (*c != '\0') + { + g_string_append_printf (quoted_component, "\\%c", *c); + embedded = TRUE; + c++; + continue; + } + } + if (*c == '*') + { + if ((c == tmp_component) || (c == tmp_component+strlen (tmp_component -1))) + { + g_string_append_printf (quoted_component, "%c", *c); + c++; + embedded = TRUE; + continue; + } + else + { + g_free (tmp_component); + return (NULL); + } + } + if (*c == '?') + { + if ((c == tmp_component) || + (c == tmp_component+strlen (tmp_component -1)) || + (!embedded && (c > tmp_component) && (*(c-1) == '?')) || + (embedded && *(c+1) == '?')) + { + g_string_append_printf (quoted_component, "%c", *c); + c++; + embedded = FALSE; + continue; + } + else + { + g_free (tmp_component); + return (NULL); + } + } + g_string_append_printf (quoted_component, "\\%c", *c); + c++; + embedded = TRUE; + } + g_free (tmp_component); + return (g_string_free (quoted_component, FALSE)); +} + +/** + * @brief Bind a CPE component for a URI CPE. + * + * @param[in] component The component to bind. + * + * @return The bound component for the URI CPE. + */ +static char * +bind_cpe_component_for_uri (const char *component) +{ + if (!component) + return (g_strdup("")); + if (strcmp (component, "") == 0) + return (g_strdup("")); + if (strcmp(component, "ANY") == 0) + return (g_strdup ("")); + if (strcmp(component, "NA") == 0) + return (g_strdup ("-")); + return (transform_for_uri (component)); +} + +/** + * @brief Transform a CPE component for a URI CPE. + * + * @param[in] component The component to transform. + * + * @return The transformed component for the URI CPE. + */ +static char * +transform_for_uri (const char *component) +{ + GString *result; + char *tmp_component; + char *c; + + if (!component) + return (g_strdup("")); + if (strcmp (component, "") == 0) + return (g_strdup("")); + + tmp_component = g_strdup(component); + + /* set all characters to lowercase */ + for (c = tmp_component; *c; c++) *c = tolower (*c); + + result = g_string_new (""); + c = tmp_component; + + while (*c) + { + if (is_alpha_num (*c) && *c != '-') + { + g_string_append_printf (result, "%c", *c); + c++; + continue; + } + if (*c == '\\') + { + c++; + if (*c != '\0') + { + g_string_append_printf (result, "%s", pct_encode(*c)); + c++; + } + continue; + } + if (*c == '?') + g_string_append_printf (result, "%s", "%01"); + if (*c == '*') + g_string_append_printf (result, "%s", "%02"); + c++; + } + g_free (tmp_component); + return (g_string_free (result, FALSE)); +} + +/** + * @brief Percent encode special characters. + * + * @param[in] c The character to encode. + * + * @return The percent code. + */ +static char * +pct_encode (char c) +{ + if (c == '!') return ("%21"); + if (c == '"') return ("%22"); + if (c == '#') return ("%23"); + if (c == '$') return ("%24"); + if (c == '%') return ("%25"); + if (c == '&') return ("%26"); + if (c == '\'') return ("%27"); + if (c == '(') return ("%28"); + if (c == ')') return ("%29"); + if (c == '*') return ("%2a"); + if (c == '+') return ("%2b"); + if (c == ',') return ("%2c"); + if (c == '-') return ("-"); + if (c == '.') return ("."); + if (c == '/') return ("%2f"); + if (c == ':') return ("%3a"); + if (c == ';') return ("%3b"); + if (c == '<') return ("%3c"); + if (c == '=') return ("%3d"); + if (c == '>') return ("%3e"); + if (c == '?') return ("%3f"); + if (c == '@') return ("%40"); + if (c == '[') return ("%5b"); + if (c == '\\') return ("%5c"); + if (c == ']') return ("%5d"); + if (c == '^') return ("%5e"); + if (c == '`') return ("%60"); + if (c == '{') return ("%7b"); + if (c == '|') return ("%7c"); + if (c == '}') return ("%7d"); + if (c == '~') return ("%7e"); + return (""); +} + +/** + * @brief Pack the sixth component of a URI CPE. + * + * @param[in] component The CPE struct with the components to pack into the + * sixth component of a URI CPE. + * + * @return The packed component for the URI CPE. + */ +static char * +pack_sixth_uri_component (const cpe_struct_t *cpe) +{ + if ((cpe->sw_edition == NULL || strcmp (cpe->sw_edition, "") == 0) && + (cpe->target_sw == NULL || strcmp (cpe->target_sw, "") == 0) && + (cpe->target_hw == NULL || strcmp (cpe->target_hw, "") == 0) && + (cpe->other == NULL || strcmp (cpe->other, "") == 0)) + { + if (strcmp(cpe->edition, "ANY") == 0) + return (g_strdup ("")); + if (strcmp(cpe->edition, "NA") == 0) + return (g_strdup ("-")); + return (g_strdup (cpe->edition)); + } + + char *edition = bind_cpe_component_for_uri (cpe->edition); + char *sw_edition = bind_cpe_component_for_uri (cpe->sw_edition); + char *target_sw = bind_cpe_component_for_uri (cpe->target_sw); + char *target_hw = bind_cpe_component_for_uri (cpe->target_hw); + char *other = bind_cpe_component_for_uri (cpe->other); + GString *component; + component = g_string_new (""); + if (!((!sw_edition || strcmp (sw_edition, "") == 0) && + (!target_sw || strcmp (target_sw, "") == 0) && + (!target_hw || strcmp (target_hw, "") == 0) && + (!other || strcmp (other, "") == 0) )) + g_string_append_printf (component, "~%s~%s~%s~%s~%s", + edition, + sw_edition, + target_sw, + target_hw, + other); + else if (edition) + g_string_append_printf (component, "%s", edition); + + if (edition) + g_free (edition); + if (sw_edition) + g_free (sw_edition); + if (target_sw) + g_free (target_sw); + if (target_hw) + g_free (target_hw); + if (other) + g_free (other); + return (g_string_free (component, FALSE)); +} + +/** + * @brief Bind a CPE component for a formatted string CPE. + * + * @param[in] component The component to bind. + * + * @return The bound component for the formatted string CPE. + */ +static char * +bind_cpe_component_for_fs (const char *component) +{ + if (!component) + return (g_strdup("*")); + if (strcmp (component, "") == 0) + return (g_strdup("*")); + if (strcmp(component, "ANY") == 0) + return (g_strdup ("*")); + if (strcmp(component, "NA") == 0) + return (g_strdup ("-")); + return (process_quoted_chars (component)); +} + + +/** + * @brief Process the quoted characters of a CPE component for + * a formatted string CPE. + * + * @param[in] component The component to process. + * + * @return The processed component for the formatted string CPE. + */ +static char * +process_quoted_chars (const char *component) +{ + if (!component) + return (g_strdup("")); + if (strcmp (component, "") == 0) + return (g_strdup("")); + + GString *fs_component; + fs_component = g_string_new (""); + char *c = (char *) component; + char next_c; + + while (*c) + { + if (*c != '\\') + { + g_string_append_printf (fs_component, "%c", *c); + c++; + } + else + { + next_c = *(c+1); + if (next_c == '.' || next_c == '-' || next_c == '_') + { + g_string_append_printf (fs_component, "%c", next_c); + c += 2; + } + else if (next_c) + { + g_string_append_printf (fs_component, "\\%c", next_c); + c += 2; + } + } + } + return (g_string_free (fs_component, FALSE)); +} + +/** + * @brief Initialize a CPE struct. + * + * @param[in/out] cpe The pointer to the CPE to initialize. + */ +void +cpe_struct_init (cpe_struct_t *cpe) +{ + cpe->part = NULL; + cpe->vendor = NULL; + cpe->product = NULL; + cpe->version = NULL; + cpe->update = NULL; + cpe->edition = NULL; + cpe->sw_edition = NULL; + cpe->target_sw = NULL; + cpe->target_hw = NULL; + cpe->other = NULL; + cpe->language = NULL; + + /* to keep the compiler satisfied */ + cpe->part = cpe->part; +} + +/** + * @brief Free a CPE struct. + * + * @param[in/out] cpe The CPE to be freed. + */ +void +cpe_struct_free (cpe_struct_t *cpe) +{ + if (cpe->part) + g_free (cpe->part); + if (cpe->vendor) + g_free (cpe->vendor); + if (cpe->product) + g_free (cpe->product); + if (cpe->version) + g_free (cpe->version); + if (cpe->update) + g_free (cpe->update); + if (cpe->edition) + g_free (cpe->edition); + if (cpe->sw_edition) + g_free (cpe->sw_edition); + if (cpe->target_sw) + g_free (cpe->target_sw); + if (cpe->target_hw) + g_free (cpe->target_hw); + if (cpe->other) + g_free (cpe->other); + if (cpe->language) + g_free (cpe->language); +} + + +/** + * @brief Cut of trailing ':' signs. + * + * @param[in/out] str The string to be processed. + */ +static void +trim_pct (char *str) +{ + char *c; + + if (!str) + return; + c = str+strlen(str)-1; + while (c >= str) + { + if (*c == ':') + { + *c = '\0'; + c--; + } + else + break; + } +} + +/** + * @brief Get the percent code from the start of a string. + * + * @param[in] str The string to get the code from. + * @param[out] code The percent code. + */ +static void +get_code (char *code, const char *str) +{ + code[0] = *str; + code[1] = *(str+1); + code[2] = *(str+2); + code[3] = '\0'; +} + +/** + * @brief Copy size characters of a string to an newly allocated new string. + * + * @param[in] src The string the first size characters are to be copied from. + * @param[in] size The number of characters to copy. + * + * @param[out] dest The copy of the first size characters of src. + */ +static void +str_cpy (char **dest, const char *src, int size) +{ + *dest = (char *) g_malloc (size + 1); + memset (*dest, 0, size + 1); + strncpy (*dest, src, size); +} + +/** + * @brief Return if a character is alpha or numeric or '_'. + * + * @param[in] c The character to be checked. + * + * @return The boolean result. + */ +static gboolean +is_alpha_num (char c) +{ + return (isalpha(c) || isdigit(c) || c == '_'); +} + diff --git a/util/cpeutils.h b/util/cpeutils.h new file mode 100644 index 00000000..dedca3fa --- /dev/null +++ b/util/cpeutils.h @@ -0,0 +1,108 @@ +/* SPDX-FileCopyrightText: 2009-2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/** + * @file + * @brief Headers for CPE utils. + */ + +#ifndef _GVM_CPEUTILS_H +#define _GVM_CPEUTILS_H + +#include +#include + +/** + * @brief XML context. + * + * This structure is used to represent the WFN naming of a CPE. + */ +typedef struct +{ +char *part; +char *vendor; +char *product; +char *version; +char *update; +char *edition; +char *sw_edition; +char *target_sw; +char *target_hw; +char *other; +char *language; +} cpe_struct_t; + +char * +uri_cpe_to_fs_cpe (const char *); + +char * +fs_cpe_to_uri_cpe (const char *); + +void +uri_cpe_to_cpe_struct (const char *, cpe_struct_t *); + +char * +cpe_struct_to_uri_cpe (const cpe_struct_t *); + +void +fs_cpe_to_cpe_struct (const char *, cpe_struct_t *); + +char * +cpe_struct_to_fs_cpe (const cpe_struct_t *); + +static char * +get_uri_component(const char *, int); + +static char * +decode_uri_component (const char *); + +static void +unpack_sixth_uri_component (const char *, cpe_struct_t *); + +static char * +get_fs_component(const char *, int); + +static char * +unbind_fs_component (char *); + +static char * +add_quoting (const char *); + +static char * +bind_cpe_component_for_uri (const char *); + +static char * +transform_for_uri (const char *); + +static char * +pct_encode (char); + +static char * +pack_sixth_uri_component (const cpe_struct_t *); + +static char * +bind_cpe_component_for_fs (const char *); + +static char * +process_quoted_chars (const char *); + +void +cpe_struct_init (cpe_struct_t *); + +void +cpe_struct_free (cpe_struct_t *); + +static void +trim_pct (char *); + +static void +get_code (char *, const char *); + +static void +str_cpy (char **, const char *, int); + +static gboolean +is_alpha_num (char); +#endif diff --git a/util/cpeutils_tests.c b/util/cpeutils_tests.c new file mode 100644 index 00000000..3896a2ef --- /dev/null +++ b/util/cpeutils_tests.c @@ -0,0 +1,188 @@ +/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "cpeutils.c" + +#include +#include + +Describe (cpeutils); +BeforeEach (cpeutils) +{ +} + +AfterEach (cpeutils) +{ +} + +/* parse_entity */ + +Ensure (cpeutils, uri_cpe_to_cpe_struct) +{ + cpe_struct_t cpe; + char * uri_cpe; + + uri_cpe = "cpe:/a:microsoft:internet_explorer:8.0.6001:beta"; + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + assert_that (cpe.part, is_equal_to_string ("a")); + assert_that (cpe.vendor, is_equal_to_string ("microsoft")); + assert_that (cpe.product, is_equal_to_string ("internet_explorer")); + assert_that (cpe.version, is_equal_to_string ("8\\.0\\.6001")); + assert_that (cpe.update, is_equal_to_string ("beta")); + assert_that (cpe.edition, is_equal_to_string ("ANY")); + assert_that (cpe.language, is_equal_to_string ("ANY")); + cpe_struct_free (&cpe); + + uri_cpe = "cpe:/a:microsoft:internet_explorer:8.%2a:sp%3f"; + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + assert_that (cpe.part, is_equal_to_string ("a")); + assert_that (cpe.vendor, is_equal_to_string ("microsoft")); + assert_that (cpe.product, is_equal_to_string ("internet_explorer")); + assert_that (cpe.version, is_equal_to_string ("8\\.\\*")); + assert_that (cpe.update, is_equal_to_string ("sp\\?")); + assert_that (cpe.edition, is_equal_to_string ("ANY")); + assert_that (cpe.language, is_equal_to_string ("ANY")); + cpe_struct_free (&cpe); + + uri_cpe = "cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~"; + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + assert_that (cpe.part, is_equal_to_string ("a")); + assert_that (cpe.vendor, is_equal_to_string ("hp")); + assert_that (cpe.product, is_equal_to_string ("insight_diagnostics")); + assert_that (cpe.version, is_equal_to_string ("7\\.4\\.0\\.1570")); + assert_that (cpe.update, is_equal_to_string ("ANY")); + assert_that (cpe.edition, is_equal_to_string ("ANY")); + assert_that (cpe.sw_edition, is_equal_to_string ("online")); + assert_that (cpe.target_sw, is_equal_to_string ("win2003")); + assert_that (cpe.target_hw, is_equal_to_string ("x64")); + assert_that (cpe.other, is_equal_to_string ("ANY")); + assert_that (cpe.language, is_equal_to_string ("ANY")); + cpe_struct_free (&cpe); + + uri_cpe = "This is a ~:SIGNAL:~ test."; + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + cpe_struct_free (&cpe); +} + +Ensure (cpeutils, fs_cpe_to_cpe_struct) +{ + cpe_struct_t cpe; + char * fs_cpe; + + fs_cpe = "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"; + cpe_struct_init (&cpe); + fs_cpe_to_cpe_struct (fs_cpe, &cpe); + assert_that (cpe.part, is_equal_to_string ("a")); + assert_that (cpe.vendor, is_equal_to_string ("microsoft")); + assert_that (cpe.product, is_equal_to_string ("internet_explorer")); + assert_that (cpe.version, is_equal_to_string ("8\\.0\\.6001")); + assert_that (cpe.update, is_equal_to_string ("beta")); + assert_that (cpe.edition, is_equal_to_string ("ANY")); + assert_that (cpe.language, is_equal_to_string ("ANY")); + assert_that (cpe.sw_edition, is_equal_to_string ("ANY")); + assert_that (cpe.target_sw, is_equal_to_string ("ANY")); + assert_that (cpe.target_hw, is_equal_to_string ("ANY")); + assert_that (cpe.other, is_equal_to_string ("ANY")); + cpe_struct_free (&cpe); + + fs_cpe = "This is a ~:SIGNAL:~ test."; + cpe_struct_init (&cpe); + fs_cpe_to_cpe_struct (fs_cpe, &cpe); + cpe_struct_free (&cpe); +} + +Ensure (cpeutils, cpe_struct_to_uri_cpe) +{ + cpe_struct_t cpe; + char * uri_cpe; + + cpe_struct_init (&cpe); + cpe.part = "a"; + cpe.vendor = "microsoft"; + cpe.product = "internet_explorer"; + cpe.version = "8\\.0\\.6001"; + cpe.update = "beta"; + cpe.edition = "ANY"; + + uri_cpe = cpe_struct_to_uri_cpe (&cpe); + assert_that (uri_cpe, is_equal_to_string ("cpe:/a:microsoft:internet_explorer:8.0.6001:beta")); + g_free (uri_cpe); +} + +Ensure (cpeutils, cpe_struct_to_fs_cpe) +{ + cpe_struct_t cpe; + char * fs_cpe; + + cpe_struct_init (&cpe); + cpe.part = "a"; + cpe.vendor = "microsoft"; + cpe.product = "internet_explorer"; + cpe.version = "8\\.0\\.6001"; + cpe.update = "beta"; + cpe.edition = "ANY"; + + fs_cpe = cpe_struct_to_fs_cpe (&cpe); + assert_that (fs_cpe, is_equal_to_string ("cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*")); + g_free (fs_cpe); +} + +Ensure (cpeutils, uri_cpe_to_fs_cpe) +{ + char * uri_cpe = "cpe:/a:microsoft:internet_explorer:8.0.6001:beta"; + char * fs_cpe = uri_cpe_to_fs_cpe(uri_cpe); + assert_that (fs_cpe, is_equal_to_string ("cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*")); + g_free (fs_cpe); + + uri_cpe = "cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~"; + fs_cpe = uri_cpe_to_fs_cpe(uri_cpe); + assert_that (fs_cpe, is_equal_to_string ("cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*")); + g_free (fs_cpe); + + uri_cpe = "This is a ~:SIGNAL:~ test."; + fs_cpe = uri_cpe_to_fs_cpe(uri_cpe); + g_free (fs_cpe); +} + +Ensure (cpeutils, fs_cpe_to_uri_cpe) +{ + char * fs_cpe = "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"; + char * uri_cpe = fs_cpe_to_uri_cpe(fs_cpe); + assert_that (uri_cpe, is_equal_to_string ("cpe:/a:microsoft:internet_explorer:8.0.6001:beta")); + g_free (uri_cpe); + + fs_cpe = "cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*"; + uri_cpe = fs_cpe_to_uri_cpe(fs_cpe); + assert_that (uri_cpe, is_equal_to_string ("cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~")); + g_free (uri_cpe); + + fs_cpe = "This is a ~:SIGNAL:~ test."; + uri_cpe = fs_cpe_to_uri_cpe(fs_cpe); + g_free (uri_cpe); +} + +/* Test suite. */ +int +main (int argc, char **argv) +{ + TestSuite *suite; + + suite = create_test_suite (); + + add_test_with_context (suite, cpeutils, uri_cpe_to_cpe_struct); + add_test_with_context (suite, cpeutils, fs_cpe_to_cpe_struct); + add_test_with_context (suite, cpeutils, cpe_struct_to_uri_cpe); + add_test_with_context (suite, cpeutils, uri_cpe_to_fs_cpe); + add_test_with_context (suite, cpeutils, fs_cpe_to_uri_cpe); + + if (argc > 1) + return run_single_test (suite, argv[1], create_text_reporter ()); + + return run_test_suite (suite, create_text_reporter ()); +} From 502cf44ebee841c6c08e822c914b794ea4e4588e Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Thu, 11 Jul 2024 10:08:57 +0200 Subject: [PATCH 2/7] Amended some formatting. --- util/cpeutils.c | 268 +++++++++++++++++++++++++++--------------------- 1 file changed, 149 insertions(+), 119 deletions(-) diff --git a/util/cpeutils.c b/util/cpeutils.c index fc66c9aa..3195f8a6 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -16,10 +16,10 @@ #include "cpeutils.h" #include +#include #include #include #include -#include #undef G_LOG_DOMAIN /** @@ -41,7 +41,7 @@ uri_cpe_to_fs_cpe (const char *uri_cpe) cpe_struct_init (&cpe); uri_cpe_to_cpe_struct (uri_cpe, &cpe); - return(cpe_struct_to_fs_cpe (&cpe)); + return (cpe_struct_to_fs_cpe (&cpe)); } /** @@ -58,7 +58,7 @@ fs_cpe_to_uri_cpe (const char *fs_cpe) cpe_struct_init (&cpe); fs_cpe_to_cpe_struct (fs_cpe, &cpe); - return(cpe_struct_to_uri_cpe (&cpe)); + return (cpe_struct_to_uri_cpe (&cpe)); } /** @@ -66,7 +66,7 @@ fs_cpe_to_uri_cpe (const char *fs_cpe) * * @param[in] uri_cpe A CPE v2.2-conformant URI. * - * @param[out] cpe Pointer to the filled CPE struct. + * @param[out] cpe Pointer to the filled CPE struct. */ void uri_cpe_to_cpe_struct (const char *uri_cpe, cpe_struct_t *cpe) @@ -89,9 +89,8 @@ uri_cpe_to_cpe_struct (const char *uri_cpe, cpe_struct_t *cpe) cpe->update = decode_uri_component (uri_component); g_free (uri_component); uri_component = get_uri_component (uri_cpe, 6); - if (strcmp (uri_component, "") == 0 || - strcmp (uri_component, "-") == 0 || - *uri_component != '~') + if (strcmp (uri_component, "") == 0 || strcmp (uri_component, "-") == 0 + || *uri_component != '~') cpe->edition = decode_uri_component (uri_component); else unpack_sixth_uri_component (uri_component, cpe); @@ -169,7 +168,7 @@ cpe_struct_to_uri_cpe (const cpe_struct_t *cpe) * * @param[in] fs_cpe A formatted string CPE. * - * @param[out] cpe Pointer to the filled CPE struct. + * @param[out] cpe Pointer to the filled CPE struct. */ void fs_cpe_to_cpe_struct (const char *fs_cpe, cpe_struct_t *cpe) @@ -303,7 +302,7 @@ cpe_struct_to_fs_cpe (const cpe_struct_t *cpe) * @return The indexth component of the URI CPE. */ static char * -get_uri_component(const char *uri_cpe, int index) +get_uri_component (const char *uri_cpe, int index) { char *component = NULL; char *c; @@ -317,7 +316,7 @@ get_uri_component(const char *uri_cpe, int index) /* find start of component */ for (int i = 0; *c != '\0' && i < index; c++) { - if (*c == ':') + if (*c == ':') i++; } @@ -331,15 +330,16 @@ get_uri_component(const char *uri_cpe, int index) component_end = component_start; else { - for (c = component_start; *c != '\0' && *c != ':'; c++); + for (c = component_start; *c != '\0' && *c != ':'; c++) + ; } component_end = c; if (component_start >= component_end || component_end == 0) - component = (char*) g_strdup (""); + component = (char *) g_strdup (""); else - str_cpy (&component, component_start, component_end-component_start); + str_cpy (&component, component_start, component_end - component_start); return component; } @@ -376,7 +376,8 @@ decode_uri_component (const char *component) /* set all characters to lowercase */ char *c = tmp_component; - for ( ; *c; c++) *c = tolower (*c); + for (; *c; c++) + *c = tolower (*c); index = 0; embedded = FALSE; @@ -385,7 +386,7 @@ decode_uri_component (const char *component) char l; while (index < strlen (tmp_component)) { - l = *(tmp_component+index); + l = *(tmp_component + index); if (l == '.' || l == '-' || l == '~') { @@ -402,20 +403,20 @@ decode_uri_component (const char *component) continue; } - get_code (code_a, tmp_component+index); + get_code (code_a, tmp_component + index); if (strcmp (code_a, "%01") == 0) { if (index >= 3) - get_code (code_b, tmp_component+index-3); + get_code (code_b, tmp_component + index - 3); else code_b[0] = '0'; if (strlen (tmp_component) >= index + 6) - get_code (code_c, tmp_component+index+3); + get_code (code_c, tmp_component + index + 3); else code_c[0] = '0'; - if ((index == 0 || index == strlen (tmp_component)-3) || - (!embedded && strcmp (code_b, "%01")) || - (embedded && strcmp (code_c, "%01"))) + if ((index == 0 || index == strlen (tmp_component) - 3) + || (!embedded && strcmp (code_b, "%01")) + || (embedded && strcmp (code_c, "%01"))) { g_string_append_printf (decoded_component, "%c", '?'); index = index + 3; @@ -430,7 +431,7 @@ decode_uri_component (const char *component) if (strcmp (code_a, "%02") == 0) { - if (index == 0 || index == strlen (tmp_component)-3) + if (index == 0 || index == strlen (tmp_component) - 3) { g_string_append_printf (decoded_component, "%c", '*'); index = index + 3; @@ -504,8 +505,8 @@ decode_uri_component (const char *component) { g_free (tmp_component); return (NULL); - } - index = index+3; + } + index = index + 3; embedded = TRUE; } @@ -524,44 +525,44 @@ decode_uri_component (const char *component) static void unpack_sixth_uri_component (const char *component, cpe_struct_t *cpe) { - const char *start = component+1; + const char *start = component + 1; const char *end; - char *edition, *sw_edition, *target_sw, *target_hw, *other; + char *edition, *sw_edition, *target_sw, *target_hw, *other; end = strchr (start, '~'); if (start >= end || end == NULL) edition = strdup (""); else - str_cpy (&edition, start, end-start); + str_cpy (&edition, start, end - start); start = end + 1; end = strchr (start, '~'); if (start >= end || end == NULL) sw_edition = strdup (""); else - str_cpy (&sw_edition, start, end-start); + str_cpy (&sw_edition, start, end - start); start = end + 1; end = strchr (start, '~'); if (start >= end || end == NULL) target_sw = strdup (""); else - str_cpy (&target_sw, start, end-start); + str_cpy (&target_sw, start, end - start); start = end + 1; end = strchr (start, '~'); if (start >= end || end == NULL) target_hw = strdup (""); else - str_cpy (&target_hw, start, end-start); + str_cpy (&target_hw, start, end - start); start = end + 1; end = strchr (start, '~'); if (start >= end || end == NULL) other = strdup (""); else - str_cpy (&other, start, end-start); + str_cpy (&other, start, end - start); cpe->edition = decode_uri_component (edition); g_free (edition); @@ -584,7 +585,7 @@ unpack_sixth_uri_component (const char *component, cpe_struct_t *cpe) * @return The indexth component of the formatted string CPE. */ static char * -get_fs_component(const char *fs_cpe, int index) +get_fs_component (const char *fs_cpe, int index) { char *component = NULL; char *c; @@ -594,7 +595,7 @@ get_fs_component(const char *fs_cpe, int index) return NULL; if (*fs_cpe == '\0') - return ((char*) g_strdup ("")); + return ((char *) g_strdup ("")); c = (char *) fs_cpe; @@ -607,7 +608,7 @@ get_fs_component(const char *fs_cpe, int index) { if (*c == ':' && c == fs_cpe) i++; - else if (c > fs_cpe && *c == ':' && *(c-1) != '\\') + else if (c > fs_cpe && *c == ':' && *(c - 1) != '\\') i++; } component_start = c; @@ -618,15 +619,16 @@ get_fs_component(const char *fs_cpe, int index) component_end = component_start; else { - for (c = component_start; *c != '\0' && *c != ':'; c++); + for (c = component_start; *c != '\0' && *c != ':'; c++) + ; } component_end = c; if (component_start >= component_end || component_end == NULL) - component = (char*) g_strdup (""); + component = (char *) g_strdup (""); else - str_cpy (&component, component_start, component_end-component_start); + str_cpy (&component, component_start, component_end - component_start); return component; } @@ -642,9 +644,9 @@ static char * unbind_fs_component (char *component) { if (strcmp (component, "*") == 0) - return ((char *) g_strdup("ANY")); + return ((char *) g_strdup ("ANY")); if (strcmp (component, "-") == 0) - return ((char *) g_strdup("NA")); + return ((char *) g_strdup ("NA")); return (add_quoting (component)); } @@ -672,12 +674,13 @@ add_quoting (const char *component) embedded = FALSE; /* set all characters to lowercase */ - for (c = tmp_component; *c; c++) *c = tolower (*c); + for (c = tmp_component; *c; c++) + *c = tolower (*c); c = tmp_component; while (*c != '\0') { - if (is_alpha_num(*c)) + if (is_alpha_num (*c)) { g_string_append_printf (quoted_component, "%c", *c); c++; @@ -697,7 +700,8 @@ add_quoting (const char *component) } if (*c == '*') { - if ((c == tmp_component) || (c == tmp_component+strlen (tmp_component -1))) + if ((c == tmp_component) + || (c == tmp_component + strlen (tmp_component - 1))) { g_string_append_printf (quoted_component, "%c", *c); c++; @@ -712,10 +716,10 @@ add_quoting (const char *component) } if (*c == '?') { - if ((c == tmp_component) || - (c == tmp_component+strlen (tmp_component -1)) || - (!embedded && (c > tmp_component) && (*(c-1) == '?')) || - (embedded && *(c+1) == '?')) + if ((c == tmp_component) + || (c == tmp_component + strlen (tmp_component - 1)) + || (!embedded && (c > tmp_component) && (*(c - 1) == '?')) + || (embedded && *(c + 1) == '?')) { g_string_append_printf (quoted_component, "%c", *c); c++; @@ -747,12 +751,12 @@ static char * bind_cpe_component_for_uri (const char *component) { if (!component) - return (g_strdup("")); + return (g_strdup ("")); if (strcmp (component, "") == 0) - return (g_strdup("")); - if (strcmp(component, "ANY") == 0) return (g_strdup ("")); - if (strcmp(component, "NA") == 0) + if (strcmp (component, "ANY") == 0) + return (g_strdup ("")); + if (strcmp (component, "NA") == 0) return (g_strdup ("-")); return (transform_for_uri (component)); } @@ -772,14 +776,15 @@ transform_for_uri (const char *component) char *c; if (!component) - return (g_strdup("")); + return (g_strdup ("")); if (strcmp (component, "") == 0) - return (g_strdup("")); + return (g_strdup ("")); - tmp_component = g_strdup(component); + tmp_component = g_strdup (component); /* set all characters to lowercase */ - for (c = tmp_component; *c; c++) *c = tolower (*c); + for (c = tmp_component; *c; c++) + *c = tolower (*c); result = g_string_new (""); c = tmp_component; @@ -797,7 +802,7 @@ transform_for_uri (const char *component) c++; if (*c != '\0') { - g_string_append_printf (result, "%s", pct_encode(*c)); + g_string_append_printf (result, "%s", pct_encode (*c)); c++; } continue; @@ -822,37 +827,68 @@ transform_for_uri (const char *component) static char * pct_encode (char c) { - if (c == '!') return ("%21"); - if (c == '"') return ("%22"); - if (c == '#') return ("%23"); - if (c == '$') return ("%24"); - if (c == '%') return ("%25"); - if (c == '&') return ("%26"); - if (c == '\'') return ("%27"); - if (c == '(') return ("%28"); - if (c == ')') return ("%29"); - if (c == '*') return ("%2a"); - if (c == '+') return ("%2b"); - if (c == ',') return ("%2c"); - if (c == '-') return ("-"); - if (c == '.') return ("."); - if (c == '/') return ("%2f"); - if (c == ':') return ("%3a"); - if (c == ';') return ("%3b"); - if (c == '<') return ("%3c"); - if (c == '=') return ("%3d"); - if (c == '>') return ("%3e"); - if (c == '?') return ("%3f"); - if (c == '@') return ("%40"); - if (c == '[') return ("%5b"); - if (c == '\\') return ("%5c"); - if (c == ']') return ("%5d"); - if (c == '^') return ("%5e"); - if (c == '`') return ("%60"); - if (c == '{') return ("%7b"); - if (c == '|') return ("%7c"); - if (c == '}') return ("%7d"); - if (c == '~') return ("%7e"); + if (c == '!') + return ("%21"); + if (c == '"') + return ("%22"); + if (c == '#') + return ("%23"); + if (c == '$') + return ("%24"); + if (c == '%') + return ("%25"); + if (c == '&') + return ("%26"); + if (c == '\'') + return ("%27"); + if (c == '(') + return ("%28"); + if (c == ')') + return ("%29"); + if (c == '*') + return ("%2a"); + if (c == '+') + return ("%2b"); + if (c == ',') + return ("%2c"); + if (c == '-') + return ("-"); + if (c == '.') + return ("."); + if (c == '/') + return ("%2f"); + if (c == ':') + return ("%3a"); + if (c == ';') + return ("%3b"); + if (c == '<') + return ("%3c"); + if (c == '=') + return ("%3d"); + if (c == '>') + return ("%3e"); + if (c == '?') + return ("%3f"); + if (c == '@') + return ("%40"); + if (c == '[') + return ("%5b"); + if (c == '\\') + return ("%5c"); + if (c == ']') + return ("%5d"); + if (c == '^') + return ("%5e"); + if (c == '`') + return ("%60"); + if (c == '{') + return ("%7b"); + if (c == '|') + return ("%7c"); + if (c == '}') + return ("%7d"); + if (c == '~') + return ("%7e"); return (""); } @@ -867,14 +903,14 @@ pct_encode (char c) static char * pack_sixth_uri_component (const cpe_struct_t *cpe) { - if ((cpe->sw_edition == NULL || strcmp (cpe->sw_edition, "") == 0) && - (cpe->target_sw == NULL || strcmp (cpe->target_sw, "") == 0) && - (cpe->target_hw == NULL || strcmp (cpe->target_hw, "") == 0) && - (cpe->other == NULL || strcmp (cpe->other, "") == 0)) + if ((cpe->sw_edition == NULL || strcmp (cpe->sw_edition, "") == 0) + && (cpe->target_sw == NULL || strcmp (cpe->target_sw, "") == 0) + && (cpe->target_hw == NULL || strcmp (cpe->target_hw, "") == 0) + && (cpe->other == NULL || strcmp (cpe->other, "") == 0)) { - if (strcmp(cpe->edition, "ANY") == 0) + if (strcmp (cpe->edition, "ANY") == 0) return (g_strdup ("")); - if (strcmp(cpe->edition, "NA") == 0) + if (strcmp (cpe->edition, "NA") == 0) return (g_strdup ("-")); return (g_strdup (cpe->edition)); } @@ -886,16 +922,12 @@ pack_sixth_uri_component (const cpe_struct_t *cpe) char *other = bind_cpe_component_for_uri (cpe->other); GString *component; component = g_string_new (""); - if (!((!sw_edition || strcmp (sw_edition, "") == 0) && - (!target_sw || strcmp (target_sw, "") == 0) && - (!target_hw || strcmp (target_hw, "") == 0) && - (!other || strcmp (other, "") == 0) )) - g_string_append_printf (component, "~%s~%s~%s~%s~%s", - edition, - sw_edition, - target_sw, - target_hw, - other); + if (!((!sw_edition || strcmp (sw_edition, "") == 0) + && (!target_sw || strcmp (target_sw, "") == 0) + && (!target_hw || strcmp (target_hw, "") == 0) + && (!other || strcmp (other, "") == 0))) + g_string_append_printf (component, "~%s~%s~%s~%s~%s", edition, sw_edition, + target_sw, target_hw, other); else if (edition) g_string_append_printf (component, "%s", edition); @@ -923,17 +955,16 @@ static char * bind_cpe_component_for_fs (const char *component) { if (!component) - return (g_strdup("*")); + return (g_strdup ("*")); if (strcmp (component, "") == 0) - return (g_strdup("*")); - if (strcmp(component, "ANY") == 0) return (g_strdup ("*")); - if (strcmp(component, "NA") == 0) + if (strcmp (component, "ANY") == 0) + return (g_strdup ("*")); + if (strcmp (component, "NA") == 0) return (g_strdup ("-")); return (process_quoted_chars (component)); } - /** * @brief Process the quoted characters of a CPE component for * a formatted string CPE. @@ -946,9 +977,9 @@ static char * process_quoted_chars (const char *component) { if (!component) - return (g_strdup("")); + return (g_strdup ("")); if (strcmp (component, "") == 0) - return (g_strdup("")); + return (g_strdup ("")); GString *fs_component; fs_component = g_string_new (""); @@ -964,10 +995,10 @@ process_quoted_chars (const char *component) } else { - next_c = *(c+1); + next_c = *(c + 1); if (next_c == '.' || next_c == '-' || next_c == '_') { - g_string_append_printf (fs_component, "%c", next_c); + g_string_append_printf (fs_component, "%c", next_c); c += 2; } else if (next_c) @@ -1036,7 +1067,6 @@ cpe_struct_free (cpe_struct_t *cpe) g_free (cpe->language); } - /** * @brief Cut of trailing ':' signs. * @@ -1049,13 +1079,13 @@ trim_pct (char *str) if (!str) return; - c = str+strlen(str)-1; + c = str + strlen (str) - 1; while (c >= str) { if (*c == ':') { *c = '\0'; - c--; + c--; } else break; @@ -1072,15 +1102,16 @@ static void get_code (char *code, const char *str) { code[0] = *str; - code[1] = *(str+1); - code[2] = *(str+2); + code[1] = *(str + 1); + code[2] = *(str + 2); code[3] = '\0'; } /** * @brief Copy size characters of a string to an newly allocated new string. * - * @param[in] src The string the first size characters are to be copied from. + * @param[in] src The string the first size characters are to be copied + * from. * @param[in] size The number of characters to copy. * * @param[out] dest The copy of the first size characters of src. @@ -1103,6 +1134,5 @@ str_cpy (char **dest, const char *src, int size) static gboolean is_alpha_num (char c) { - return (isalpha(c) || isdigit(c) || c == '_'); + return (isalpha (c) || isdigit (c) || c == '_'); } - From 029ced92070001fe4c8a08ccaab2a2afe8a53a21 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Thu, 11 Jul 2024 10:46:02 +0200 Subject: [PATCH 3/7] Amended some more formatting. --- util/cpeutils.h | 26 ++++++++++----------- util/cpeutils_tests.c | 53 +++++++++++++++++++++++++++---------------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/util/cpeutils.h b/util/cpeutils.h index dedca3fa..46708c97 100644 --- a/util/cpeutils.h +++ b/util/cpeutils.h @@ -21,17 +21,17 @@ */ typedef struct { -char *part; -char *vendor; -char *product; -char *version; -char *update; -char *edition; -char *sw_edition; -char *target_sw; -char *target_hw; -char *other; -char *language; + char *part; + char *vendor; + char *product; + char *version; + char *update; + char *edition; + char *sw_edition; + char *target_sw; + char *target_hw; + char *other; + char *language; } cpe_struct_t; char * @@ -53,7 +53,7 @@ char * cpe_struct_to_fs_cpe (const cpe_struct_t *); static char * -get_uri_component(const char *, int); +get_uri_component (const char *, int); static char * decode_uri_component (const char *); @@ -62,7 +62,7 @@ static void unpack_sixth_uri_component (const char *, cpe_struct_t *); static char * -get_fs_component(const char *, int); +get_fs_component (const char *, int); static char * unbind_fs_component (char *); diff --git a/util/cpeutils_tests.c b/util/cpeutils_tests.c index 3896a2ef..32cb12e0 100644 --- a/util/cpeutils_tests.c +++ b/util/cpeutils_tests.c @@ -22,7 +22,7 @@ AfterEach (cpeutils) Ensure (cpeutils, uri_cpe_to_cpe_struct) { cpe_struct_t cpe; - char * uri_cpe; + char *uri_cpe; uri_cpe = "cpe:/a:microsoft:internet_explorer:8.0.6001:beta"; cpe_struct_init (&cpe); @@ -73,7 +73,7 @@ Ensure (cpeutils, uri_cpe_to_cpe_struct) Ensure (cpeutils, fs_cpe_to_cpe_struct) { cpe_struct_t cpe; - char * fs_cpe; + char *fs_cpe; fs_cpe = "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"; cpe_struct_init (&cpe); @@ -100,7 +100,7 @@ Ensure (cpeutils, fs_cpe_to_cpe_struct) Ensure (cpeutils, cpe_struct_to_uri_cpe) { cpe_struct_t cpe; - char * uri_cpe; + char *uri_cpe; cpe_struct_init (&cpe); cpe.part = "a"; @@ -111,14 +111,15 @@ Ensure (cpeutils, cpe_struct_to_uri_cpe) cpe.edition = "ANY"; uri_cpe = cpe_struct_to_uri_cpe (&cpe); - assert_that (uri_cpe, is_equal_to_string ("cpe:/a:microsoft:internet_explorer:8.0.6001:beta")); + assert_that (uri_cpe, is_equal_to_string ( + "cpe:/a:microsoft:internet_explorer:8.0.6001:beta")); g_free (uri_cpe); } Ensure (cpeutils, cpe_struct_to_fs_cpe) { cpe_struct_t cpe; - char * fs_cpe; + char *fs_cpe; cpe_struct_init (&cpe); cpe.part = "a"; @@ -129,41 +130,55 @@ Ensure (cpeutils, cpe_struct_to_fs_cpe) cpe.edition = "ANY"; fs_cpe = cpe_struct_to_fs_cpe (&cpe); - assert_that (fs_cpe, is_equal_to_string ("cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*")); + assert_that ( + fs_cpe, + is_equal_to_string ( + "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*")); g_free (fs_cpe); } Ensure (cpeutils, uri_cpe_to_fs_cpe) { - char * uri_cpe = "cpe:/a:microsoft:internet_explorer:8.0.6001:beta"; - char * fs_cpe = uri_cpe_to_fs_cpe(uri_cpe); - assert_that (fs_cpe, is_equal_to_string ("cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*")); + char *uri_cpe = "cpe:/a:microsoft:internet_explorer:8.0.6001:beta"; + char *fs_cpe = uri_cpe_to_fs_cpe (uri_cpe); + assert_that ( + fs_cpe, + is_equal_to_string ( + "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*")); g_free (fs_cpe); uri_cpe = "cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~"; - fs_cpe = uri_cpe_to_fs_cpe(uri_cpe); - assert_that (fs_cpe, is_equal_to_string ("cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*")); + fs_cpe = uri_cpe_to_fs_cpe (uri_cpe); + assert_that (fs_cpe, + is_equal_to_string ("cpe:2.3:a:hp:insight_diagnostics:7.4.0." + "1570:-:*:*:online:win2003:x64:*")); g_free (fs_cpe); uri_cpe = "This is a ~:SIGNAL:~ test."; - fs_cpe = uri_cpe_to_fs_cpe(uri_cpe); + fs_cpe = uri_cpe_to_fs_cpe (uri_cpe); g_free (fs_cpe); } Ensure (cpeutils, fs_cpe_to_uri_cpe) { - char * fs_cpe = "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"; - char * uri_cpe = fs_cpe_to_uri_cpe(fs_cpe); - assert_that (uri_cpe, is_equal_to_string ("cpe:/a:microsoft:internet_explorer:8.0.6001:beta")); + char *fs_cpe = + "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"; + char *uri_cpe = fs_cpe_to_uri_cpe (fs_cpe); + assert_that (uri_cpe, is_equal_to_string ( + "cpe:/a:microsoft:internet_explorer:8.0.6001:beta")); g_free (uri_cpe); - fs_cpe = "cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*"; - uri_cpe = fs_cpe_to_uri_cpe(fs_cpe); - assert_that (uri_cpe, is_equal_to_string ("cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~")); + fs_cpe = + "cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*"; + uri_cpe = fs_cpe_to_uri_cpe (fs_cpe); + assert_that ( + uri_cpe, + is_equal_to_string ( + "cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~")); g_free (uri_cpe); fs_cpe = "This is a ~:SIGNAL:~ test."; - uri_cpe = fs_cpe_to_uri_cpe(fs_cpe); + uri_cpe = fs_cpe_to_uri_cpe (fs_cpe); g_free (uri_cpe); } From 9ba4e4cd4e37fab535a8d46545c6eb57c5c0eda1 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Fri, 19 Jul 2024 09:39:49 +0200 Subject: [PATCH 4/7] Added a function to check if one CPE matches the other CPE. Implemented some amendments and added a function, that takes two CPE structs and checks if one of the CPEs matches the other one. --- util/cpeutils.c | 425 ++++++++++++++++++++++++++++-------------- util/cpeutils.h | 35 +++- util/cpeutils_tests.c | 29 +++ 3 files changed, 341 insertions(+), 148 deletions(-) diff --git a/util/cpeutils.c b/util/cpeutils.c index 3195f8a6..528a833c 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -38,10 +38,13 @@ char * uri_cpe_to_fs_cpe (const char *uri_cpe) { cpe_struct_t cpe; + char *fs_cpe; cpe_struct_init (&cpe); uri_cpe_to_cpe_struct (uri_cpe, &cpe); - return (cpe_struct_to_fs_cpe (&cpe)); + fs_cpe = cpe_struct_to_fs_cpe (&cpe); + cpe_struct_free (&cpe); + return (fs_cpe); } /** @@ -55,10 +58,13 @@ char * fs_cpe_to_uri_cpe (const char *fs_cpe) { cpe_struct_t cpe; + char *uri_cpe; cpe_struct_init (&cpe); fs_cpe_to_cpe_struct (fs_cpe, &cpe); - return (cpe_struct_to_uri_cpe (&cpe)); + uri_cpe = cpe_struct_to_uri_cpe (&cpe); + cpe_struct_free (&cpe); + return (uri_cpe); } /** @@ -355,6 +361,7 @@ static char * decode_uri_component (const char *component) { GString *decoded_component; + char *escapes = "!\"#$%&'()*+,/:;<=>?@[\\]^`{|}~"; char *tmp_component; char code_a[4], code_b[4], code_c[4]; long unsigned int index; @@ -384,6 +391,7 @@ decode_uri_component (const char *component) decoded_component = g_string_new (""); char l; + char *unescaped; while (index < strlen (tmp_component)) { l = *(tmp_component + index); @@ -404,6 +412,7 @@ decode_uri_component (const char *component) } get_code (code_a, tmp_component + index); + if (strcmp (code_a, "%01") == 0) { if (index >= 3) @@ -443,64 +452,18 @@ decode_uri_component (const char *component) return (NULL); } } - if (strcmp (code_a, "%21") == 0) - g_string_append_printf (decoded_component, "%s", "\\!"); - else if (strcmp (code_a, "%22") == 0) - g_string_append_printf (decoded_component, "%s", "\\\""); - else if (strcmp (code_a, "%23") == 0) - g_string_append_printf (decoded_component, "%s", "\\#"); - else if (strcmp (code_a, "%24") == 0) - g_string_append_printf (decoded_component, "%s", "\\$"); - else if (strcmp (code_a, "%25") == 0) - g_string_append_printf (decoded_component, "%s", "\\%"); - else if (strcmp (code_a, "%26") == 0) - g_string_append_printf (decoded_component, "%s", "\\&"); - else if (strcmp (code_a, "%27") == 0) - g_string_append_printf (decoded_component, "%s", "\\'"); - else if (strcmp (code_a, "%28") == 0) - g_string_append_printf (decoded_component, "%s", "\\("); - else if (strcmp (code_a, "%29") == 0) - g_string_append_printf (decoded_component, "%s", "\\)"); - else if (strcmp (code_a, "%2a") == 0) - g_string_append_printf (decoded_component, "%s", "\\*"); - else if (strcmp (code_a, "%2b") == 0) - g_string_append_printf (decoded_component, "%s", "\\+"); - else if (strcmp (code_a, "%2c") == 0) - g_string_append_printf (decoded_component, "%s", "\\,"); - else if (strcmp (code_a, "%2f") == 0) - g_string_append_printf (decoded_component, "%s", "\\/"); - else if (strcmp (code_a, "%3a") == 0) - g_string_append_printf (decoded_component, "%s", "\\:"); - else if (strcmp (code_a, "%3b") == 0) - g_string_append_printf (decoded_component, "%s", "\\;"); - else if (strcmp (code_a, "%3c") == 0) - g_string_append_printf (decoded_component, "%s", "\\<"); - else if (strcmp (code_a, "%3d") == 0) - g_string_append_printf (decoded_component, "%s", "\\="); - else if (strcmp (code_a, "%3e") == 0) - g_string_append_printf (decoded_component, "%s", "\\>"); - else if (strcmp (code_a, "%3f") == 0) - g_string_append_printf (decoded_component, "%s", "\\?"); - else if (strcmp (code_a, "%40") == 0) - g_string_append_printf (decoded_component, "%s", "\\@"); - else if (strcmp (code_a, "%5b") == 0) - g_string_append_printf (decoded_component, "%s", "\\["); - else if (strcmp (code_a, "%5c") == 0) - g_string_append_printf (decoded_component, "%s", "\\\\"); - else if (strcmp (code_a, "%5d") == 0) - g_string_append_printf (decoded_component, "%s", "\\]"); - else if (strcmp (code_a, "%5e") == 0) - g_string_append_printf (decoded_component, "%s", "\\^"); - else if (strcmp (code_a, "%60") == 0) - g_string_append_printf (decoded_component, "%s", "\\`"); - else if (strcmp (code_a, "%7b") == 0) - g_string_append_printf (decoded_component, "%s", "\\{"); - else if (strcmp (code_a, "%7c") == 0) - g_string_append_printf (decoded_component, "%s", "\\|"); - else if (strcmp (code_a, "%7d") == 0) - g_string_append_printf (decoded_component, "%s", "\\}"); - else if (strcmp (code_a, "%7e") == 0) - g_string_append_printf (decoded_component, "%s", "\\~"); + + unescaped = g_uri_unescape_string (code_a, NULL); + if (unescaped && strchr (escapes, *unescaped)) + { + g_string_append_printf (decoded_component, "\\%s", unescaped); + g_free (unescaped); + } + else if (unescaped) + { + g_string_append_printf (decoded_component, "%s", unescaped); + g_free (unescaped); + } else { g_free (tmp_component); @@ -680,7 +643,7 @@ add_quoting (const char *component) c = tmp_component; while (*c != '\0') { - if (is_alpha_num (*c)) + if (g_ascii_isalnum (*c) || *c == '_') { g_string_append_printf (quoted_component, "%c", *c); c++; @@ -791,7 +754,7 @@ transform_for_uri (const char *component) while (*c) { - if (is_alpha_num (*c) && *c != '-') + if ((g_ascii_isalnum (*c) || *c == '_') && *c != '-') { g_string_append_printf (result, "%c", *c); c++; @@ -802,7 +765,13 @@ transform_for_uri (const char *component) c++; if (*c != '\0') { - g_string_append_printf (result, "%s", pct_encode (*c)); + char to_escape[2]; + char * escaped; + to_escape[0] = *c; + to_escape[1] = '\0'; + escaped = g_uri_escape_string (to_escape, NULL, FALSE); + g_string_append_printf (result, "%s", escaped); + g_free (escaped); c++; } continue; @@ -817,81 +786,6 @@ transform_for_uri (const char *component) return (g_string_free (result, FALSE)); } -/** - * @brief Percent encode special characters. - * - * @param[in] c The character to encode. - * - * @return The percent code. - */ -static char * -pct_encode (char c) -{ - if (c == '!') - return ("%21"); - if (c == '"') - return ("%22"); - if (c == '#') - return ("%23"); - if (c == '$') - return ("%24"); - if (c == '%') - return ("%25"); - if (c == '&') - return ("%26"); - if (c == '\'') - return ("%27"); - if (c == '(') - return ("%28"); - if (c == ')') - return ("%29"); - if (c == '*') - return ("%2a"); - if (c == '+') - return ("%2b"); - if (c == ',') - return ("%2c"); - if (c == '-') - return ("-"); - if (c == '.') - return ("."); - if (c == '/') - return ("%2f"); - if (c == ':') - return ("%3a"); - if (c == ';') - return ("%3b"); - if (c == '<') - return ("%3c"); - if (c == '=') - return ("%3d"); - if (c == '>') - return ("%3e"); - if (c == '?') - return ("%3f"); - if (c == '@') - return ("%40"); - if (c == '[') - return ("%5b"); - if (c == '\\') - return ("%5c"); - if (c == ']') - return ("%5d"); - if (c == '^') - return ("%5e"); - if (c == '`') - return ("%60"); - if (c == '{') - return ("%7b"); - if (c == '|') - return ("%7c"); - if (c == '}') - return ("%7d"); - if (c == '~') - return ("%7e"); - return (""); -} - /** * @brief Pack the sixth component of a URI CPE. * @@ -1111,7 +1005,7 @@ get_code (char *code, const char *str) * @brief Copy size characters of a string to an newly allocated new string. * * @param[in] src The string the first size characters are to be copied - * from. + * from. * @param[in] size The number of characters to copy. * * @param[out] dest The copy of the first size characters of src. @@ -1125,14 +1019,257 @@ str_cpy (char **dest, const char *src, int size) } /** - * @brief Return if a character is alpha or numeric or '_'. + * @brief Returns if source is a match for target. That means + * that source is a superset of target. * - * @param[in] c The character to be checked. + * @param[in] source The cpe_struct that represents a set of CPEs. + * target The cpe_struct that represents a single CPE or + * or a set of CPEs that is checked if it is a + * subset of source meaning that it is matched by + * source. * - * @return The boolean result. + * @return Returns if source is a match for target. */ +gboolean +cpe_struct_match (cpe_struct_t source, cpe_struct_t target) +{ + enum set_relation relation; + + relation = compare_component (source.part, target.part); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.vendor, target.vendor); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.product, target.product); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.version, target.version); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.update, target.update); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.edition, target.edition); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.sw_edition, target.sw_edition); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.target_sw, target.target_sw); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.target_hw, target.target_hw); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.other, target.other); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + relation = compare_component (source.language, target.language); + if (relation != SUPERSET && relation != EQUAL) + return (FALSE); + + return (TRUE); +} + +static enum set_relation +compare_component (const char *source, const char *target) +{ + enum set_relation result; + char *source_cpy, *target_cpy; + char *c; + + if (source) + source_cpy = g_strdup(source); + else + source_cpy = g_strdup ("ANY"); + if (target) + target_cpy = g_strdup(target); + else + target_cpy = g_strdup ("ANY"); + + if (is_string (source_cpy)) + { + printf ("\nPROTO: >%s<\n", source_cpy); + /* set all characters to lowercase */ + for (c = source_cpy; *c; c++) + *c = tolower (*c); + } + if (is_string (target_cpy)) + { + /* set all characters to lowercase */ + for (c = target_cpy; *c; c++) + *c = tolower (*c); + } + if (is_string (target_cpy) && has_wildcards (target_cpy)) + { + g_free (source_cpy); + g_free (target_cpy); + return (UNDEFINED); + } + if (strcmp (source_cpy, target_cpy) == 0) + { + g_free (source_cpy); + g_free (target_cpy); + return (EQUAL); + } + if (strcmp (source_cpy, "ANY") == 0) + { + g_free (source_cpy); + g_free (target_cpy); + return (SUPERSET); + } + printf ("\n PROTO: %s - %s \n", source_cpy, target_cpy); + if (strcmp (target_cpy, "ANY") == 0) + { + g_free (source_cpy); + g_free (target_cpy); + return (SUBSET); + } + if (strcmp (target_cpy, "NA") == 0 || strcmp (source_cpy, "NA") == 0) + { + g_free (source_cpy); + g_free (target_cpy); + return (DISJOINT); + } + + result = compare_strings (source_cpy, target_cpy); + g_free (source_cpy); + g_free (target_cpy); + return (result); +} + +static enum set_relation +compare_strings (const char *source, const char *target) +{ + int start = 0; + int end = strlen (source); + int begins = 0; + int ends = 0; + + char *sub_source; + + if (*source == '*') + { + start = 1; + begins = -1; + } + else + { + while (start < (int) strlen (source) && *(source+start) == '?') + { + start++; + begins++; + } + } + if (*(source + end - 1) == '*' && is_even_wildcards (source, end - 1)) + { + end--; + ends = -1; + } + else + { + while (end > 0 && *(source + end - 1) == '?' && is_even_wildcards (source, end - 1)) + { + end--; + ends++; + } + } + + str_cpy (&sub_source, source+start, end - start); + int index = -1; + int escapes = 0; + int leftover = strlen (target); + + while (leftover > 0) + { + index = index_of (target, sub_source, index+1); + if (index == -1) + break; + escapes = count_escapes (target, 0, index); + if (index > 0 && begins != -1 && begins < (index - escapes)) + break; + escapes = count_escapes (target, index + 1, strlen (target)); + leftover = strlen (target) - index - escapes - strlen (sub_source); + if (leftover > 0 && (ends != -1 && leftover > ends)) + continue; + g_free (sub_source); + return SUPERSET; + } + g_free (sub_source); + return DISJOINT; +} + +static int +count_escapes (const char *str, int start, int end) +{ + int result = 0; + gboolean active = FALSE; + + for (int i = 0; i < end && *(str+i) != '\0'; i++) + { + active = (!active && *(str+i) == '\\'); + if (active && i >= start) + result++; + } + return (result); +} + static gboolean -is_alpha_num (char c) +is_even_wildcards (const char *str, int index) { - return (isalpha (c) || isdigit (c) || c == '_'); + int result = 0; + + while (index > 0 && *(str + index - 1) == '\\') + { + index--; + result++; + } + return ((result % 2) == 0); +} + +static gboolean +has_wildcards (const char *str) +{ + char *c = (char *) str; + gboolean active = FALSE; + + while (*c != '\0') + { + if (!active && (*c == '?' || *c == '*')) + return TRUE; + + if (!active && *c == '\\') + active = TRUE; + else + active = FALSE; + + c++; + } + return FALSE; +} + +static int +index_of (const char *str, const char *sub_str, int offset) +{ + char *start; + char *begin_substr; + + if (offset > (int) strlen (str)) + return (-1); + + start = (char *) str + offset; + begin_substr = strstr (start, sub_str); + if (begin_substr == NULL) + return (-1); + return (begin_substr - str); +} + +static gboolean +is_string (const char *str) +{ + if (!str) + return FALSE; + + return (strcmp (str, "ANY") && strcmp (str, "NA")); } diff --git a/util/cpeutils.h b/util/cpeutils.h index 46708c97..da7e5137 100644 --- a/util/cpeutils.h +++ b/util/cpeutils.h @@ -76,9 +76,6 @@ bind_cpe_component_for_uri (const char *); static char * transform_for_uri (const char *); -static char * -pct_encode (char); - static char * pack_sixth_uri_component (const cpe_struct_t *); @@ -103,6 +100,36 @@ get_code (char *, const char *); static void str_cpy (char **, const char *, int); +enum set_relation + { + DISJOINT, + EQUAL, + SUBSET, + SUPERSET, + UNDEFINED + }; + +gboolean +cpe_struct_match (cpe_struct_t source, cpe_struct_t target); + +static enum set_relation +compare_component (const char *, const char *); + +static enum set_relation +compare_strings (const char *, const char *); + +static int +count_escapes (const char *, int, int); + +static gboolean +is_even_wildcards (const char *, int); + +static gboolean +has_wildcards (const char *); + +static int +index_of (const char *, const char *, int); + static gboolean -is_alpha_num (char); +is_string (const char *); #endif diff --git a/util/cpeutils_tests.c b/util/cpeutils_tests.c index 32cb12e0..b289fef4 100644 --- a/util/cpeutils_tests.c +++ b/util/cpeutils_tests.c @@ -182,6 +182,33 @@ Ensure (cpeutils, fs_cpe_to_uri_cpe) g_free (uri_cpe); } +Ensure (cpeutils, cpe_struct_match) +{ + cpe_struct_t cpe1, cpe2; + char *fs_cpe1, *fs_cpe2; + + fs_cpe1 = "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"; + cpe_struct_init (&cpe1); + fs_cpe_to_cpe_struct (fs_cpe1, &cpe1); + assert_that (cpe_struct_match (cpe1, cpe1), is_equal_to (TRUE)); + + fs_cpe2 = "cpe:2.3:a:microsoft:internet_explorer:*:beta:*:*:*:*:*:*"; + cpe_struct_init (&cpe2); + fs_cpe_to_cpe_struct (fs_cpe2, &cpe2); + assert_that (cpe_struct_match (cpe2, cpe1), is_equal_to (TRUE)); + + assert_that (cpe_struct_match (cpe1, cpe2), is_equal_to (FALSE)); + + fs_cpe2 = "cpe:2.3:a:microsoft:internet_explorer:*:-:*:*:*:*:*:*"; + cpe_struct_free (&cpe2); + cpe_struct_init (&cpe2); + fs_cpe_to_cpe_struct (fs_cpe2, &cpe2); + assert_that (cpe_struct_match (cpe2, cpe1), is_equal_to (FALSE)); + + cpe_struct_free (&cpe1); + cpe_struct_free (&cpe2); +} + /* Test suite. */ int main (int argc, char **argv) @@ -193,8 +220,10 @@ main (int argc, char **argv) add_test_with_context (suite, cpeutils, uri_cpe_to_cpe_struct); add_test_with_context (suite, cpeutils, fs_cpe_to_cpe_struct); add_test_with_context (suite, cpeutils, cpe_struct_to_uri_cpe); + add_test_with_context (suite, cpeutils, cpe_struct_to_fs_cpe); add_test_with_context (suite, cpeutils, uri_cpe_to_fs_cpe); add_test_with_context (suite, cpeutils, fs_cpe_to_uri_cpe); + add_test_with_context (suite, cpeutils, cpe_struct_match); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); From 267b7dc29e27589da04e843e87cc6e26def6b928 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Fri, 19 Jul 2024 09:58:40 +0200 Subject: [PATCH 5/7] Amended some formatting. --- util/cpeutils.c | 23 ++++++++++++----------- util/cpeutils.h | 14 +++++++------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/util/cpeutils.c b/util/cpeutils.c index 528a833c..aea6a2ba 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -766,7 +766,7 @@ transform_for_uri (const char *component) if (*c != '\0') { char to_escape[2]; - char * escaped; + char *escaped; to_escape[0] = *c; to_escape[1] = '\0'; escaped = g_uri_escape_string (to_escape, NULL, FALSE); @@ -1080,11 +1080,11 @@ compare_component (const char *source, const char *target) char *c; if (source) - source_cpy = g_strdup(source); + source_cpy = g_strdup (source); else source_cpy = g_strdup ("ANY"); if (target) - target_cpy = g_strdup(target); + target_cpy = g_strdup (target); else target_cpy = g_strdup ("ANY"); @@ -1156,7 +1156,7 @@ compare_strings (const char *source, const char *target) } else { - while (start < (int) strlen (source) && *(source+start) == '?') + while (start < (int) strlen (source) && *(source + start) == '?') { start++; begins++; @@ -1169,21 +1169,22 @@ compare_strings (const char *source, const char *target) } else { - while (end > 0 && *(source + end - 1) == '?' && is_even_wildcards (source, end - 1)) + while (end > 0 && *(source + end - 1) == '?' + && is_even_wildcards (source, end - 1)) { end--; ends++; } } - str_cpy (&sub_source, source+start, end - start); + str_cpy (&sub_source, source + start, end - start); int index = -1; int escapes = 0; int leftover = strlen (target); while (leftover > 0) { - index = index_of (target, sub_source, index+1); + index = index_of (target, sub_source, index + 1); if (index == -1) break; escapes = count_escapes (target, 0, index); @@ -1206,9 +1207,9 @@ count_escapes (const char *str, int start, int end) int result = 0; gboolean active = FALSE; - for (int i = 0; i < end && *(str+i) != '\0'; i++) + for (int i = 0; i < end && *(str + i) != '\0'; i++) { - active = (!active && *(str+i) == '\\'); + active = (!active && *(str + i) == '\\'); if (active && i >= start) result++; } @@ -1220,7 +1221,7 @@ is_even_wildcards (const char *str, int index) { int result = 0; - while (index > 0 && *(str + index - 1) == '\\') + while (index > 0 && *(str + index - 1) == '\\') { index--; result++; @@ -1259,7 +1260,7 @@ index_of (const char *str, const char *sub_str, int offset) return (-1); start = (char *) str + offset; - begin_substr = strstr (start, sub_str); + begin_substr = strstr (start, sub_str); if (begin_substr == NULL) return (-1); return (begin_substr - str); diff --git a/util/cpeutils.h b/util/cpeutils.h index da7e5137..2aabcb43 100644 --- a/util/cpeutils.h +++ b/util/cpeutils.h @@ -101,13 +101,13 @@ static void str_cpy (char **, const char *, int); enum set_relation - { - DISJOINT, - EQUAL, - SUBSET, - SUPERSET, - UNDEFINED - }; +{ + DISJOINT, + EQUAL, + SUBSET, + SUPERSET, + UNDEFINED +}; gboolean cpe_struct_match (cpe_struct_t source, cpe_struct_t target); From 2645c341b3c40782b098a04bbc13f9c51babb286 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Tue, 23 Jul 2024 13:36:50 +0200 Subject: [PATCH 6/7] Implemented some amendments. --- util/cpeutils.c | 141 +++++++++++++++++++++++++++++++++++------- util/cpeutils_tests.c | 35 +++++++++++ 2 files changed, 153 insertions(+), 23 deletions(-) diff --git a/util/cpeutils.c b/util/cpeutils.c index aea6a2ba..97a41fd4 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -433,6 +433,7 @@ decode_uri_component (const char *component) } else { + g_string_free (decoded_component, TRUE); g_free (tmp_component); return (NULL); } @@ -448,6 +449,7 @@ decode_uri_component (const char *component) } else { + g_string_free (decoded_component, TRUE); g_free (tmp_component); return (NULL); } @@ -466,6 +468,7 @@ decode_uri_component (const char *component) } else { + g_string_free (decoded_component, TRUE); g_free (tmp_component); return (NULL); } @@ -499,33 +502,53 @@ unpack_sixth_uri_component (const char *component, cpe_struct_t *cpe) else str_cpy (&edition, start, end - start); - start = end + 1; - end = strchr (start, '~'); - if (start >= end || end == NULL) - sw_edition = strdup (""); + if (end != NULL) + { + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + sw_edition = strdup (""); + else + str_cpy (&sw_edition, start, end - start); + } else - str_cpy (&sw_edition, start, end - start); + sw_edition = strdup (""); - start = end + 1; - end = strchr (start, '~'); - if (start >= end || end == NULL) - target_sw = strdup (""); + if (end != NULL) + { + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + target_sw = strdup (""); + else + str_cpy (&target_sw, start, end - start); + } else - str_cpy (&target_sw, start, end - start); + target_sw = strdup (""); - start = end + 1; - end = strchr (start, '~'); - if (start >= end || end == NULL) - target_hw = strdup (""); + if (end != NULL) + { + start = end + 1; + end = strchr (start, '~'); + if (start >= end || end == NULL) + target_hw = strdup (""); + else + str_cpy (&target_hw, start, end - start); + } else - str_cpy (&target_hw, start, end - start); + target_hw = strdup (""); - start = end + 1; - end = strchr (start, '~'); - if (start >= end || end == NULL) - other = strdup (""); + if (end != NULL) + { + start = end + 1; + end = component + strlen (component); + if (start >= end) + other = strdup (""); + else + str_cpy (&other, start, end - start); + } else - str_cpy (&other, start, end - start); + other = strdup (""); cpe->edition = decode_uri_component (edition); g_free (edition); @@ -1023,7 +1046,7 @@ str_cpy (char **dest, const char *src, int size) * that source is a superset of target. * * @param[in] source The cpe_struct that represents a set of CPEs. - * target The cpe_struct that represents a single CPE or + * @param[in] target The cpe_struct that represents a single CPE or * or a set of CPEs that is checked if it is a * subset of source meaning that it is matched by * source. @@ -1072,6 +1095,17 @@ cpe_struct_match (cpe_struct_t source, cpe_struct_t target) return (TRUE); } +/** + * @brief Returns if the component "source" is a match for the component + * "target". That means that source is a superset of target. + * + * @param[in] source The component of a cpe_struct. + * @param[in] target The component of a cpe_struct that is checked if it + * is a subset of source meaning that it is matched by + * source. + * + * @return Returns if source is a match for target. + */ static enum set_relation compare_component (const char *source, const char *target) { @@ -1090,7 +1124,6 @@ compare_component (const char *source, const char *target) if (is_string (source_cpy)) { - printf ("\nPROTO: >%s<\n", source_cpy); /* set all characters to lowercase */ for (c = source_cpy; *c; c++) *c = tolower (*c); @@ -1139,6 +1172,18 @@ compare_component (const char *source, const char *target) return (result); } +/** + * @brief Returns if the string of a component "source" is a match for the + * the string of a component "target". That means that source + * represents a superset of target. + * + * @param[in] source The string of a component of a cpe_struct. + * @param[in] target The string of a component of a cpe_struct that is + * checked if it represents a subset of source meaning + * that it is matched by source. + * + * @return Returns if source is a match for target. + */ static enum set_relation compare_strings (const char *source, const char *target) { @@ -1201,6 +1246,19 @@ compare_strings (const char *source, const char *target) return DISJOINT; } +/** + * @brief Counts the number of unescaped escape signs ("\") in a specified + * part of a string. + * + * @param[in] str The string to be examined. + * @param[in] start The start position in the string where the examination + * begins. + * @param[in] end The end position in the string where the examination + * ends. + * + * @return Returns the number of unescaped escape signs in the specified + * part of the string. + */ static int count_escapes (const char *str, int start, int end) { @@ -1216,6 +1274,16 @@ count_escapes (const char *str, int start, int end) return (result); } +/** + * @brief Returns true if an even number of escape (backslash) characters + * precede the character at the index "index" in string "str". + * + * @param[in] str The string to be examined. + * @param[in] index The index where the examination starts. + * + * @return Returns if an even number of escape characters precede the + * character at index "index". + */ static gboolean is_even_wildcards (const char *str, int index) { @@ -1229,6 +1297,13 @@ is_even_wildcards (const char *str, int index) return ((result % 2) == 0); } +/** + * @brief Returns if a given string contains wildcards ("*" or "?"). + * + * @param[in] str The string to be examined. + * + * @return Returns TRUE if the string contains wildcards. FALSE otherwise. + */ static gboolean has_wildcards (const char *str) { @@ -1250,6 +1325,17 @@ has_wildcards (const char *str) return FALSE; } +/** + * @brief Searches the string "str" for the first occurrence of the string + * "sub_str", starting at the offset "offset" in "str". + * + * @param[in] str The string to be examined. + * @param[in] sub_str The string to be searched for in "str". + * @param[in] offset The offset where to start the search in "str". + * + * @return Returns the index where the string "sub_str" starts in "str", if + * the string "sub_str" was found, -1 otherwise. + */ static int index_of (const char *str, const char *sub_str, int offset) { @@ -1266,11 +1352,20 @@ index_of (const char *str, const char *sub_str, int offset) return (begin_substr - str); } +/** + * @brief Returns if a string is an ordinary string and does not represent + * one of the logical values "ANY" or "NA". + * + * @param[in] str The string to be examined. + * + * @return Returns TRUE if the string "str" does not represent one of the + * logical values "ANY" or "NA". Returns FALSE otherwise. + */ static gboolean is_string (const char *str) { if (!str) - return FALSE; + return TRUE; return (strcmp (str, "ANY") && strcmp (str, "NA")); } diff --git a/util/cpeutils_tests.c b/util/cpeutils_tests.c index b289fef4..7374ce6f 100644 --- a/util/cpeutils_tests.c +++ b/util/cpeutils_tests.c @@ -64,6 +64,41 @@ Ensure (cpeutils, uri_cpe_to_cpe_struct) assert_that (cpe.language, is_equal_to_string ("ANY")); cpe_struct_free (&cpe); + uri_cpe = + "cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~other"; + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + assert_that (cpe.part, is_equal_to_string ("a")); + assert_that (cpe.vendor, is_equal_to_string ("hp")); + assert_that (cpe.product, is_equal_to_string ("insight_diagnostics")); + assert_that (cpe.version, is_equal_to_string ("7\\.4\\.0\\.1570")); + assert_that (cpe.update, is_equal_to_string ("ANY")); + assert_that (cpe.edition, is_equal_to_string ("ANY")); + assert_that (cpe.sw_edition, is_equal_to_string ("online")); + assert_that (cpe.target_sw, is_equal_to_string ("win2003")); + assert_that (cpe.target_hw, is_equal_to_string ("x64")); + assert_that (cpe.other, is_equal_to_string ("other")); + assert_that (cpe.language, is_equal_to_string ("ANY")); + cpe_struct_free (&cpe); + + uri_cpe = + "cpe:/" + "a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~other:english"; + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + assert_that (cpe.part, is_equal_to_string ("a")); + assert_that (cpe.vendor, is_equal_to_string ("hp")); + assert_that (cpe.product, is_equal_to_string ("insight_diagnostics")); + assert_that (cpe.version, is_equal_to_string ("7\\.4\\.0\\.1570")); + assert_that (cpe.update, is_equal_to_string ("ANY")); + assert_that (cpe.edition, is_equal_to_string ("ANY")); + assert_that (cpe.sw_edition, is_equal_to_string ("online")); + assert_that (cpe.target_sw, is_equal_to_string ("win2003")); + assert_that (cpe.target_hw, is_equal_to_string ("x64")); + assert_that (cpe.other, is_equal_to_string ("other")); + assert_that (cpe.language, is_equal_to_string ("english")); + cpe_struct_free (&cpe); + uri_cpe = "This is a ~:SIGNAL:~ test."; cpe_struct_init (&cpe); uri_cpe_to_cpe_struct (uri_cpe, &cpe); From ec8f48ab6c056e154b51c5732ad7909f1bc726fe Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Tue, 23 Jul 2024 13:43:16 +0200 Subject: [PATCH 7/7] Removed a debug message. --- util/cpeutils.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util/cpeutils.c b/util/cpeutils.c index 97a41fd4..3cc988a1 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -1152,7 +1152,6 @@ compare_component (const char *source, const char *target) g_free (target_cpy); return (SUPERSET); } - printf ("\n PROTO: %s - %s \n", source_cpy, target_cpy); if (strcmp (target_cpy, "ANY") == 0) { g_free (source_cpy);