From 2d92dc9241b49624829f01020436518e4bfdc538 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Tue, 20 Oct 2026 14:25:43 +0200 Subject: [PATCH 1/3] Change: Change gvmldap to accept CA certificate data. --- ldap/gvmldap.c | 128 +++++++++++++++++++++++++++++++++++++------ ldap/gvmldap_tests.c | 57 +++++++++++++++++-- 2 files changed, 165 insertions(+), 20 deletions(-) diff --git a/ldap/gvmldap.c b/ldap/gvmldap.c index b2132f19..8d4fb2f5 100644 --- a/ldap/gvmldap.c +++ b/ldap/gvmldap.c @@ -21,6 +21,10 @@ #include #include +#include +#include +#include +#include #define LDAP_DEFAULT_PORT 389 #define LDAPS_DEFAULT_PORT 636 @@ -108,41 +112,133 @@ ldap_set_timeout_option (LDAP *ldap, int option, guint timeout_seconds) return ldap_set_option (ldap, option, &tv); } +/** + * @brief Writes the CA certificate to a temporary file. + * + * @param ca_cert CA certificate content. + * + * @return Path to the temporary file containing the CA certificate, + * or NULL on failure. The caller should call g_unlink() and g_free() + * on the returned path after use. + */ +static gchar * +ldap_write_ca_cert_tmp (const gchar *ca_cert) +{ + GError *error = NULL; + gchar *path = NULL; + gint fd; + gsize remaining = 0; + const gchar *p = NULL; + + if (ca_cert == NULL || *ca_cert == '\0') + return NULL; + + fd = g_file_open_tmp ("gvmldap-ca-XXXXXX", &path, &error); + if (fd < 0) + { + g_warning ("Could not create temporary LDAP CA file: %s", + error->message); + g_clear_error (&error); + return NULL; + } + + if (fchmod (fd, 0600) != 0) + { + g_warning ("Could not set LDAP CA file permissions: %s", + g_strerror (errno)); + goto fail; + } + + p = ca_cert; + remaining = strlen (ca_cert); + + while (remaining > 0) + { + ssize_t written = write (fd, p, remaining); + + if (written < 0 && errno == EINTR) + continue; + if (written <= 0) + { + g_warning ("Could not write temporary LDAP CA file: %s", + written < 0 ? g_strerror (errno) : "write made no progress"); + goto fail; + } + + p += written; + remaining -= written; + } + + if (close (fd) != 0) + { + g_warning ("Could not close temporary LDAP CA file: %s", + g_strerror (errno)); + fd = -1; + goto fail; + } + + return path; + +fail: + if (fd >= 0) + close (fd); + + if (g_unlink (path) != 0) + g_warning ("Could not remove temporary LDAP CA file: %s", + g_strerror (errno)); + + g_free (path); + return NULL; +} + /* * @brief Configure TLS options for an LDAP connection. * * @param ldap LDAP connection. - * @param ca_cert_file Path to the CA certificate file for TLS, can be - * NULL. + * @param ca_cert CA certificate in PEM format for TLS, can be NULL. * * @return 0 on success, -1 on failure. */ static int -ldap_configure_tls (LDAP *ldap, const gchar *ca_cert_file) +ldap_configure_tls (LDAP *ldap, const gchar *ca_cert) { int require_cert = LDAP_OPT_X_TLS_DEMAND; int new_ctx = 0; - int ret; + gchar *ca_path = NULL; + int ret = -1; if (!ldap) return -1; - ret = ldap_set_option (ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &require_cert); - if (ret != LDAP_OPT_SUCCESS) + if (ldap_set_option (ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &require_cert) + != LDAP_OPT_SUCCESS) return -1; - if (ca_cert_file && ca_cert_file[0] != '\0') + if (ca_cert && ca_cert[0] != '\0') { - ret = ldap_set_option (ldap, LDAP_OPT_X_TLS_CACERTFILE, ca_cert_file); - if (ret != LDAP_OPT_SUCCESS) + ca_path = ldap_write_ca_cert_tmp (ca_cert); + if (ca_path == NULL) return -1; + + if (ldap_set_option (ldap, LDAP_OPT_X_TLS_CACERTFILE, ca_path) + != LDAP_OPT_SUCCESS) + goto cleanup; } - ret = ldap_set_option (ldap, LDAP_OPT_X_TLS_NEWCTX, &new_ctx); - if (ret != LDAP_OPT_SUCCESS) - return -1; + if (ldap_set_option (ldap, LDAP_OPT_X_TLS_NEWCTX, &new_ctx) + == LDAP_OPT_SUCCESS) + ret = 0; + + cleanup: + if (ca_path != NULL) + { + if (g_unlink (ca_path) != 0) + g_warning ("Could not remove temporary LDAP CA file: %s", + g_strerror (errno)); + g_free (ca_path); + } - return 0; + return ret; } /** @@ -151,7 +247,7 @@ ldap_configure_tls (LDAP *ldap, const gchar *ca_cert_file) * @param connection Pointer to the LDAP connection structure. * @param host The LDAP server host. * @param port The LDAP server port, 0 to use the mode's default. - * @param ca_cert_file Path to the CA certificate file for TLS. + * @param ca_cert CA certificate for TLS in PEM format. * @param tls_mode The TLS mode to use (PLAINTEXT, STARTTLS, or TLS). * @param network_timeout Network timeout in seconds. * @param operation_timeout Operation timeout in seconds. @@ -161,7 +257,7 @@ ldap_configure_tls (LDAP *ldap, const gchar *ca_cert_file) */ gvm_ldap_return_t gvm_ldap_open (gvm_ldap_connection_t **connection, const gchar *host, gint port, - const gchar *ca_cert_file, gvm_ldap_tls_mode_t tls_mode, + const gchar *ca_cert, gvm_ldap_tls_mode_t tls_mode, guint network_timeout, guint operation_timeout) { gvm_ldap_connection_t *new_connection; @@ -218,7 +314,7 @@ gvm_ldap_open (gvm_ldap_connection_t **connection, const gchar *host, gint port, if (tls_mode != GVM_LDAP_TLS_PLAINTEXT) { - if (ldap_configure_tls (new_connection->ldap, ca_cert_file) != 0) + if (ldap_configure_tls (new_connection->ldap, ca_cert) != 0) { g_warning ("%s: Failed to configure LDAP TLS", __func__); goto option_error; diff --git a/ldap/gvmldap_tests.c b/ldap/gvmldap_tests.c index f82ae0a0..93fbb38f 100644 --- a/ldap/gvmldap_tests.c +++ b/ldap/gvmldap_tests.c @@ -26,6 +26,9 @@ static int ldap_initialize_call_count = 0; static int ldap_unbind_ext_s_call_count = 0; static LDAP *last_ldap_unbind_ext_s_handle = NULL; +static gchar *last_ca_cert_path = NULL; +static gchar *ca_cert_contents_at_set_option = NULL; + static struct berval ** make_mock_bervals (const gchar **values) { @@ -121,11 +124,17 @@ int ldap_set_option (LDAP *ld, int option, const void *invalue) { (void) ld; - (void) invalue; ldap_set_option_call_count++; last_ldap_set_option_option = option; + if (option == LDAP_OPT_X_TLS_CACERTFILE && invalue != NULL) + { + last_ca_cert_path = g_strdup ((const gchar *) invalue); + g_file_get_contents (last_ca_cert_path, + &ca_cert_contents_at_set_option, NULL, NULL); + } + return mock_ldap_set_option_return_value; } @@ -189,6 +198,9 @@ AfterEach (gvmldap) mock_values_to_return = NULL; } g_clear_pointer (&last_ldap_initialize_uri, g_free); + + g_clear_pointer (&last_ca_cert_path, g_free); + g_clear_pointer (&ca_cert_contents_at_set_option, g_free); } /* ldap_build_uri */ @@ -607,6 +619,34 @@ Ensure (gvmldap, ldap_set_timeout_option_sets_timeout_for_nonzero) assert_that (ret, is_equal_to (LDAP_OPT_SUCCESS)); } +/* ldap_write_ca_cert_tmp */ + +Ensure (gvmldap, ldap_write_ca_cert_tmp_rejects_missing_cert) +{ + assert_that (ldap_write_ca_cert_tmp (NULL), is_null); + assert_that (ldap_write_ca_cert_tmp (""), is_null); +} + +Ensure (gvmldap, ldap_write_ca_cert_tmp_writes_private_file) +{ + const gchar *cert = "mock CA certificate\nsecond line\n"; + gchar *path = ldap_write_ca_cert_tmp (cert); + gchar *contents = NULL; + gsize length = 0; + struct stat st; + + assert_that (path, is_not_null); + assert_that (g_file_get_contents (path, &contents, &length, NULL), is_true); + assert_that (contents, is_equal_to_string (cert)); + assert_that ((int) length, is_equal_to ((int) strlen (cert))); + assert_that (stat (path, &st), is_equal_to (0)); + assert_that ((int) (st.st_mode & 0777), is_equal_to (0600)); + + g_free (contents); + g_unlink (path); + g_free (path); +} + /* ldap_configure_tls */ Ensure (gvmldap, ldap_configure_tls_sets_tls_options_correctly_no_cert) @@ -625,14 +665,18 @@ Ensure (gvmldap, ldap_configure_tls_sets_tls_options_correctly_no_cert) Ensure (gvmldap, ldap_configure_tls_sets_tls_options_correctly_with_cert) { LDAP *ldap = (LDAP *) 0x1; + const gchar *cert = "mock CA certificate\nsecond line\n"; int ret; - ret = ldap_configure_tls (ldap, "/path/to/cert"); + ret = ldap_configure_tls (ldap, cert); + assert_that (ret, is_equal_to (0)); assert_that (ldap_set_option_call_count, is_equal_to (3)); assert_that (last_ldap_set_option_option, is_equal_to (LDAP_OPT_X_TLS_NEWCTX)); - assert_that (ret, is_equal_to (0)); + assert_that (last_ca_cert_path, is_not_null); + assert_that (ca_cert_contents_at_set_option, is_equal_to_string (cert)); + assert_that (g_file_test (last_ca_cert_path, G_FILE_TEST_EXISTS), is_false); } Ensure (gvmldap, ldap_configure_tls_handles_returns_error_for_invalid_input) @@ -807,6 +851,11 @@ main (int argc, char **argv) add_test_with_context (suite, gvmldap, ldap_set_timeout_option_sets_timeout_for_nonzero); + add_test_with_context (suite, gvmldap, + ldap_write_ca_cert_tmp_rejects_missing_cert); + add_test_with_context (suite, gvmldap, + ldap_write_ca_cert_tmp_writes_private_file); + add_test_with_context (suite, gvmldap, ldap_configure_tls_sets_tls_options_correctly_no_cert); add_test_with_context ( @@ -838,4 +887,4 @@ main (int argc, char **argv) destroy_test_suite (suite); return ret; -} \ No newline at end of file +} From 1d886fec55273f795cce5d18323392e9a588a76a Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Tue, 20 Oct 2026 14:26:15 +0200 Subject: [PATCH 2/3] Change: Change ad_connector to accept CA certificate data. --- ad_connector/ad_connector.c | 18 +++++++------ ad_connector/ad_connector.h | 6 ++--- ad_connector/ad_connector_tests.c | 45 ++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/ad_connector/ad_connector.c b/ad_connector/ad_connector.c index 799a7888..7868bd9f 100644 --- a/ad_connector/ad_connector.c +++ b/ad_connector/ad_connector.c @@ -34,7 +34,7 @@ struct ad_connector gint ldap_port; /**< LDAP port number or 0 for default (389 for LDAP, 636 for LDAPS). */ ad_connector_tls_mode_t tls_mode; /**< TLS mode to use for the connection. */ - gchar *cacert_file; /**< CA Certificate, or NULL. */ + gchar *ca_cert; /**< CA Certificate, or NULL. */ gchar *bind_dn; /**< Distinguished Name (DN) to bind as. */ guint network_timeout; /**< Network timeout in seconds. */ guint operation_timeout; /**< Operation timeout in seconds. */ @@ -109,7 +109,7 @@ static const gchar *ad_group_attributes[] = {"sAMAccountName", "displayName", /** * @brief Create a new Active Directory connector instance. * - * The connector defaults to LDAPS, port 0, no CA certificate file, + * The connector defaults to LDAPS, port 0, no CA certificate, * no bind DN, and zero network/operation timeouts. * * Port 0 lets the LDAP layer choose the default port for the @@ -188,7 +188,7 @@ ad_connector_builder (ad_connector_t connector, ad_connector_opt_t opt, if (connector->ldap_connection) return AD_CONNECTOR_CONNECTION_ERROR; - if (val == NULL && opt != AD_CONNECTOR_OPT_CA_CERT_FILE) + if (val == NULL && opt != AD_CONNECTOR_OPT_CA_CERT) return AD_CONNECTOR_INVALID_VALUE; switch (opt) @@ -213,9 +213,11 @@ ad_connector_builder (ad_connector_t connector, ad_connector_opt_t opt, connector->tls_mode = tls_mode; break; } - case AD_CONNECTOR_OPT_CA_CERT_FILE: - g_free (connector->cacert_file); - connector->cacert_file = val ? g_strdup ((const gchar *) val) : NULL; + case AD_CONNECTOR_OPT_CA_CERT: + g_free (connector->ca_cert); + connector->ca_cert = val && *((const gchar *) val) != '\0' + ? g_strdup ((const gchar *) val) + : NULL; break; case AD_CONNECTOR_OPT_BIND_DN: return set_non_empty_string_value (val, &connector->bind_dn); @@ -427,7 +429,7 @@ ad_connector_connect (ad_connector_t connector, const gchar *password) ret = gvm_ldap_open (&connector->ldap_connection, connector->ldap_host, - connector->ldap_port, connector->cacert_file, tls_mode, + connector->ldap_port, connector->ca_cert, tls_mode, connector->network_timeout, connector->operation_timeout); if (ret != GVM_LDAP_SUCCESS) @@ -1074,7 +1076,7 @@ ad_connector_free (ad_connector_t connector) } g_free (connector->ldap_host); - g_free (connector->cacert_file); + g_free (connector->ca_cert); g_free (connector->bind_dn); g_free (connector); diff --git a/ad_connector/ad_connector.h b/ad_connector/ad_connector.h index 68085f9f..b83c7d8c 100644 --- a/ad_connector/ad_connector.h +++ b/ad_connector/ad_connector.h @@ -23,9 +23,9 @@ typedef enum AD_CONNECTOR_OPT_PORT, /**< LDAP server port, 0 uses the TLS mode default */ AD_CONNECTOR_OPT_TLS_MODE, /**< Instance of ad_connector_tls_mode_t */ - AD_CONNECTOR_OPT_CA_CERT_FILE, /**< Optional CA certificate path */ - AD_CONNECTOR_OPT_BIND_DN, /**< Non-empty bind name/DN for the LDAP connection - */ + AD_CONNECTOR_OPT_CA_CERT, /**< Optional CA certificate in PEM format */ + AD_CONNECTOR_OPT_BIND_DN, /**< Non-empty bind name/DN + for the LDAP connection */ AD_CONNECTOR_OPT_NETWORK_TIMEOUT, /**< Network timeout (seconds), 0 for no explicit timeout/default LDAP behavior*/ diff --git a/ad_connector/ad_connector_tests.c b/ad_connector/ad_connector_tests.c index 708486f9..1ed7e4fb 100644 --- a/ad_connector/ad_connector_tests.c +++ b/ad_connector/ad_connector_tests.c @@ -19,6 +19,7 @@ static gint stub_bind_calls; static gint stub_close_calls; static gchar *stub_last_open_host; +static gchar *stub_last_open_ca_cert; static gint stub_last_open_port; static gvm_ldap_tls_mode_t stub_last_open_tls_mode; static guint stub_last_open_network_timeout; @@ -38,13 +39,14 @@ static GHashTable *stub_entry_attributes; /* -------------------- Mock Functions -------------------- */ gvm_ldap_return_t gvm_ldap_open (gvm_ldap_connection_t **connection, const gchar *host, gint port, - const gchar *cacert_file, gvm_ldap_tls_mode_t tls_mode, + const gchar *ca_cert, gvm_ldap_tls_mode_t tls_mode, guint network_timeout, guint operation_timeout) { - (void) cacert_file; stub_open_calls++; g_free (stub_last_open_host); stub_last_open_host = g_strdup (host); + g_free (stub_last_open_ca_cert); + stub_last_open_ca_cert = g_strdup (ca_cert); stub_last_open_port = port; stub_last_open_tls_mode = tls_mode; stub_last_open_network_timeout = network_timeout; @@ -155,6 +157,8 @@ reset_ldap_stubs (void) g_free (stub_last_open_host); stub_last_open_host = NULL; + g_free (stub_last_open_ca_cert); + stub_last_open_ca_cert = NULL; stub_last_open_port = 0; stub_last_open_tls_mode = GVM_LDAP_TLS_LDAPS; stub_last_open_network_timeout = 0; @@ -361,6 +365,9 @@ AfterEach (ad_connector) g_free (stub_last_open_host); stub_last_open_host = NULL; + g_free (stub_last_open_ca_cert); + stub_last_open_ca_cert = NULL; + g_free (stub_last_bind_dn); stub_last_bind_dn = NULL; @@ -448,23 +455,34 @@ Ensure (ad_connector, builder_validates_non_negative_timeouts) ad_connector_free (connector); } -Ensure (ad_connector, builder_allows_null_ca_cert_file) +Ensure (ad_connector, builder_accepts_ca_cert_and_allows_null_or_empty) { ad_connector_t connector; - const gchar *ca = "/tmp/test-ca.pem"; + const gchar *ca_cert = + "-----BEGIN CERTIFICATE-----\n" + "mock certificate data\n" + "-----END CERTIFICATE-----\n"; connector = ad_connector_new (); assert_that (connector, is_not_null); assert_that ( - ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT_FILE, ca), + ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ca_cert), is_equal_to (AD_CONNECTOR_OK)); - assert_that (connector->cacert_file, is_equal_to_string ("/tmp/test-ca.pem")); + assert_that (connector->ca_cert, is_equal_to_string (ca_cert)); assert_that ( - ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT_FILE, NULL), + ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ""), is_equal_to (AD_CONNECTOR_OK)); - assert_that (connector->cacert_file, is_null); + assert_that (connector->ca_cert, is_null); + + assert_that ( + ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ca_cert), + is_equal_to (AD_CONNECTOR_OK)); + assert_that ( + ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, NULL), + is_equal_to (AD_CONNECTOR_OK)); + assert_that (connector->ca_cert, is_null); ad_connector_free (connector); } @@ -816,11 +834,18 @@ Ensure (ad_connector, connect_succeeds_with_valid_configuration) { ad_connector_t connector = ad_connector_new (); ad_connector_tls_mode_t starttls = AD_CONNECTOR_TLS_STARTTLS; + const gchar *ca_cert = + "-----BEGIN CERTIFICATE-----\n" + "mock certificate data\n" + "-----END CERTIFICATE-----\n"; gint port = 1389; assert_that (connector, is_not_null); set_valid_connection_config (connector); + assert_that ( + ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ca_cert), + is_equal_to (AD_CONNECTOR_OK)); assert_that (ad_connector_builder (connector, AD_CONNECTOR_OPT_PORT, &port), is_equal_to (AD_CONNECTOR_OK)); assert_that ( @@ -835,6 +860,7 @@ Ensure (ad_connector, connect_succeeds_with_valid_configuration) assert_that (connector->ldap_connection, is_equal_to (stub_open_connection)); assert_that (stub_last_open_host, is_equal_to_string ("ad.example.org")); + assert_that (stub_last_open_ca_cert, is_equal_to_string (ca_cert)); assert_that (stub_last_open_port, is_equal_to (1389)); assert_that (stub_last_open_tls_mode, is_equal_to (GVM_LDAP_TLS_STARTTLS)); assert_that (stub_last_open_network_timeout, is_equal_to (12)); @@ -1557,7 +1583,8 @@ main (int argc, char **argv) builder_rejects_empty_host_or_bind_dn); add_test_with_context (suite, ad_connector, builder_validates_non_negative_timeouts); - add_test_with_context (suite, ad_connector, builder_allows_null_ca_cert_file); + add_test_with_context (suite, ad_connector, + builder_accepts_ca_cert_and_allows_null_or_empty); add_test_with_context (suite, ad_connector, builder_rejects_changes_when_connection_exists); From cca8ec4e9425429fc1ad203415ac71852de5f3b0 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Tue, 20 Oct 2026 15:01:12 +0200 Subject: [PATCH 3/3] Add more tests and adjust formatting --- ad_connector/ad_connector.h | 14 +++--- ad_connector/ad_connector_tests.c | 24 ++++------ ldap/gvmldap.c | 28 ++++++------ ldap/gvmldap_tests.c | 76 +++++++++++++++++++++++++++++-- 4 files changed, 104 insertions(+), 38 deletions(-) diff --git a/ad_connector/ad_connector.h b/ad_connector/ad_connector.h index b83c7d8c..86e7e81a 100644 --- a/ad_connector/ad_connector.h +++ b/ad_connector/ad_connector.h @@ -19,13 +19,13 @@ */ typedef enum { - AD_CONNECTOR_OPT_HOST, /**< non-empty host/IP without port */ - AD_CONNECTOR_OPT_PORT, /**< LDAP server port, 0 uses the - TLS mode default */ - AD_CONNECTOR_OPT_TLS_MODE, /**< Instance of ad_connector_tls_mode_t */ - AD_CONNECTOR_OPT_CA_CERT, /**< Optional CA certificate in PEM format */ - AD_CONNECTOR_OPT_BIND_DN, /**< Non-empty bind name/DN - for the LDAP connection */ + AD_CONNECTOR_OPT_HOST, /**< non-empty host/IP without port */ + AD_CONNECTOR_OPT_PORT, /**< LDAP server port, 0 uses the + TLS mode default */ + AD_CONNECTOR_OPT_TLS_MODE, /**< Instance of ad_connector_tls_mode_t */ + AD_CONNECTOR_OPT_CA_CERT, /**< Optional CA certificate in PEM format */ + AD_CONNECTOR_OPT_BIND_DN, /**< Non-empty bind name/DN + for the LDAP connection */ AD_CONNECTOR_OPT_NETWORK_TIMEOUT, /**< Network timeout (seconds), 0 for no explicit timeout/default LDAP behavior*/ diff --git a/ad_connector/ad_connector_tests.c b/ad_connector/ad_connector_tests.c index 1ed7e4fb..391314cf 100644 --- a/ad_connector/ad_connector_tests.c +++ b/ad_connector/ad_connector_tests.c @@ -458,10 +458,9 @@ Ensure (ad_connector, builder_validates_non_negative_timeouts) Ensure (ad_connector, builder_accepts_ca_cert_and_allows_null_or_empty) { ad_connector_t connector; - const gchar *ca_cert = - "-----BEGIN CERTIFICATE-----\n" - "mock certificate data\n" - "-----END CERTIFICATE-----\n"; + const gchar *ca_cert = "-----BEGIN CERTIFICATE-----\n" + "mock certificate data\n" + "-----END CERTIFICATE-----\n"; connector = ad_connector_new (); assert_that (connector, is_not_null); @@ -471,17 +470,15 @@ Ensure (ad_connector, builder_accepts_ca_cert_and_allows_null_or_empty) is_equal_to (AD_CONNECTOR_OK)); assert_that (connector->ca_cert, is_equal_to_string (ca_cert)); - assert_that ( - ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ""), - is_equal_to (AD_CONNECTOR_OK)); + assert_that (ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ""), + is_equal_to (AD_CONNECTOR_OK)); assert_that (connector->ca_cert, is_null); assert_that ( ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, ca_cert), is_equal_to (AD_CONNECTOR_OK)); - assert_that ( - ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, NULL), - is_equal_to (AD_CONNECTOR_OK)); + assert_that (ad_connector_builder (connector, AD_CONNECTOR_OPT_CA_CERT, NULL), + is_equal_to (AD_CONNECTOR_OK)); assert_that (connector->ca_cert, is_null); ad_connector_free (connector); @@ -834,10 +831,9 @@ Ensure (ad_connector, connect_succeeds_with_valid_configuration) { ad_connector_t connector = ad_connector_new (); ad_connector_tls_mode_t starttls = AD_CONNECTOR_TLS_STARTTLS; - const gchar *ca_cert = - "-----BEGIN CERTIFICATE-----\n" - "mock certificate data\n" - "-----END CERTIFICATE-----\n"; + const gchar *ca_cert = "-----BEGIN CERTIFICATE-----\n" + "mock certificate data\n" + "-----END CERTIFICATE-----\n"; gint port = 1389; assert_that (connector, is_not_null); diff --git a/ldap/gvmldap.c b/ldap/gvmldap.c index 8d4fb2f5..cdbb97f5 100644 --- a/ldap/gvmldap.c +++ b/ldap/gvmldap.c @@ -19,12 +19,12 @@ #include "gvmldap.h" +#include +#include #include #include -#include #include #include -#include #define LDAP_DEFAULT_PORT 389 #define LDAPS_DEFAULT_PORT 636 @@ -136,8 +136,7 @@ ldap_write_ca_cert_tmp (const gchar *ca_cert) fd = g_file_open_tmp ("gvmldap-ca-XXXXXX", &path, &error); if (fd < 0) { - g_warning ("Could not create temporary LDAP CA file: %s", - error->message); + g_warning ("Could not create temporary LDAP CA file: %s", error->message); g_clear_error (&error); return NULL; } @@ -161,7 +160,8 @@ ldap_write_ca_cert_tmp (const gchar *ca_cert) if (written <= 0) { g_warning ("Could not write temporary LDAP CA file: %s", - written < 0 ? g_strerror (errno) : "write made no progress"); + written < 0 ? g_strerror (errno) + : "write made no progress"); goto fail; } @@ -229,16 +229,16 @@ ldap_configure_tls (LDAP *ldap, const gchar *ca_cert) == LDAP_OPT_SUCCESS) ret = 0; - cleanup: - if (ca_path != NULL) - { - if (g_unlink (ca_path) != 0) - g_warning ("Could not remove temporary LDAP CA file: %s", - g_strerror (errno)); - g_free (ca_path); - } +cleanup: + if (ca_path != NULL) + { + if (g_unlink (ca_path) != 0) + g_warning ("Could not remove temporary LDAP CA file: %s", + g_strerror (errno)); + g_free (ca_path); + } - return ret; + return ret; } /** diff --git a/ldap/gvmldap_tests.c b/ldap/gvmldap_tests.c index 93fbb38f..5d81f0a0 100644 --- a/ldap/gvmldap_tests.c +++ b/ldap/gvmldap_tests.c @@ -15,6 +15,7 @@ static struct berval **mock_values_to_return = NULL; static int mock_ldap_str2dn_return_value = 0; static int mock_ldap_set_option_return_value = LDAP_OPT_SUCCESS; +static int mock_ldap_set_option_failure_option = 0; static int ldap_set_option_call_count = 0; static int last_ldap_set_option_option = 0; @@ -131,10 +132,13 @@ ldap_set_option (LDAP *ld, int option, const void *invalue) if (option == LDAP_OPT_X_TLS_CACERTFILE && invalue != NULL) { last_ca_cert_path = g_strdup ((const gchar *) invalue); - g_file_get_contents (last_ca_cert_path, - &ca_cert_contents_at_set_option, NULL, NULL); + g_file_get_contents (last_ca_cert_path, &ca_cert_contents_at_set_option, + NULL, NULL); } + if (option == mock_ldap_set_option_failure_option) + return LDAP_OPT_ERROR; + return mock_ldap_set_option_return_value; } @@ -172,6 +176,7 @@ BeforeEach (gvmldap) mock_ldap_str2dn_return_value = 0; mock_ldap_set_option_return_value = LDAP_OPT_SUCCESS; + mock_ldap_set_option_failure_option = 0; ldap_set_option_call_count = 0; last_ldap_set_option_option = 0; @@ -189,6 +194,7 @@ AfterEach (gvmldap) mock_dn_to_return = NULL; mock_ldap_str2dn_return_value = 0; mock_ldap_set_option_return_value = LDAP_OPT_SUCCESS; + mock_ldap_set_option_failure_option = 0; ldap_set_option_call_count = 0; last_ldap_set_option_option = 0; @@ -679,11 +685,49 @@ Ensure (gvmldap, ldap_configure_tls_sets_tls_options_correctly_with_cert) assert_that (g_file_test (last_ca_cert_path, G_FILE_TEST_EXISTS), is_false); } +Ensure (gvmldap, ldap_configure_tls_removes_cert_file_when_cacertfile_fails) +{ + LDAP *ldap = (LDAP *) 0x1; + const gchar *cert = "mock CA certificate\n"; + int ret; + + mock_ldap_set_option_failure_option = LDAP_OPT_X_TLS_CACERTFILE; + + ret = ldap_configure_tls (ldap, cert); + + assert_that (ret, is_equal_to (-1)); + assert_that (ldap_set_option_call_count, is_equal_to (2)); + assert_that (last_ldap_set_option_option, + is_equal_to (LDAP_OPT_X_TLS_CACERTFILE)); + assert_that (last_ca_cert_path, is_not_null); + assert_that (ca_cert_contents_at_set_option, is_equal_to_string (cert)); + assert_that (g_file_test (last_ca_cert_path, G_FILE_TEST_EXISTS), is_false); +} + +Ensure (gvmldap, ldap_configure_tls_removes_cert_file_when_newctx_fails) +{ + LDAP *ldap = (LDAP *) 0x1; + const gchar *cert = "mock CA certificate\n"; + int ret; + + mock_ldap_set_option_failure_option = LDAP_OPT_X_TLS_NEWCTX; + + ret = ldap_configure_tls (ldap, cert); + + assert_that (ret, is_equal_to (-1)); + assert_that (ldap_set_option_call_count, is_equal_to (3)); + assert_that (last_ldap_set_option_option, + is_equal_to (LDAP_OPT_X_TLS_NEWCTX)); + assert_that (last_ca_cert_path, is_not_null); + assert_that (ca_cert_contents_at_set_option, is_equal_to_string (cert)); + assert_that (g_file_test (last_ca_cert_path, G_FILE_TEST_EXISTS), is_false); +} + Ensure (gvmldap, ldap_configure_tls_handles_returns_error_for_invalid_input) { int ret; - ret = ldap_configure_tls (NULL, "/path/to/cert"); + ret = ldap_configure_tls (NULL, "mock CA certificate"); assert_that (ldap_set_option_call_count, is_equal_to (0)); assert_that (ret, is_equal_to (-1)); @@ -759,6 +803,26 @@ Ensure (gvmldap, gvm_ldap_open_returns_connection_on_success) gvm_ldap_close (connection); } +Ensure (gvmldap, gvm_ldap_open_passes_ca_cert_data_to_tls_configuration) +{ + gvm_ldap_connection_t *connection = NULL; + const gchar *cert = "-----BEGIN CERTIFICATE-----\n" + "mock certificate data\n" + "-----END CERTIFICATE-----\n"; + gvm_ldap_return_t ret; + + ret = gvm_ldap_open (&connection, "ldap.example.org", 0, cert, + GVM_LDAP_TLS_LDAPS, 0, 0); + + assert_that (ret, is_equal_to (GVM_LDAP_SUCCESS)); + assert_that (connection, is_not_null); + assert_that (last_ca_cert_path, is_not_null); + assert_that (ca_cert_contents_at_set_option, is_equal_to_string (cert)); + assert_that (g_file_test (last_ca_cert_path, G_FILE_TEST_EXISTS), is_false); + + gvm_ldap_close (connection); +} + /* gvm_ldap_close */ Ensure (gvmldap, gvm_ldap_close_unbinds_connection) { @@ -860,6 +924,10 @@ main (int argc, char **argv) ldap_configure_tls_sets_tls_options_correctly_no_cert); add_test_with_context ( suite, gvmldap, ldap_configure_tls_sets_tls_options_correctly_with_cert); + add_test_with_context ( + suite, gvmldap, ldap_configure_tls_removes_cert_file_when_cacertfile_fails); + add_test_with_context ( + suite, gvmldap, ldap_configure_tls_removes_cert_file_when_newctx_fails); add_test_with_context ( suite, gvmldap, ldap_configure_tls_handles_returns_error_for_invalid_input); @@ -874,6 +942,8 @@ main (int argc, char **argv) gvm_ldap_open_returns_error_when_initialize_fails); add_test_with_context (suite, gvmldap, gvm_ldap_open_returns_connection_on_success); + add_test_with_context ( + suite, gvmldap, gvm_ldap_open_passes_ca_cert_data_to_tls_configuration); add_test_with_context (suite, gvmldap, gvm_ldap_close_unbinds_connection); add_test_with_context (suite, gvmldap,