From 28f044eb51dd9a5875788b90cb67aef05fdb67a5 Mon Sep 17 00:00:00 2001 From: Matt Mundell Date: Mon, 25 Nov 2024 17:13:04 +0200 Subject: [PATCH 1/3] Add: group common json utilities --- util/CMakeLists.txt | 4 ++-- util/json.c | 6 ++++++ util/json.h | 13 +++++++++++++ util/jsonpull.h | 3 ++- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 util/json.c create mode 100644 util/json.h diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 36ba0077..95f114ec 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -112,12 +112,12 @@ endif (BUILD_WITH_LDAP) include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIRS}) -set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c jsonpull.c kb.c +set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c json.c jsonpull.c kb.c ldaputils.c nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c versionutils.c xmlutils.c) set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h - jsonpull.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h + json.h jsonpull.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h uuidutils.h versionutils.h xmlutils.h) if (BUILD_STATIC) diff --git a/util/json.c b/util/json.c new file mode 100644 index 00000000..9d01a04e --- /dev/null +++ b/util/json.c @@ -0,0 +1,6 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "json.h" diff --git a/util/json.h b/util/json.h new file mode 100644 index 00000000..83faaec4 --- /dev/null +++ b/util/json.h @@ -0,0 +1,13 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _GVM_JSON_H +#define _GVM_JSON_H + +#define _GNU_SOURCE + +#include + +#endif /* _GVM_JSON_H */ diff --git a/util/jsonpull.h b/util/jsonpull.h index 50d36578..6e561bc5 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -8,7 +8,8 @@ #define _GNU_SOURCE -#include +#include "json.h" + #include #include From 6a38901dc50e507a36c8efcd760bb70323a23ead Mon Sep 17 00:00:00 2001 From: Matt Mundell Date: Mon, 25 Nov 2024 17:22:49 +0200 Subject: [PATCH 2/3] Move gvm_json_string_escape to json.c --- CMakeLists.txt | 2 +- util/CMakeLists.txt | 15 +++++++++++ util/json.c | 58 +++++++++++++++++++++++++++++++++++++++++++ util/json.h | 5 ++++ util/json_tests.c | 51 +++++++++++++++++++++++++++++++++++++ util/jsonpull.c | 58 ------------------------------------------- util/jsonpull.h | 3 --- util/jsonpull_tests.c | 22 +--------------- 8 files changed, 131 insertions(+), 83 deletions(-) create mode 100644 util/json_tests.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7578df95..c354379c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,7 +232,7 @@ if (BUILD_TESTS AND NOT SKIP_SRC) DEPENDS array-test alivedetection-test boreas_error-test boreas_io-test cli-test cpeutils-test cvss-test ping-test sniffer-test util-test networking-test passwordbasedauthentication-test xmlutils-test version-test versionutils-test - osp-test nvti-test hosts-test jsonpull-test compressutils-test) + osp-test nvti-test hosts-test json-test jsonpull-test compressutils-test) endif (BUILD_TESTS AND NOT SKIP_SRC) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 95f114ec..598a6005 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -148,6 +148,21 @@ endif (BUILD_SHARED) ## Tests if (BUILD_TESTS) + add_executable (json-test + EXCLUDE_FROM_ALL + json_tests.c) + + add_test (json-test json-test) + + target_include_directories (json-test PRIVATE ${CGREEN_INCLUDE_DIRS}) + + target_link_libraries (json-test ${CGREEN_LIBRARIES} + ${GLIB_LDFLAGS} ${CJSON_LDFLAGS}) + + add_custom_target (tests-json + DEPENDS json-test) + + add_executable (jsonpull-test EXCLUDE_FROM_ALL jsonpull_tests.c) diff --git a/util/json.c b/util/json.c index 9d01a04e..d33a001b 100644 --- a/util/json.c +++ b/util/json.c @@ -4,3 +4,61 @@ */ #include "json.h" + +/** + * @brief Escapes a string according to the JSON or JSONPath standard + * + * @param[in] string The string to escape + * @param[in] single_quote Whether to escape single quotes + * + * @return The escaped string + */ +gchar * +gvm_json_string_escape (const char *string, gboolean single_quote) +{ + gchar *point; + if (string == NULL) + return NULL; + + GString *escaped = g_string_sized_new (strlen (string)); + for (point = (char *) string; *point != 0; point++) + { + unsigned char character = *point; + + if ((character > 31) && (character != '\\') + && (single_quote ? (character != '\'') : (character != '\"'))) + { + g_string_append_c (escaped, character); + } + else + { + g_string_append_c (escaped, '\\'); + switch (*point) + { + case '\\': + case '\'': + case '\"': + g_string_append_c (escaped, *point); + break; + case '\b': + g_string_append_c (escaped, 'b'); + break; + case '\f': + g_string_append_c (escaped, 'f'); + break; + case '\n': + g_string_append_c (escaped, 'n'); + break; + case '\r': + g_string_append_c (escaped, 'r'); + break; + case '\t': + g_string_append_c (escaped, 't'); + break; + default: + g_string_append_printf (escaped, "u%04x", character); + } + } + } + return g_string_free (escaped, FALSE); +} diff --git a/util/json.h b/util/json.h index 83faaec4..e72e1fce 100644 --- a/util/json.h +++ b/util/json.h @@ -10,4 +10,9 @@ #include +#include + +gchar * +gvm_json_string_escape (const char *, gboolean); + #endif /* _GVM_JSON_H */ diff --git a/util/json_tests.c b/util/json_tests.c new file mode 100644 index 00000000..c005b6bd --- /dev/null +++ b/util/json_tests.c @@ -0,0 +1,51 @@ +/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "json.c" + +#include +#include +#include + +Describe (json); +BeforeEach (json) +{ +} +AfterEach (json) +{ +} + +Ensure (json, can_json_escape_strings) +{ + const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; + const char *escaped_string_dq = "\\\"'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü'\\\""; + const char *escaped_string_sq = "\"\\'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü\\'\""; + + gchar *escaped_string = NULL; + escaped_string = gvm_json_string_escape (NULL, FALSE); + assert_that (escaped_string, is_null); + + escaped_string = gvm_json_string_escape (unescaped_string, FALSE); + assert_that (escaped_string, is_equal_to_string (escaped_string_dq)); + g_free (escaped_string); + + escaped_string = gvm_json_string_escape (unescaped_string, TRUE); + assert_that (escaped_string, is_equal_to_string (escaped_string_sq)); + g_free (escaped_string); +} + +int +main (int argc, char **argv) +{ + TestSuite *suite; + + suite = create_test_suite (); + + add_test_with_context (suite, json, can_json_escape_strings); + + if (argc > 1) + return run_single_test (suite, argv[1], create_text_reporter ()); + return run_test_suite (suite, create_text_reporter ()); +} diff --git a/util/jsonpull.c b/util/jsonpull.c index 12df83b5..63b8443e 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -11,64 +11,6 @@ #define GVM_JSON_CHAR_ERROR -2 ///< Error reading file #define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state -/** - * @brief Escapes a string according to the JSON or JSONPath standard - * - * @param[in] string The string to escape - * @param[in] single_quote Whether to escape single quotes - * - * @return The escaped string - */ -gchar * -gvm_json_string_escape (const char *string, gboolean single_quote) -{ - gchar *point; - if (string == NULL) - return NULL; - - GString *escaped = g_string_sized_new (strlen (string)); - for (point = (char *) string; *point != 0; point++) - { - unsigned char character = *point; - - if ((character > 31) && (character != '\\') - && (single_quote ? (character != '\'') : (character != '\"'))) - { - g_string_append_c (escaped, character); - } - else - { - g_string_append_c (escaped, '\\'); - switch (*point) - { - case '\\': - case '\'': - case '\"': - g_string_append_c (escaped, *point); - break; - case '\b': - g_string_append_c (escaped, 'b'); - break; - case '\f': - g_string_append_c (escaped, 'f'); - break; - case '\n': - g_string_append_c (escaped, 'n'); - break; - case '\r': - g_string_append_c (escaped, 'r'); - break; - case '\t': - g_string_append_c (escaped, 't'); - break; - default: - g_string_append_printf (escaped, "u%04x", character); - } - } - } - return g_string_free (escaped, FALSE); -} - /** * @brief Creates a new JSON path element. * diff --git a/util/jsonpull.h b/util/jsonpull.h index 6e561bc5..1ece9f79 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -98,9 +98,6 @@ typedef struct size_t parse_buffer_limit; ///< Maximum parse buffer size } gvm_json_pull_parser_t; -gchar * -gvm_json_string_escape (const char *, gboolean); - gvm_json_path_elem_t * gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t, int); diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index 444f5a66..e4492184 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "json.c" #include "jsonpull.c" #include @@ -72,25 +73,6 @@ read_with_error_on_eof (void *stream_cookie, char *buf, size_t size) #define JSON_READ_ERROR "error reading JSON stream: Input/output error" -Ensure (jsonpull, can_json_escape_strings) -{ - const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; - const char *escaped_string_dq = "\\\"'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü'\\\""; - const char *escaped_string_sq = "\"\\'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü\\'\""; - - gchar *escaped_string = NULL; - escaped_string = gvm_json_string_escape (NULL, FALSE); - assert_that (escaped_string, is_null); - - escaped_string = gvm_json_string_escape (unescaped_string, FALSE); - assert_that (escaped_string, is_equal_to_string (escaped_string_dq)); - g_free (escaped_string); - - escaped_string = gvm_json_string_escape (unescaped_string, TRUE); - assert_that (escaped_string, is_equal_to_string (escaped_string_sq)); - g_free (escaped_string); -} - Ensure (jsonpull, can_init_parser_with_defaults) { gvm_json_pull_parser_t parser; @@ -1132,8 +1114,6 @@ main (int argc, char **argv) suite = create_test_suite (); - add_test_with_context (suite, jsonpull, can_json_escape_strings); - add_test_with_context (suite, jsonpull, can_init_parser_with_defaults); add_test_with_context (suite, jsonpull, can_parse_false); From 949f05acc637e4d7cb369111066cb6b662be04b0 Mon Sep 17 00:00:00 2001 From: Matt Mundell Date: Mon, 25 Nov 2024 18:04:44 +0200 Subject: [PATCH 3/3] Add gvm_json_obj_double --- openvasd/openvasd.c | 22 +++++----------------- openvasd/vtparser.c | 20 ++++++-------------- util/json.c | 20 ++++++++++++++++++++ util/json.h | 3 +++ 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/openvasd/openvasd.c b/openvasd/openvasd.c index a8ed0e48..7298e013 100644 --- a/openvasd/openvasd.c +++ b/openvasd/openvasd.c @@ -12,6 +12,7 @@ #include "../base/array.h" #include "../base/networking.h" +#include "../util/json.h" #include #include @@ -1095,7 +1096,6 @@ openvasd_parsed_results (openvasd_connector_t conn, unsigned long first, const gchar *err = NULL; openvasd_resp_t resp = NULL; openvasd_result_t result = NULL; - unsigned long id = 0; gchar *type = NULL; gchar *ip_address = NULL; gchar *hostname = NULL; @@ -1133,10 +1133,6 @@ openvasd_parsed_results (openvasd_connector_t conn, unsigned long first, // error goto res_cleanup; - if ((item = cJSON_GetObjectItem (result_obj, "id")) != NULL - && cJSON_IsNumber (item)) - id = item->valuedouble; - if ((item = cJSON_GetObjectItem (result_obj, "type")) != NULL && cJSON_IsString (item)) type = g_strdup (item->valuestring); @@ -1193,7 +1189,8 @@ openvasd_parsed_results (openvasd_connector_t conn, unsigned long first, detail_source_description = g_strdup (detail_obj->valuestring); } - result = openvasd_result_new (id, type, ip_address, hostname, oid, port, + result = openvasd_result_new (gvm_json_obj_double (result_obj, "id"), + type, ip_address, hostname, oid, port, protocol, message, detail_name, detail_value, detail_source_type, detail_source_name, detail_source_description); @@ -1410,7 +1407,6 @@ openvasd_parsed_scan_status (openvasd_connector_t conn) cJSON *status = NULL; openvasd_resp_t resp = NULL; gchar *status_val = NULL; - time_t start_time = 0, end_time = 0; int progress = -1; openvasd_status_t status_code = OPENVASD_SCAN_STATUS_ERROR; openvasd_scan_status_t status_info; @@ -1433,14 +1429,6 @@ openvasd_parsed_scan_status (openvasd_connector_t conn) goto status_cleanup; status_val = g_strdup (status->valuestring); - if ((status = cJSON_GetObjectItem (parser, "start_time")) != NULL - && !cJSON_IsNumber (status)) - start_time = status->valuedouble; - - if ((status = cJSON_GetObjectItem (parser, "end_time")) != NULL - && !cJSON_IsNumber (status)) - end_time = status->valuedouble; - progress = openvasd_get_scan_progress_ext (NULL, resp); status_cleanup: @@ -1451,8 +1439,8 @@ openvasd_parsed_scan_status (openvasd_connector_t conn) g_free (status_val); status_info->status = status_code; - status_info->end_time = end_time; - status_info->start_time = start_time; + status_info->end_time = gvm_json_obj_double (parser, "end_time"); + status_info->start_time = gvm_json_obj_double (parser, "start_time"); status_info->progress = progress; return status_info; diff --git a/openvasd/vtparser.c b/openvasd/vtparser.c index 2007598e..ce51499c 100644 --- a/openvasd/vtparser.c +++ b/openvasd/vtparser.c @@ -83,13 +83,9 @@ add_tags_to_nvt (nvti_t *nvt, cJSON *tag_obj) && cJSON_IsString (item)) nvti_set_affected (nvt, item->valuestring); - if ((item = cJSON_GetObjectItem (tag_obj, "creation_date")) != NULL - && cJSON_IsNumber (item)) - nvti_set_creation_time (nvt, item->valuedouble); + nvti_set_creation_time (nvt, gvm_json_obj_double (tag_obj, "creation_date")); - if ((item = cJSON_GetObjectItem (tag_obj, "last_modification")) != NULL - && cJSON_IsNumber (item)) - nvti_set_modification_time (nvt, item->valuedouble); + nvti_set_modification_time (nvt, gvm_json_obj_double (tag_obj, "last_modification")); if ((item = cJSON_GetObjectItem (tag_obj, "insight")) != NULL && cJSON_IsString (item)) @@ -150,7 +146,6 @@ add_tags_to_nvt (nvti_t *nvt, cJSON *tag_obj) gchar *severity_origin = NULL, *severity_type = NULL; gchar *cvss_base; - time_t severity_date = 0; double cvss_base_dbl; if (g_strrstr (severity_vector, "CVSS:3")) @@ -160,17 +155,14 @@ add_tags_to_nvt (nvti_t *nvt, cJSON *tag_obj) cvss_base_dbl = get_cvss_score_from_base_metrics (severity_vector); - if ((item = cJSON_GetObjectItem (tag_obj, "severity_date")) != NULL - && cJSON_IsNumber (item)) - severity_date = item->valuedouble; - if ((item = cJSON_GetObjectItem (tag_obj, "severity_origin")) != NULL && cJSON_IsString (item)) severity_origin = item->valuestring; - nvti_add_vtseverity ( - nvt, vtseverity_new (severity_type, severity_origin, severity_date, - cvss_base_dbl, severity_vector)); + nvti_add_vtseverity (nvt, + vtseverity_new (severity_type, severity_origin, + gvm_json_obj_double (tag_obj, "severity_date"), + cvss_base_dbl, severity_vector)); nvti_add_tag (nvt, "cvss_base_vector", severity_vector); diff --git a/util/json.c b/util/json.c index d33a001b..c865b2b9 100644 --- a/util/json.c +++ b/util/json.c @@ -62,3 +62,23 @@ gvm_json_string_escape (const char *string, gboolean single_quote) } return g_string_free (escaped, FALSE); } + +/** + * @brief Get a double field from a JSON object. + * + * @param[in] obj Object + * @param[in] key Field name. + * + * @return A double. + */ +double +gvm_json_obj_double (cJSON *obj, const gchar *key) +{ + cJSON *item; + + item = cJSON_GetObjectItem (obj, key); + if (item && cJSON_IsNumber (item)) + return item->valuedouble; + + return 0; +} diff --git a/util/json.h b/util/json.h index e72e1fce..277be4db 100644 --- a/util/json.h +++ b/util/json.h @@ -15,4 +15,7 @@ gchar * gvm_json_string_escape (const char *, gboolean); +double +gvm_json_obj_double (cJSON *, const gchar *); + #endif /* _GVM_JSON_H */