diff --git a/kerberos/authenticate_test.c b/kerberos/authenticate_test.c index 3ea302e2d..f0946e32d 100644 --- a/kerberos/authenticate_test.c +++ b/kerberos/authenticate_test.c @@ -1,9 +1,8 @@ -#include "openvas-krb5.h" +#include "../misc/openvas-krb5.h" #include #include -#define REALM "GBKERB.LOCAL" #define GUARD_ENV_SET(var, env) \ do \ @@ -15,6 +14,7 @@ } \ } \ while (0) + int main () { diff --git a/kerberos/.gitignore b/misc/.gitignore similarity index 100% rename from kerberos/.gitignore rename to misc/.gitignore diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index bd647ff24..ec939a385 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -15,6 +15,8 @@ pkg_check_modules (GLIB REQUIRED glib-2.0>=2.42) pkg_check_modules (GLIB_JSON REQUIRED json-glib-1.0>=1.4.4) pkg_check_modules (GNUTLS REQUIRED gnutls>=3.6.4) pkg_check_modules (CURL REQUIRED libcurl>=7.74.0) +pkg_check_modules (KRB5 REQUIRED krb5) +pkg_check_modules (KRB5_GSSAPI REQUIRED krb5-gssapi) pkg_check_modules (LIBGVM_BASE REQUIRED libgvm_base>=22.4) pkg_check_modules (LIBGVM_UTIL REQUIRED libgvm_util>=22.4) @@ -69,13 +71,13 @@ add_definitions (-DOPENVAS_MISC_VERSION="${PROJECT_VERSION_STRING}") include_directories (${GLIB_INCLUDE_DIRS} ${GLIB_JSON_INCLUDE_DIRS} ${LIBGVM_BASE_INCLUDE_DIRS} - ${GNUTLS_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS}) + ${GNUTLS_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${KRB5_INCLUDE_DIRS} ${KRB5_GSSAPI_INCLUDE_DIRS}) # Library set (FILES bpf_share.c ftp_funcs.c vendorversion.c network.c plugutils.c pcap.c scan_id.c strutils.c table_driven_lsc.c ipc.c ipc_openvas.c ipc_pipe.c - user_agent.c scanneraux.c kb_cache.c heartbeat.c) + user_agent.c scanneraux.c kb_cache.c heartbeat.c openvas-krb5.c) # On windows we are always PIC and stack-protector is replaces by DEP # Also stack protection needs a shared library to work @@ -93,7 +95,7 @@ set_target_properties (openvas_misc_shared PROPERTIES VERSION "${PROJECT_VERSION target_link_libraries (openvas_misc_shared LINK_PRIVATE ${GNUTLS_LDFLAGS} ${UUID_LDFLAGS} ${GLIB_LDFLAGS} ${GLIB_JSON_LDFLAGS} - ${PCAP_LDFLAGS} ${LIBGVM_BOREAS_LDFLAGS} ${CURL_LDFLAGS} + ${PCAP_LDFLAGS} ${LIBGVM_BOREAS_LDFLAGS} ${CURL_LDFLAGS} ${KRB5_LDFLAGS} ${KRB5_GSSAPI_LDFLAGS} ${LINKER_HARDENING_FLAGS}) if (OPENVAS_STATE_DIR) @@ -136,7 +138,7 @@ set (LINK_LIBS_FOR_TESTS cgreen ${LIBGVM_BASE_LDFLAGS} ${GLIB_LDFLAGS} ${PCAP_LDFLAGS} - ${CURL_LDFLAGS} + ${CURL_LDFLAGS} ${KRB5_LDFLAGS} ${KRB5_GSSAPI_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${CMAKE_THREAD_LIBS_INIT} ${ALIVEDETECTION_TEST_LINKER_WRAP_OPTIONS}) @@ -163,7 +165,7 @@ target_include_directories (ipc-openvas-test PRIVATE ${CGREEN_INCLUDE_DIRS}) target_link_libraries (ipc-openvas-test cgreen ${GLIB_LDFLAGS} ${GLIB_JSON_LDFLAGS} - ${CURL_LDFLAGS} + ${CURL_LDFLAGS} ${KRB5_LDFLAGS} ${KRB5_GSSAPI_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_custom_target (tests-ipc-openvas @@ -178,7 +180,7 @@ target_link_libraries (lsc-test cgreen ${LIBGVM_UTIL_LDFLAGS} ${GLIB_LDFLAGS} ${GLIB_JSON_LDFLAGS} - ${CURL_LDFLAGS} + ${CURL_LDFLAGS} ${KRB5_LDFLAGS} ${KRB5_GSSAPI_LDFLAGS} ${LINKER_HARDENING_FLAGS}) add_custom_target (tests-lsc diff --git a/kerberos/openvas-krb5.c b/misc/openvas-krb5.c similarity index 99% rename from kerberos/openvas-krb5.c rename to misc/openvas-krb5.c index 117327664..d3238ef94 100644 --- a/kerberos/openvas-krb5.c +++ b/misc/openvas-krb5.c @@ -339,7 +339,7 @@ o_krb5_free_data (const OKrb5Element *element, OKrb5Data *data) // numbers but can just reuse credentials to find connections that way we can // simply reconnect when we either don't find an entry or when the ticket is // invalid witout having the caller to remember artifical identifier. -unsigned long +static unsigned long o_krb5_cache_credential_id (const OKrb5Credential *cred) { unsigned long hash = 2166136261; @@ -379,9 +379,9 @@ OKrb5ErrorCode o_krb5_cache_clear (void) { OKrb5ErrorCode result = O_KRB5_SUCCESS; +size_t i; if (element_cache == NULL) goto result; - int i; for (i = 0; i < element_cache->len; i++) { o_krb5_free_element ((element_cache->elements[i])->element); @@ -401,8 +401,8 @@ o_krb5_cache_find (const OKrb5Credential *cred) { return NULL; } - int i; unsigned long id = o_krb5_cache_credential_id (cred); + size_t i; for (i = 0; i < element_cache->len; i++) { @@ -414,7 +414,7 @@ o_krb5_cache_find (const OKrb5Credential *cred) return NULL; } -OKrb5ErrorCode +static OKrb5ErrorCode o_krb5_cache_add_element (const OKrb5Credential credentials, OKrb5CacheElement **out) { diff --git a/kerberos/openvas-krb5.h b/misc/openvas-krb5.h similarity index 100% rename from kerberos/openvas-krb5.h rename to misc/openvas-krb5.h diff --git a/nasl/CMakeLists.txt b/nasl/CMakeLists.txt index 2e888f1a4..b9df861d1 100644 --- a/nasl/CMakeLists.txt +++ b/nasl/CMakeLists.txt @@ -127,7 +127,8 @@ set (FILES arc4.c capture_packet.c charcnv.c exec.c genrand.c hmacmd5.c nasl_http.c nasl_http2.c nasl_init.c nasl_lex_ctxt.c nasl_misc_funcs.c nasl_scanner_glue.c nasl_packet_forgery.c nasl_packet_forgery_v6.c nasl_signature.c nasl_smb.c nasl_socket.c nasl_text_utils.c nasl_tree.c nasl_var.c nasl_wmi.c - nasl_isotime.c ntlmssp.c smb_crypt.c smb_crypt2.c smb_signing.c time.c) + nasl_isotime.c ntlmssp.c smb_crypt.c smb_crypt2.c smb_signing.c time.c + nasl_krb5.c) if (NOT OPENVAS_WMICLIENT_FOUND) diff --git a/nasl/nasl_init.c b/nasl/nasl_init.c index 0c8dab42d..db4bdfd48 100644 --- a/nasl/nasl_init.c +++ b/nasl/nasl_init.c @@ -27,6 +27,8 @@ #include "nasl_misc_funcs.h" #include "nasl_packet_forgery.h" #include "nasl_packet_forgery_v6.h" +#include "nasl_krb5.h" + #include /* for getenv. */ #include /* for memset */ @@ -414,6 +416,8 @@ static init_func libfuncs[] = { {"isotime_scan", nasl_isotime_scan}, {"isotime_print", nasl_isotime_print}, {"isotime_add", nasl_isotime_add}, + // krb5 + {"krb5_find_kdc", nasl_okrb5_find_kdc }, {NULL, NULL}}; /* String variables */ diff --git a/nasl/nasl_krb5.c b/nasl/nasl_krb5.c new file mode 100644 index 000000000..7b4282598 --- /dev/null +++ b/nasl/nasl_krb5.c @@ -0,0 +1,160 @@ +#include "nasl_krb5.h" + +#include "../misc/openvas-krb5.h" +#include "nasl_debug.h" +#include "nasl_func.h" +#include "nasl_global_ctxt.h" +#include "nasl_lex_ctxt.h" +#include "nasl_tree.h" +#include "nasl_var.h" +// TODO: add string function for result +#define nasl_print_krb_error(lexic, credential, result) \ + nasl_perror (lexic, "%s[config_path: %s realm: %s user: %s] => %d", \ + __func__, credential.config_path, credential.realm, \ + credential.user, result); + +OKrb5ErrorCode last_okrb5_result; +static OKrb5Credential +build_krb5_credential (lex_ctxt *lexic) +{ + OKrb5Credential credential; + credential.user = NULL; + credential.password = NULL; + // neither values from get_str_var_by_name nor getenv must be freed + if ((credential.config_path = get_str_var_by_name (lexic, "config_path")) + == NULL) + { + credential.config_path = getenv ("KRB5_CONFIG"); + if (credential.config_path == NULL) + { + credential.config_path = "/etc/krb5.conf"; + } + } + if ((credential.realm = get_str_var_by_name (lexic, "realm")) == NULL) + { + credential.realm = getenv ("KRB5_REALM"); + if (credential.realm == NULL) + { + nasl_print_krb_error (lexic, credential, O_KRB5_REALM_NOT_FOUND); + } + } + + return credential; +} + +/** + * @brief Returns the defined KDC of a given Realm + * + * This function returns the KDC of a given Realm. The Realm is defined in the + * krb5.conf file. If there is no KDC for the given Realm, the function returns + * NULL within the tree_cell to the script. + * + * The nasl function has two optional parameter: + * - realm: The realm for which the KDC should be returned. If the realm is not + * defined, then the env parameter `KRB5_REALM` is used. + * - config_path: The path to the krb5.conf file. If the path is not defined, + * then the env parameter `KRB5_CONFIG` is used. + * + * This function should only be used for debug purposes. + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing the KDC as a string. + */ +tree_cell * +nasl_okrb5_find_kdc (lex_ctxt *lexic) +{ + tree_cell *retc; + char *kdc = NULL; + OKrb5Credential credential; + + credential = build_krb5_credential (lexic); + + if ((last_okrb5_result = o_krb5_find_kdc (&credential, &kdc))) + { + nasl_print_krb_error (lexic, credential, last_okrb5_result); + return NULL; + } + + retc = alloc_typed_cell (CONST_DATA); + retc->x.str_val = kdc; + retc->size = strlen (kdc); + return retc; +} + +tree_cell * +nasl_okrb5_add_realm (lex_ctxt *lexic) +{ + tree_cell *retc; + OKrb5Credential credential; + // TODO: create macro for that + char *kdc = get_str_var_by_name (lexic, "kdc"); + if (kdc == NULL) + { + kdc = getenv ("KRB5_KDC"); + if (kdc == NULL) + { + last_okrb5_result = O_KRB5_EXPECTED_NOT_NULL; + nasl_print_krb_error (lexic, credential, last_okrb5_result); + goto exit; + } + } + + credential = build_krb5_credential (lexic); + + if ((last_okrb5_result = o_krb5_add_realm (&credential, kdc))) + { + nasl_print_krb_error (lexic, credential, last_okrb5_result); + } + +exit: + retc = alloc_typed_cell (CONST_INT); + retc->x.i_val = last_okrb5_result; + return retc; +} + +tree_cell * +nasl_okrb5_result (lex_ctxt *lexic) { + (void) lexic; + // TODO: implement function to return string representation of result + return NULL; +} + +/** + * @brief Returns 1 if the krb5 function was successful 0 otherwise + * + * The nasl function has one optional parameter: + * - retval: the return value of the krb5 function. If the value is not defined, the return value of the last krb5 function is used. + * + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing a number indicating success. + */ +tree_cell * +nasl_okrb5_is_success (lex_ctxt *lexic) { + OKrb5ErrorCode result = get_int_var_by_name (lexic, "retval", last_okrb5_result); + tree_cell *retc = alloc_typed_cell (CONST_INT); + retc->x.i_val = result == O_KRB5_SUCCESS; + return retc; +} + +/** + * @brief Returns 0 if the krb5 function was successful and 1 if it failed + * + * The nasl function has one optional parameter: + * - retval: the return value of the krb5 function. If the value is not defined, the return value of the last krb5 function is used. + * + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing a number indicating success. + */ +tree_cell * +nasl_okrb5_is_failure (lex_ctxt *lexic) { + OKrb5ErrorCode result = get_int_var_by_name (lexic, "retval", last_okrb5_result); + tree_cell *retc = alloc_typed_cell (CONST_INT); + retc->x.i_val = result != O_KRB5_SUCCESS; + return retc; +} + diff --git a/nasl/nasl_krb5.h b/nasl/nasl_krb5.h new file mode 100644 index 000000000..5095b2794 --- /dev/null +++ b/nasl/nasl_krb5.h @@ -0,0 +1,83 @@ +#include "nasl_lex_ctxt.h" +#include "nasl_tree.h" + +/** + * @brief Returns the defined KDC of a given Realm + * + * This function returns the KDC of a given Realm. The Realm is defined in the krb5.conf file. + * If there is no KDC for the given Realm, the function returns NULL within the tree_cell to the script. + * + * The nasl function has two optional parameter: + * - realm: The realm for which the KDC should be returned. If the realm is not defined, then the env parameter `KRB5_REALM` is used. + * - config_path: The path to the krb5.conf file. If the path is not defined, then the env parameter `KRB5_CONFIG` is used. + * + * This function should only be used for debug purposes. + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing the KDC as a string. + */ +tree_cell * +nasl_okrb5_find_kdc (lex_ctxt *lexic); + +/** + * @brief Adds the given KDC to the given Realm + * + * This function returns 0 on success. To retrieve a human readable error message, the function `okrb5_result` can be used. + * + * The nasl function has three optional parameter: + * - realm: The realm for which the KDC should be returned. If the realm is not defined, then the env parameter `KRB5_REALM` is used. + * - kdc: The realm for which the KDC should be returned. If the realm is not defined, then the env parameter `KRB5_KDC` is used. + * - config_path: The path to the krb5.conf file. If the path is not defined, then the env parameter `KRB5_CONFIG` is used. + * + * This function should only be used for debug purposes. + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing a number indicating success or failure. + */ +tree_cell * +nasl_okrb5_add_realm (lex_ctxt *lexic); + +/** + * @brief Returns the last result of the krb5 functions as a string + * + * The nasl function has one optional parameter: + * - retval: the return value of the krb5 function. If the value is not defined, the return value of the last krb5 function is used. + * + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing a number indicating success or failure. + */ +tree_cell * +nasl_okrb5_result (lex_ctxt *lexic); + +/** + * @brief Returns 1 if the krb5 function was successful 0 otherwise + * + * The nasl function has one optional parameter: + * - retval: the return value of the krb5 function. If the value is not defined, the return value of the last krb5 function is used. + * + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing a number indicating success. + */ +tree_cell * +nasl_okrb5_is_success (lex_ctxt *lexic); + +/** + * @brief Returns 0 if the krb5 function was successful and 1 if it failed + * + * The nasl function has one optional parameter: + * - retval: the return value of the krb5 function. If the value is not defined, the return value of the last krb5 function is used. + * + * + * @param[in] lexic NASL lexer. + * + * @return lex cell containing a number indicating success. + */ +tree_cell * +nasl_okrb5_is_failure (lex_ctxt *lexic); + diff --git a/nasl/nasl_var.c b/nasl/nasl_var.c index 80b9c6570..81e1061f8 100644 --- a/nasl/nasl_var.c +++ b/nasl/nasl_var.c @@ -1114,6 +1114,9 @@ get_variable_by_name (lex_ctxt *ctxt, const char *name) return (char *) var2str (v); } + // TODO: this is very confusing that it returns char * instead of const char * + // because it is not supposed to be modified as str_form is freed later on and + // may double free on misuse char * get_str_var_by_name (lex_ctxt *lexic, const char *name) {