void *extension_library_open(const char *name) { if (!enable_extension_libraries) { return NULL; } if (getenv("CFENGINE_TEST_OVERRIDE_EXTENSION_LIBRARY_DO_CLOSE") == NULL) { // Only do loading checks if we are not doing tests. attempted_loading = true; } const char *dir = getenv("CFENGINE_TEST_OVERRIDE_EXTENSION_LIBRARY_DIR"); char lib[] = "/lib"; if (dir) { lib[0] = '\0'; } else { dir = GetWorkDir(); } char path[strlen(dir) + strlen(lib) + strlen(name) + 2]; sprintf(path, "%s%s/%s", dir, lib, name); void *handle = shlib_open(path); if (!handle) { return handle; } // Version check, to avoid binary incompatible plugins. const char * (*GetExtensionLibraryVersion)() = shlib_load(handle, "GetExtensionLibraryVersion"); if (!GetExtensionLibraryVersion) { Log(LOG_LEVEL_ERR, "Could not retreive version from extension plugin (%s). Not loading the plugin.", name); goto close_and_fail; } const char *plugin_version = GetExtensionLibraryVersion(); unsigned int bin_major, bin_minor, bin_patch; unsigned int plug_major, plug_minor, plug_patch; if (sscanf(VERSION, "%u.%u.%u", &bin_major, &bin_minor, &bin_patch) != 3) { Log(LOG_LEVEL_ERR, "Not able to extract version number from binary (%s). Not loading extension plugin.", name); goto close_and_fail; } if (sscanf(plugin_version, "%u.%u.%u", &plug_major, &plug_minor, &plug_patch) != 3) { Log(LOG_LEVEL_ERR, "Not able to extract version number from plugin (%s). Not loading extension plugin.", name); goto close_and_fail; } if (bin_major != plug_major || bin_minor != plug_minor || bin_patch != plug_patch) { Log(LOG_LEVEL_ERR, "Extension plugin version does not match CFEngine Community version " "(CFEngine Community v%u.%u.%u, Extension (%s) v%u.%u.%u). Refusing to load it.", bin_major, bin_minor, bin_patch, name, plug_major, plug_minor, plug_patch); goto close_and_fail; } return handle; close_and_fail: shlib_close(handle); return NULL; }
void *extension_library_open(const char *name) { if (!enable_extension_libraries) { return NULL; } if (getenv("CFENGINE_TEST_OVERRIDE_EXTENSION_LIBRARY_DO_CLOSE") == NULL) { // Only do loading checks if we are not doing tests. attempted_loading = true; } const char *dirs_to_try[3] = { NULL }; const char *dir = getenv("CFENGINE_TEST_OVERRIDE_EXTENSION_LIBRARY_DIR"); char lib[] = "/lib"; if (dir) { lib[0] = '\0'; dirs_to_try[0] = dir; } else { dirs_to_try[0] = GetWorkDir(); if (strcmp(WORKDIR, dirs_to_try[0]) != 0) { // try to load from the real WORKDIR in case GetWorkDir returned the local workdir to the user // We try this because enterprise "make install" is in WORKDIR, not per user dirs_to_try[1] = WORKDIR; } } void *handle = NULL; for (int i = 0; dirs_to_try[i]; i++) { char path[strlen(dirs_to_try[i]) + strlen(lib) + strlen(name) + 2]; xsnprintf(path, sizeof(path), "%s%s/%s", dirs_to_try[i], lib, name); Log(LOG_LEVEL_DEBUG, "Trying to shlib_open extension plugin '%s' from '%s'", name, path); handle = shlib_open(path); if (handle) { Log(LOG_LEVEL_VERBOSE, "Successfully opened extension plugin '%s' from '%s'", name, path); break; } else { const char *error; if (errno == ENOENT) { error = "(not installed)"; } else { error = GetErrorStr(); } Log(LOG_LEVEL_VERBOSE, "Could not open extension plugin '%s' from '%s': %s", name, path, error); } } if (!handle) { return handle; } // Version check, to avoid binary incompatible plugins. const char * (*GetExtensionLibraryVersion)() = shlib_load(handle, "GetExtensionLibraryVersion"); if (!GetExtensionLibraryVersion) { Log(LOG_LEVEL_ERR, "Could not retrieve version from extension plugin (%s). Not loading the plugin.", name); goto close_and_fail; } const char *plugin_version = GetExtensionLibraryVersion(); unsigned int bin_major, bin_minor, bin_patch; unsigned int plug_major, plug_minor, plug_patch; if (sscanf(VERSION, "%u.%u.%u", &bin_major, &bin_minor, &bin_patch) != 3) { Log(LOG_LEVEL_ERR, "Not able to extract version number from binary (%s). Not loading extension plugin.", name); goto close_and_fail; } if (sscanf(plugin_version, "%u.%u.%u", &plug_major, &plug_minor, &plug_patch) != 3) { Log(LOG_LEVEL_ERR, "Not able to extract version number from plugin (%s). Not loading extension plugin.", name); goto close_and_fail; } if (bin_major != plug_major || bin_minor != plug_minor || bin_patch != plug_patch) { Log(LOG_LEVEL_ERR, "Extension plugin version does not match CFEngine Community version " "(CFEngine Community v%u.%u.%u, Extension (%s) v%u.%u.%u). Refusing to load it.", bin_major, bin_minor, bin_patch, name, plug_major, plug_minor, plug_patch); goto close_and_fail; } Log(LOG_LEVEL_VERBOSE, "Successfully loaded extension plugin '%s'", name); return handle; close_and_fail: shlib_close(handle); return NULL; }
void extension_library_close(void *handle) { shlib_close(handle); }
static int test_lib(void) { SHLIB ssllib = SHLIB_INIT; SHLIB cryptolib = SHLIB_INIT; SSL_CTX *ctx; union { void (*func)(void); SHLIB_SYM sym; } symbols[3]; TLS_method_t myTLS_method; SSL_CTX_new_t mySSL_CTX_new; SSL_CTX_free_t mySSL_CTX_free; ERR_get_error_t myERR_get_error; OpenSSL_version_num_t myOpenSSL_version_num; int result = 0; switch (test_type) { case JUST_CRYPTO: if (!TEST_true(shlib_load(path_crypto, &cryptolib))) goto end; break; case CRYPTO_FIRST: if (!TEST_true(shlib_load(path_crypto, &cryptolib)) || !TEST_true(shlib_load(path_ssl, &ssllib))) goto end; break; case SSL_FIRST: if (!TEST_true(shlib_load(path_ssl, &ssllib)) || !TEST_true(shlib_load(path_crypto, &cryptolib))) goto end; break; } if (test_type != JUST_CRYPTO) { if (!TEST_true(shlib_sym(ssllib, "TLS_method", &symbols[0].sym)) || !TEST_true(shlib_sym(ssllib, "SSL_CTX_new", &symbols[1].sym)) || !TEST_true(shlib_sym(ssllib, "SSL_CTX_free", &symbols[2].sym))) goto end; myTLS_method = (TLS_method_t)symbols[0].func; mySSL_CTX_new = (SSL_CTX_new_t)symbols[1].func; mySSL_CTX_free = (SSL_CTX_free_t)symbols[2].func; if (!TEST_ptr(ctx = mySSL_CTX_new(myTLS_method()))) goto end; mySSL_CTX_free(ctx); } if (!TEST_true(shlib_sym(cryptolib, "ERR_get_error", &symbols[0].sym)) || !TEST_true(shlib_sym(cryptolib, "OpenSSL_version_num", &symbols[1].sym))) goto end; myERR_get_error = (ERR_get_error_t)symbols[0].func; if (!TEST_int_eq(myERR_get_error(), 0)) goto end; myOpenSSL_version_num = (OpenSSL_version_num_t)symbols[1].func; if (!TEST_int_eq(myOpenSSL_version_num(), OPENSSL_VERSION_NUMBER)) goto end; #ifdef OPENSSL_USE_NODELETE switch (test_type) { case JUST_CRYPTO: if (!TEST_true(shlib_close(cryptolib))) goto end; break; case CRYPTO_FIRST: if (!TEST_true(shlib_close(cryptolib)) || !TEST_true(shlib_close(ssllib))) goto end; break; case SSL_FIRST: if (!TEST_true(shlib_close(ssllib)) || !TEST_true(shlib_close(cryptolib))) goto end; break; } #endif result = 1; end: return result; }