diff --git a/README.md b/README.md index 9552a56c6..5d048d214 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Prerequisites: * pkg-config * gcc * zlib >= 1.2 +* libbrotli (optional, for Brotli compression) Prerequisites for building documentation: * Doxygen diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index a876c148f..5e4620652 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@/gsad +STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -753,7 +753,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_SOURCE_DIR@/gsad/src +INPUT = @CMAKE_SOURCE_DIR@/src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -822,7 +822,6 @@ EXCLUDE_SYMBOLS = # command). EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ \ - @CMAKE_SOURCE_DIR@/gsad \ @CMAKE_CURRENT_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the diff --git a/doc/Doxyfile_full.in b/doc/Doxyfile_full.in index 5736feeb5..a94f92b57 100644 --- a/doc/Doxyfile_full.in +++ b/doc/Doxyfile_full.in @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@/gsad +STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -753,7 +753,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_SOURCE_DIR@/gsad/src +INPUT = @CMAKE_SOURCE_DIR@/src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -822,7 +822,6 @@ EXCLUDE_SYMBOLS = # command). EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ \ - @CMAKE_SOURCE_DIR@/gsad \ @CMAKE_CURRENT_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the diff --git a/doc/Doxyfile_xml.in b/doc/Doxyfile_xml.in index a4913783e..bdf9c5190 100644 --- a/doc/Doxyfile_xml.in +++ b/doc/Doxyfile_xml.in @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@/gsad +STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -753,7 +753,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_SOURCE_DIR@/gsad/src +INPUT = @CMAKE_SOURCE_DIR@/src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -822,7 +822,6 @@ EXCLUDE_SYMBOLS = # command). EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ \ - @CMAKE_SOURCE_DIR@/gsad \ @CMAKE_CURRENT_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7d2e5473..349ae67f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ pkg_check_modules (LIBGVM_UTIL REQUIRED libgvm_util>=22.6) pkg_check_modules (LIBGVM_GMP REQUIRED libgvm_gmp>=22.6) pkg_check_modules (GNUTLS REQUIRED gnutls>=3.2.15) pkg_check_modules (ZLIB REQUIRED zlib>=1.2) +pkg_check_modules (BROTLI libbrotlienc) message (STATUS "Looking for libgcrypt...") find_library (LIBGCRYPT gcrypt) @@ -63,6 +64,9 @@ set (HARDENING_FLAGS "-D_FORTIFY_SOURCE=2 -fstack-protector") set (LINKER_HARDENING_FLAGS "-Wl,-z,relro -Wl,-z,now") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wformat -Wformat-security") +if (BROTLI_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_BROTLI=1") +endif (BROTLI_FOUND) set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror") set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${HARDENING_FLAGS}") @@ -73,7 +77,8 @@ include_directories (${LIBMICROHTTPD_INCLUDE_DIRS} ${LIBXML_INCLUDE_DIRS} ${LIBGVM_UTIL_INCLUDE_DIRS} ${LIBGVM_GMP_INCLUDE_DIRS} ${GNUTLS_INCLUDE_DIRS} - ${ZLIB_INCLUDE_DIRS}) + ${ZLIB_INCLUDE_DIRS} + ${BROTLI_INCLUDE_DIRS}) find_package (Threads) @@ -104,6 +109,7 @@ target_link_libraries (gsad ${LIBMICROHTTPD_LDFLAGS} ${LIBGCRYPT_LDFLAGS} ${GNUTLS_LDFLAGS} ${ZLIB_LDFLAGS} + ${BROTLI_LDFLAGS} ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} diff --git a/src/gsad.c b/src/gsad.c index 92a2fec8a..167e48691 100644 --- a/src/gsad.c +++ b/src/gsad.c @@ -30,9 +30,6 @@ * \section Introduction * \verbinclude README.md * - * \section Installation - * \verbinclude INSTALL - * * \section copying License * \verbinclude LICENSE */ @@ -45,6 +42,9 @@ #include #include +#ifdef HAVE_BROTLI +#include +#endif #include #include #include @@ -1161,32 +1161,59 @@ watch_client_connection (void *data) * @return 1 if may, else 0. */ static int -may_compress_response (http_connection_t *con) +may_compress (http_connection_t *con, const char *encoding) { - const char *ae; - const char *de; + const char *all, *one; - ae = MHD_lookup_connection_value (con, MHD_HEADER_KIND, - MHD_HTTP_HEADER_ACCEPT_ENCODING); - if (ae == NULL) + all = MHD_lookup_connection_value (con, MHD_HEADER_KIND, + MHD_HTTP_HEADER_ACCEPT_ENCODING); + if (all == NULL) return 0; - if (strcmp (ae, "*") == 0) + if (strcmp (all, "*") == 0) return 1; - de = strstr (ae, "deflate"); - if (de == NULL) + one = strstr (all, encoding); + if (one == NULL) return 0; - if (((de == ae) || (de[-1] == ',') || (de[-1] == ' ')) - && ((de[strlen ("deflate")] == '\0') || (de[strlen ("deflate")] == ',') - || (de[strlen ("deflate")] == ';'))) + if (((one == all) || (one[-1] == ',') || (one[-1] == ' ')) + && ((one[strlen (encoding)] == '\0') || (one[strlen (encoding)] == ',') + || (one[strlen (encoding)] == ';'))) return 1; return 0; } /** - * @brief Compress response. + * @brief Check whether may compress response. + * + * @param[in] con HTTP Connection + * + * @return 1 if may, else 0. + */ +static int +may_deflate (http_connection_t *con) +{ + return may_compress (con, "deflate"); +} + +#ifdef HAVE_BROTLI +/** + * @brief Check whether may compress response. + * + * @param[in] con HTTP Connection + * + * @return 1 if may, else 0. + */ +static int +may_brotli (http_connection_t *con) +{ + return may_compress (con, "br"); +} +#endif + +/** + * @brief Compress response with zlib. * * @param[in] res_len Response length. * @param[in] res Response. @@ -1196,8 +1223,8 @@ may_compress_response (http_connection_t *con) * @return 1 on success, else 0. */ static int -compress_response (const size_t res_len, const char *res, size_t *comp_len, - char **comp) +compress_response_deflate (const size_t res_len, const char *res, + size_t *comp_len, char **comp) { Bytef *cbuf; uLongf cbuf_size; @@ -1219,6 +1246,46 @@ compress_response (const size_t res_len, const char *res, size_t *comp_len, return 0; } +#ifdef HAVE_BROTLI +/** + * @brief Compress response with Brotli. + * + * @param[in] res_len Response length. + * @param[in] res Response. + * @param[out] comp_len Compressed length. + * @param[out] comp Compressed response. + * + * @return 1 on success, else 0. + */ +static int +compress_response_brotli (const size_t res_len, const char *res, + size_t *comp_len, char **comp) +{ + size_t cbuf_size; + uint8_t *cbuf; + int ret; + + cbuf_size = BrotliEncoderMaxCompressedSize (res_len); + cbuf = g_malloc (cbuf_size); + + ret = BrotliEncoderCompress (BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, + BROTLI_DEFAULT_MODE, res_len, (uint8_t *) res, + &cbuf_size, cbuf); + + if ((ret == BROTLI_TRUE) && (cbuf_size < res_len)) + { + *comp = (char *) cbuf; + *comp_len = cbuf_size; + g_warning ("%s: 1", __func__); + return 1; + } + + g_free (cbuf); + g_warning ("%s: 0", __func__); + return 0; +} +#endif + /** * @brief Handle a complete GET request. * @@ -1245,8 +1312,10 @@ exec_gmp_get (http_connection_t *con, gsad_connection_info_t *con_info, cmd_response_data_t *response_data; pthread_t watch_thread; connection_watcher_data_t *watcher_data; - validator_t validator = get_validator (); + validator_t validator; + gchar *encoding; + validator = get_validator (); response_data = cmd_response_data_new (); cmd = params_value (params, "cmd"); @@ -1566,24 +1635,42 @@ exec_gmp_get (http_connection_t *con, gsad_connection_info_t *con_info, if (res_len == 0) res_len = strlen (res); - if (may_compress_response (con)) + encoding = NULL; + +#ifdef HAVE_BROTLI + if (may_brotli (con)) + { + gsize comp_len; + + if (compress_response_brotli (res_len, res, &comp_len, &comp)) + { + free (res); + res_len = comp_len; + res = comp; + encoding = "br"; + } + } +#endif + + if ((encoding == NULL) && may_deflate (con)) { gsize comp_len; - if (compress_response (res_len, res, &comp_len, &comp)) + if (compress_response_deflate (res_len, res, &comp_len, &comp)) { free (res); res_len = comp_len; res = comp; + encoding = "deflate"; } } response = MHD_create_response_from_buffer (res_len, (void *) res, MHD_RESPMEM_MUST_FREE); - if (comp) + if (encoding) MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_ENCODING, - "deflate"); + encoding); if (watcher_data) { diff --git a/src/gsad_gmp.c b/src/gsad_gmp.c index c4a3f2ad4..d45c60db9 100644 --- a/src/gsad_gmp.c +++ b/src/gsad_gmp.c @@ -762,6 +762,13 @@ message_invalid (gvm_connection_t *connection, credentials_t *credentials, * @brief Set redirect or return a basic action_result page based on entity. * * @param[in] connection Connection to manager + * @param[in] credentials Username and password for authentication. + * @param[in] params Request parameters. + * @param[in] entity Entity. + * @param[in] action Name of the action. + * @param[in] response_data Response data. + * + * @return Enveloped XML object. */ static gchar * response_from_entity (gvm_connection_t *connection, credentials_t *credentials, @@ -794,7 +801,6 @@ response_from_entity (gvm_connection_t *connection, credentials_t *credentials, * @param[in] type Type of resource. * @param[in] credentials Username and password for authentication. * @param[in] params Request parameters. - * @param[in] extra_xml Extra XML to insert inside page element. * @param[in] arguments Extra arguments for GMP GET command. * @param[out] response_data Extra data return for the HTTP response. * @@ -938,7 +944,6 @@ get_one (gvm_connection_t *connection, const char *type, * @param[in] type Entity type. * @param[in] credentials Username and password for authentication. * @param[in] params Request parameters. - * @param[in] extra_xml Extra XML to insert inside page element. * @param[in] arguments Extra arguments for GMP GET command. * @param[out] response_data Extra data return for the HTTP response. * @@ -1393,6 +1398,7 @@ export_resource (gvm_connection_t *connection, const char *type, * @brief Export a list of resources. * * @param[in] connection Connection to manager. + * @param[in] type Type of resource. * @param[in] credentials Username and password for authentication. * @param[in] params Request parameters. * @param[out] response_data Extra data return for the HTTP response. @@ -1696,7 +1702,6 @@ move_resource_to_trash (gvm_connection_t *connection, const char *type, * @brief Delete a resource from the trashcan * * @param[in] connection Connection to manager. - * @param[in] type Type of resource. * @param[in] credentials Username and password for authentication. * @param[in] params Request parameters. * @param[out] response_data Extra data return for the HTTP response. @@ -1866,19 +1871,6 @@ resource_action (gvm_connection_t *connection, credentials_t *credentials, } \ } -/** - * @brief Returns page to create a new container task. - * - * @param[in] connection Connection to manager. - * @param[in] credentials Credentials of user issuing the action. - * @param[in] params Request parameters. - * @param[in] message If not NULL, display message. - * @param[in] extra_xml Extra XML to insert inside page element. - * @param[out] response_data Extra data return for the HTTP response. - * - * @return Enveloped XML object. - */ - /** * @brief Create a report, get all tasks, envelope the result. * @@ -3321,10 +3313,10 @@ create_credential_gmp (gvm_connection_t *connection, credentials_t *credentials, /** * @brief Get one credential, envelope the result. * - * @param[in] connection Connection to manager. + * @param[in] connection Connection to manager. * @param[in] credentials Username and password for authentication. * @param[in] params Request parameters. - * @param[in] commands Extra commands to run before the others. + * @param[in] extra_xml Extra XML to insert inside page element. * @param[out] response_data Extra data return for the HTTP response. * * @return Enveloped XML object. @@ -4303,14 +4295,13 @@ get_alerts (gvm_connection_t *connection, credentials_t *, params_t *, #define EVENT_TYPE_TICKET_RECEIVED "Ticket received" #define EVENT_TYPE_ASSIGNED_TICKET_CHANGED "Assigned ticket changed" #define EVENT_TYPE_OWNED_TICKET_CHANGED "Owned ticket changed" + /** * @brief Send event data for an alert. * * @param[in] xml XML. * @param[out] data Data. * @param[out] event Event. - * - * @return 0 on success, -1 on error. */ static void append_alert_event_data (GString *xml, params_t *data, const char *event) @@ -5584,9 +5575,8 @@ delete_target_gmp (gvm_connection_t *connection, credentials_t *credentials, * @brief Restore a resource, get all trash, envelope the result. * * @param[in] connection Connection to manager. - * @param[in] connection Connection to manager. - * @param[in] credentials Username and password for authentication. - * @param[in] params Request parameters. + * @param[in] credentials Username and password for authentication. + * @param[in] params Request parameters. * @param[out] response_data Extra data return for the HTTP response. * * @return Enveloped XML object. @@ -7811,9 +7801,7 @@ delete_report_gmp (gvm_connection_t *connection, credentials_t *credentials, * @param[in] connection Connection to manager. * @param[in] credentials Username and password for authentication. * @param[in] params Request parameters. - * @param[in] commands Extra commands to run before the others. * @param[in] extra_xml Extra XML to insert inside page element. - * @param[out] error Set to 1 if error, else 0. * @param[out] response_data Extra data return for the HTTP response. * * @return Report. @@ -11370,6 +11358,8 @@ get_trash_tickets_gmp (gvm_connection_t *connection, credentials_t *credentials, * @param[out] xml GString to write responses to. * @param[out] modify_failed_flag Pointer to an int to set to 1 on failure * to modify one of the settings. + * @param[out] response_data Extra data return for the HTTP response. + * * @return 0 on success, -1 on error. */ static int @@ -11437,10 +11427,6 @@ send_settings_filters (gvm_connection_t *connection, params_t *data, * @param[in] credentials Credentials of user issuing the action. * @param[in] params Request parameters. * @param[in] accept_language Accept-Language, from browser. - * @param[out] timezone Timezone. Caller must free. - * @param[out] password Password. Caller must free. - * @param[out] severity Severity. Caller must free. - * @param[out] language Language. Caller must free. * @param[out] response_data Extra data return for the HTTP response. * * @return Enveloped XML object. @@ -13330,9 +13316,9 @@ create_port_range_gmp (gvm_connection_t *connection, credentials_t *credentials, * @brief Get one port_list, envelope the result. * * @param[in] connection Connection to manager. - * @param[in] credentials Username and password for authentication. - * @param[in] params Request parameters. - * @param[in] commands Extra commands to run before the others. + * @param[in] credentials Username and password for authentication. + * @param[in] params Request parameters. + * @param[in] extra_xml Extra XML to insert inside page element. * @param[out] response_data Extra data return for the HTTP response. * * @return Enveloped XML object. @@ -16077,7 +16063,6 @@ get_asset_gmp (gvm_connection_t *connection, credentials_t *credentials, * @param[in] connection Connection to manager. * @param[in] credentials Credentials for the manager connection. * @param[in] params Request parameters. - * @param[in] extra_xml Extra XML to insert inside page element. * @param[out] response_data Extra data return for the HTTP response. * * @return XML enveloped assets response or error message. @@ -17257,17 +17242,12 @@ authenticate_gmp (const gchar *username, const gchar *password, gchar **role, } /** - * @brief Check authentication credentials. + * @brief Log out. * * @param[in] username Username. * @param[in] password Password. - * @param[out] role Role. - * @param[out] timezone Timezone. - * @param[out] capabilities Capabilities of manager. - * @param[out] language User Interface Language, or NULL. - * @param[out] pw_warning Password warning message, NULL if password is OK. * - * @return 0 success, 1 manager down, 2 failed, 3 timeout, -1 error. + * @return 0 success, else error. */ int logout_gmp (const gchar *username, const gchar *password) diff --git a/src/gsad_http.c b/src/gsad_http.c index 61c1e38c4..f2510e8eb 100644 --- a/src/gsad_http.c +++ b/src/gsad_http.c @@ -860,7 +860,6 @@ add_cors_headers (http_response_t *response) * @brief Add header to forbid caching to a HTTP response. * * @param[in] response The HTTP response to add the headers to. - * @param[in] allow_caching 1 to allow caching, 0 to forbid. */ void add_forbid_caching_headers (http_response_t *response)