From 8b9fa14786c07b99471e2f0829b854c2a49afc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kemp=20Mu=C3=B1oz?= <marcel.kemp@wazuh.com> Date: Tue, 26 Nov 2024 16:43:24 +0100 Subject: [PATCH 1/2] feat: backport WMI and WUA API integration Merge pull request #26706 from wazuh/enhancement/25766-develop-integration-with-wmi-api-to-retrieve-installed-windows-updates Develop Integration with WMI and WUA APIs to Retrieve Installed Windows Updates --- src/common/data_provider/CMakeLists.txt | 2 +- src/common/data_provider/src/sysInfoWin.cpp | 37 +++ .../data_provider/src/utilsWrapperWin.cpp | 255 ++++++++++++++++++ .../data_provider/src/utilsWrapperWin.hpp | 79 ++++++ .../tests/sysInfoWin/CMakeLists.txt | 12 +- .../tests/sysInfoWin/sysInfoWin_test.cpp | 178 +++++++++++- .../tests/sysInfoWin/sysInfoWin_test.h | 20 ++ 7 files changed, 576 insertions(+), 7 deletions(-) create mode 100644 src/common/data_provider/src/utilsWrapperWin.cpp create mode 100644 src/common/data_provider/src/utilsWrapperWin.hpp diff --git a/src/common/data_provider/CMakeLists.txt b/src/common/data_provider/CMakeLists.txt index e685481eeac..842b5c92aaa 100644 --- a/src/common/data_provider/CMakeLists.txt +++ b/src/common/data_provider/CMakeLists.txt @@ -168,7 +168,7 @@ add_library(sysinfo STATIC target_include_directories(sysinfo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries(sysinfo PUBLIC psapi iphlpapi ws2_32) + target_link_libraries(sysinfo PUBLIC psapi iphlpapi ws2_32 wbemuuid uuid wuguid ole32 oleaut32) elseif(APPLE) find_library(iokit_lib IOKit) if(NOT iokit_lib) diff --git a/src/common/data_provider/src/sysInfoWin.cpp b/src/common/data_provider/src/sysInfoWin.cpp index cda3e8a9cb3..1ed90b90b5d 100644 --- a/src/common/data_provider/src/sysInfoWin.cpp +++ b/src/common/data_provider/src/sysInfoWin.cpp @@ -41,12 +41,15 @@ #include "packages/packagesPYPI.hpp" #include "packages/packagesNPM.hpp" #include "packages/modernPackageDataRetriever.hpp" +#include "utilsWrapperWin.hpp" + constexpr auto CENTRAL_PROCESSOR_REGISTRY {"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"}; const std::string UNINSTALL_REGISTRY{"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"}; constexpr auto SYSTEM_IDLE_PROCESS_NAME {"System Idle Process"}; constexpr auto SYSTEM_PROCESS_NAME {"System"}; + static const std::map<std::string, DWORD> gs_firmwareTableProviderSignature { {"ACPI", 0x41435049}, @@ -912,9 +915,43 @@ void SysInfo::getPackages(std::function<void(nlohmann::json&)> callback) const ModernFactoryPackagesCreator<HAS_STDFILESYSTEM>::getPackages(searchPaths, callback); } + nlohmann::json SysInfo::getHotfixes() const { std::set<std::string> hotfixes; + std::ostringstream oss; + ComHelper comHelper; + + // Initialize COM + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + + if (SUCCEEDED(hres)) + { + try + { + // Query hotfixes using WMI + QueryWMIHotFixes(hotfixes, comHelper); + } + catch (...) + { + // Ignore the error. The OS does not support WMI API. + } + + + try + { + // Query hotfixes using Windows Update API + QueryWUHotFixes(hotfixes, comHelper); + } + catch (...) + { + // Ignore the error. The OS does not support WUA API. + } + + // Uninitialize COM + CoUninitialize(); + } + PackageWindowsHelper::getHotFixFromReg(HKEY_LOCAL_MACHINE, PackageWindowsHelper::WIN_REG_HOTFIX, hotfixes); PackageWindowsHelper::getHotFixFromRegNT(HKEY_LOCAL_MACHINE, PackageWindowsHelper::VISTA_REG_HOTFIX, hotfixes); PackageWindowsHelper::getHotFixFromRegWOW(HKEY_LOCAL_MACHINE, PackageWindowsHelper::WIN_REG_WOW_HOTFIX, hotfixes); diff --git a/src/common/data_provider/src/utilsWrapperWin.cpp b/src/common/data_provider/src/utilsWrapperWin.cpp new file mode 100644 index 00000000000..ab7781238e0 --- /dev/null +++ b/src/common/data_provider/src/utilsWrapperWin.cpp @@ -0,0 +1,255 @@ +/* + * Wazuh SysInfo + * Copyright (C) 2015, Wazuh Inc. + * December 22, 2021. + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License (version 2) as published by the FSF - Free Software + * Foundation + */ + +#include <regex> +#include <sstream> // For std::ostringstream +#include <iomanip> // For std::hex +#include <stdexcept> // For std::runtime_error +#include <string> // For std::string and std::wstring +#include <locale> // For localization utilities (if needed for string conversion) + +#define WMI_WUA_DLL +#include "utilsWrapperWin.hpp" + + +// Implement WMI functions +HRESULT ComHelper::CreateWmiLocator(IWbemLocator*& pLoc) +{ + return CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc); +} + +HRESULT ComHelper::ConnectToWmiServer(IWbemLocator* pLoc, IWbemServices*& pSvc) +{ + return pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, 0, 0, 0, &pSvc); +} + +HRESULT ComHelper::SetProxyBlanket(IWbemServices* pSvc) +{ + return CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); +} + +HRESULT ComHelper::ExecuteWmiQuery(IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator) +{ + return pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_QuickFixEngineering"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); +} + +// Implement Windows Update API functions +HRESULT ComHelper::CreateUpdateSearcher(IUpdateSearcher*& pUpdateSearcher) +{ + return CoCreateInstance(CLSID_UpdateSearcher, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSearcher, (LPVOID*)&pUpdateSearcher); +} + +HRESULT ComHelper::GetTotalHistoryCount(IUpdateSearcher* pUpdateSearcher, LONG& count) +{ + return pUpdateSearcher->GetTotalHistoryCount(&count); +} + +HRESULT ComHelper::QueryHistory(IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count) +{ + return pUpdateSearcher->QueryHistory(0, count, &pHistory); +} + +HRESULT ComHelper::GetCount(IUpdateHistoryEntryCollection* pHistory, LONG& count) +{ + return pHistory->get_Count(&count); +} + +HRESULT ComHelper::GetItem(IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry) +{ + return pHistory->get_Item(index, pEntry); +} + +HRESULT ComHelper::GetTitle(IUpdateHistoryEntry* pEntry, BSTR& title) +{ + return pEntry->get_Title(&title); +} + +// This function provides a minimal implementation for converting C strings to BSTRs, +// avoiding the need to include a full COM library. This can be useful when you only need this specific functionality +// and want to minimize dependencies. +namespace _com_util +{ + BSTR ConvertStringToBSTR(const char* str) + { + int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + BSTR bstr = SysAllocStringLen(0, len); + MultiByteToWideChar(CP_ACP, 0, str, -1, bstr, len); + return bstr; + } +} + +// The BstrToString function takes a Windows-specific string (BSTR) and converts it into +// a standard C++ string (std::string) that can be more easily used in the application. +std::string BstrToString(BSTR bstr) +{ + std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; + std::wstring wstr(bstr, SysStringLen(bstr)); + return converter.to_bytes(wstr); +} + +void QueryWMIHotFixes(std::set<std::string>& hotfixSet, IComHelper& comHelper) +{ + HRESULT hres; + IWbemLocator* pLoc = NULL; + IWbemServices* pSvc = NULL; + std::ostringstream oss; + + hres = comHelper.CreateWmiLocator(pLoc); + + if (FAILED(hres)) + { + oss << "WMI: Error creating IWbemLocator. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + hres = comHelper.ConnectToWmiServer(pLoc, pSvc); + + if (FAILED(hres)) + { + if (pLoc) pLoc->Release(); + + oss << "WMI: connection failed. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + hres = comHelper.SetProxyBlanket(pSvc); + + if (FAILED(hres)) + { + if (pSvc) pSvc->Release(); + + if (pLoc) pLoc->Release(); + + oss << "WMI: security error. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + IEnumWbemClassObject* pEnumerator = NULL; + hres = comHelper.ExecuteWmiQuery(pSvc, pEnumerator); + + if (FAILED(hres)) + { + if (pLoc) pLoc->Release(); + + if (pLoc) pSvc->Release(); + + oss << "WMI: query error. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + IWbemClassObject* pclsObj = NULL; + ULONG uReturn = 0; + + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + hr = pclsObj->Get(L"HotFixID", 0, &vtProp, 0, 0); + + if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) + { + std::string hotfix = BstrToString(vtProp.bstrVal); + + if (hotfixSet.find(hotfix) == hotfixSet.end()) + { + // New HotFix found + hotfixSet.insert(hotfix); + } + } + + VariantClear(&vtProp); + pclsObj->Release(); + } + + pSvc->Release(); + pLoc->Release(); + pEnumerator->Release(); +} + +void QueryWUHotFixes(std::set<std::string>& hotfixSet, IComHelper& comHelper) +{ + HRESULT hres; + IUpdateSearcher* pUpdateSearcher = NULL; + IUpdateHistoryEntryCollection* pHistory = NULL; + std::regex hotfixRegex("KB[0-9]+"); + std::ostringstream oss; + + hres = comHelper.CreateUpdateSearcher(pUpdateSearcher); + + if (FAILED(hres)) + { + oss << "WUA: UpdateSearcher error. Code: " << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + LONG count; + hres = comHelper.GetTotalHistoryCount(pUpdateSearcher, count); + + if (FAILED(hres)) + { + if (pUpdateSearcher) pUpdateSearcher->Release(); + + oss << "WUA: Error getting total update history count. Code: 0x" << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + hres = comHelper.QueryHistory(pUpdateSearcher, pHistory, count); + + if (FAILED(hres)) + { + if (pUpdateSearcher) pUpdateSearcher->Release(); + + oss << "WUA: Error querying update history. Code: 0x" << std::hex << hres; + throw std::runtime_error(oss.str()); + } + + LONG historyCount; + hres = comHelper.GetCount(pHistory, historyCount); + + for (LONG i = 0; i < historyCount; ++i) + { + IUpdateHistoryEntry* pEntry = NULL; + comHelper.GetItem(pHistory, i, &pEntry); + BSTR title; + comHelper.GetTitle(pEntry, title); + std::string titleStr = BstrToString(title); + + std::smatch match; + + if (std::regex_search(titleStr, match, hotfixRegex)) + { + std::string hotfix = match[0]; + + if (hotfixSet.find(hotfix) == hotfixSet.end()) + { + // New HotFix found + hotfixSet.insert(hotfix); + } + } + + if (pEntry) pEntry->Release(); + + SysFreeString(title); + } + + if (pHistory) pHistory->Release(); + + if (pUpdateSearcher) pUpdateSearcher->Release(); +} + diff --git a/src/common/data_provider/src/utilsWrapperWin.hpp b/src/common/data_provider/src/utilsWrapperWin.hpp new file mode 100644 index 00000000000..6422302eb70 --- /dev/null +++ b/src/common/data_provider/src/utilsWrapperWin.hpp @@ -0,0 +1,79 @@ +/* + * Wazuh SysInfo + * Copyright (C) 2015, Wazuh Inc. + * December 22, 2021. + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License (version 2) as published by the FSF - Free Software + * Foundation + */ +#pragma once + +#ifdef WMI_WUA_DLL +#ifdef WIN_EXPORT +#define EXPORTED __declspec(dllexport) +#else +#define EXPORTED __declspec(dllimport) +#endif +#endif + +/* Hotfixes APIs */ +#include <set> +#include <wbemidl.h> +#include <wbemcli.h> +#include <stdio.h> +#include <comdef.h> +#include <codecvt> +#include "wuapi.h" + + +// Define GUID manually for CLSID_UpdateSearcher +DEFINE_GUID(CLSID_UpdateSearcher, 0x5A2A5E6E, 0xD633, 0x4C3A, 0x8A, 0x7E, 0x69, 0x4D, 0xBF, 0x9E, 0xCE, 0xD4); + +class EXPORTED IComHelper +{ + public: + virtual ~IComHelper() = default; + + // Abstracted methods for WMI functions + virtual HRESULT CreateWmiLocator(IWbemLocator*& pLoc) = 0; + virtual HRESULT ConnectToWmiServer(IWbemLocator* pLoc, IWbemServices*& pSvc) = 0; + virtual HRESULT SetProxyBlanket(IWbemServices* pSvc) = 0; + virtual HRESULT ExecuteWmiQuery(IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator) = 0; + + // Abstracted methods for Windows Update API functions + virtual HRESULT CreateUpdateSearcher(IUpdateSearcher*& pUpdateSearcher) = 0; + virtual HRESULT GetTotalHistoryCount(IUpdateSearcher* pUpdateSearcher, LONG& count) = 0; + virtual HRESULT QueryHistory(IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count) = 0; + virtual HRESULT GetCount(IUpdateHistoryEntryCollection* pHistory, LONG& count) = 0; + virtual HRESULT GetItem(IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry) = 0; + virtual HRESULT GetTitle(IUpdateHistoryEntry* pEntry, BSTR& title) = 0; +}; + +class EXPORTED ComHelper : public IComHelper +{ + public: + // Implement WMI functions + HRESULT CreateWmiLocator(IWbemLocator*& pLoc) override; + HRESULT ConnectToWmiServer(IWbemLocator* pLoc, IWbemServices*& pSvc) override; + HRESULT SetProxyBlanket(IWbemServices* pSvc) override; + HRESULT ExecuteWmiQuery(IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator) override; + + // Implement Windows Update API functions + HRESULT CreateUpdateSearcher(IUpdateSearcher*& pUpdateSearcher) override; + HRESULT GetTotalHistoryCount(IUpdateSearcher* pUpdateSearcher, LONG& count) override; + HRESULT QueryHistory(IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count) override; + HRESULT GetCount(IUpdateHistoryEntryCollection* pHistory, LONG& count) override; + HRESULT GetItem(IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry) override; + HRESULT GetTitle(IUpdateHistoryEntry* pEntry, BSTR& title) override; +}; + +// Queries Windows Management Instrumentation (WMI) to retrieve installed hotfixes +// and stores them in the provided set. +EXPORTED void QueryWMIHotFixes(std::set<std::string>& hotfixSet, IComHelper& comHelper); + + +// Queries Windows Update Agent (WUA) for installed update history, +// extracts hotfixes, and adds them to the provided set. +EXPORTED void QueryWUHotFixes(std::set<std::string>& hotfixSet, IComHelper& comHelper); diff --git a/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt b/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt index ba331b2a473..7f96227b52d 100644 --- a/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt +++ b/src/common/data_provider/tests/sysInfoWin/CMakeLists.txt @@ -7,10 +7,18 @@ set(CMAKE_CXX_FLAGS_DEBUG "-g --coverage") file(GLOB sysinfo_UNIT_TEST_SRC "*.cpp") - add_executable(sysInfoWindows_unit_test - ${sysinfo_UNIT_TEST_SRC}) +file(GLOB SYSINFO_SRC + "${CMAKE_SOURCE_DIR}/src/utilsWrapperWin.cpp") + +add_executable(sysInfoWindows_unit_test + ${sysinfo_UNIT_TEST_SRC} + ${SYSINFO_SRC}) + +link_directories("${CMAKE_SOURCE_DIR}/lib/") target_link_libraries(sysInfoWindows_unit_test + wbemuuid + wuguid debug gtestd debug gmockd debug gtest_maind diff --git a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp index 8cf5d58dc2f..e7e59a9991b 100644 --- a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp +++ b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.cpp @@ -9,13 +9,16 @@ * Foundation. */ -#include "sysInfoWin_test.h" + +#include <set> +#include <stdio.h> #include "packages/packagesWindowsParserHelper.h" +#include "sysInfoWin_test.h" +#include <iostream> -void SysInfoWinTest::SetUp() {}; -void SysInfoWinTest::TearDown() -{}; +void SysInfoWinTest::SetUp() {}; +void SysInfoWinTest::TearDown() {}; TEST_F(SysInfoWinTest, test_extract_HFValue_7618) { @@ -102,3 +105,170 @@ TEST_F(SysInfoWinTest, testHF_PRODUCT_Valids_Format) EXPECT_FALSE(std::regex_match(hf, std::regex(KB_WITH_NUMBERS_AND_LETTERS_FORMAT_REGEX))); } } + +// Test: Windows Management Instrumentation (WMI) to retrieve installed hotfixes +TEST_F(SysInfoWinTest, WmiLocatorCreationFailure) +{ + MockComHelper mockHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockHelper, CreateWmiLocator(::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiConnectToWmiServerFailure) +{ + MockComHelper mockComHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockComHelper, CreateWmiLocator(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ConnectToWmiServer(testing::_, testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockComHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiSetProxyBlanket) +{ + MockComHelper mockComHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockComHelper, CreateWmiLocator(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ConnectToWmiServer(testing::_, testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, SetProxyBlanket(testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockComHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiExecuteQuery) +{ + MockComHelper mockComHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockComHelper, CreateWmiLocator(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ConnectToWmiServer(testing::_, testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, SetProxyBlanket(testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockComHelper, ExecuteWmiQuery(testing::_, testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWMIHotFixes(hotfixSet, mockComHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WmiPopulatesWMIHotfixSetCorrectly) +{ + std::set<std::string> hotfixSet; + ComHelper comHelper; + + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + EXPECT_TRUE(SUCCEEDED(hres)) << "COM Initialization failed with HRESULT: " << std::hex << hres; + + QueryWMIHotFixes(hotfixSet, comHelper); + + constexpr auto KB_NO_NUMBERS_FORMAT_REGEX { "(KB+[a-z])"}; + constexpr auto KB_WITH_NUMBERS_AND_LETTERS_FORMAT_REGEX { "(KB+[0-9]{6,}+[aA-zZ])"}; + + for (const auto& hf : hotfixSet) + { + EXPECT_FALSE(std::regex_match(hf, std::regex(KB_NO_NUMBERS_FORMAT_REGEX))); + EXPECT_FALSE(std::regex_match(hf, std::regex(KB_WITH_NUMBERS_AND_LETTERS_FORMAT_REGEX))); + } + + CoUninitialize(); +} + +// Test: Windows Update Agent (WUA) for installed update history, +TEST_F(SysInfoWinTest, WuaLocatorCreationFailure) +{ + MockComHelper mockHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWUHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WuaGetTotalHistoryCount) +{ + MockComHelper mockHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, GetTotalHistoryCount(::testing::_, ::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWUHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, WuaQueryHistory) +{ + MockComHelper mockHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, GetTotalHistoryCount(::testing::_, ::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, QueryHistory(::testing::_, ::testing::_, ::testing::_)) + .WillOnce(testing::Return(E_FAIL)); + + EXPECT_THROW(QueryWUHotFixes(hotfixSet, mockHelper), std::runtime_error); +} + +TEST_F(SysInfoWinTest, GetHistoryTest) +{ + MockComHelper mockHelper; + std::set<std::string> hotfixSet; + + EXPECT_CALL(mockHelper, CreateUpdateSearcher(::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, GetTotalHistoryCount(::testing::_, ::testing::_)) + .WillOnce(testing::Return(S_OK)); + + EXPECT_CALL(mockHelper, QueryHistory(::testing::_, ::testing::_, ::testing::_)) + .WillOnce(testing::Return(S_OK)); + + long count = 4; + EXPECT_CALL(mockHelper, GetCount(testing::_, testing::_)) + .WillOnce(testing::DoAll(testing::SetArgReferee<1>(count), testing::Return(S_OK))); + + for (int i = 0 ; i < count; i++) + { + + EXPECT_CALL(mockHelper, GetItem(testing::_, i, testing::_)) + .WillOnce(testing::Return(S_OK)); + + // Simulate getting the title + EXPECT_CALL(mockHelper, GetTitle(testing::_, testing::_)) + .WillRepeatedly(testing::Invoke([](IUpdateHistoryEntry*, BSTR & title) -> HRESULT + { + title = SysAllocString(L"Security Update KB123456"); + return S_OK; + })); + } + + QueryWUHotFixes(hotfixSet, mockHelper); + + EXPECT_EQ(hotfixSet.size(), static_cast<unsigned int>(1)); + EXPECT_EQ(*hotfixSet.begin(), "KB123456"); +} diff --git a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h index dfdfefa8fd1..7dbfa43b8ac 100644 --- a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h +++ b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h @@ -15,6 +15,9 @@ #include "gtest/gtest.h" #include "gmock/gmock.h" +#define WMI_WUA_DLL +#include "utilsWrapperWin.hpp" + class SysInfoWinTest : public ::testing::Test { protected: @@ -26,4 +29,21 @@ class SysInfoWinTest : public ::testing::Test void TearDown() override; }; + +class MockComHelper : public IComHelper +{ + public: + MOCK_METHOD(HRESULT, CreateWmiLocator, (IWbemLocator*& pLoc), (override)); + MOCK_METHOD(HRESULT, ConnectToWmiServer, (IWbemLocator* pLoc, IWbemServices*& pSvc), (override)); + MOCK_METHOD(HRESULT, SetProxyBlanket, (IWbemServices* pSvc), (override)); + MOCK_METHOD(HRESULT, ExecuteWmiQuery, (IWbemServices* pSvc, IEnumWbemClassObject*& pEnumerator), (override)); + MOCK_METHOD(HRESULT, CreateUpdateSearcher, (IUpdateSearcher*& pUpdateSearcher), (override)); + MOCK_METHOD(HRESULT, GetTotalHistoryCount, (IUpdateSearcher* pUpdateSearcher, LONG& count), (override)); + MOCK_METHOD(HRESULT, QueryHistory, (IUpdateSearcher* pUpdateSearcher, IUpdateHistoryEntryCollection*& pHistory, LONG& count), (override)); + MOCK_METHOD(HRESULT, GetCount, (IUpdateHistoryEntryCollection* pHistory, LONG& count), (override)); + MOCK_METHOD(HRESULT, GetItem, (IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry), (override)); + MOCK_METHOD(HRESULT, GetTitle, (IUpdateHistoryEntry* pEntry, BSTR& title), (override)); +}; + + #endif //_SYSINFO_WIN_TEST_H From fdac8bdf19f95ee849905c0c3226938e8898118b Mon Sep 17 00:00:00 2001 From: Luis Enrique Chico Capistrano <luis.chico@wazuh.com> Date: Thu, 30 Jan 2025 21:35:09 -0300 Subject: [PATCH 2/2] feat: enhancement code --- src/common/data_provider/CMakeLists.txt | 1 + src/common/data_provider/src/utilsWrapperWin.cpp | 1 - src/common/data_provider/src/utilsWrapperWin.hpp | 2 +- .../data_provider/tests/sysInfoWin/sysInfoWin_test.h | 7 +------ 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/common/data_provider/CMakeLists.txt b/src/common/data_provider/CMakeLists.txt index 842b5c92aaa..a8361e503e9 100644 --- a/src/common/data_provider/CMakeLists.txt +++ b/src/common/data_provider/CMakeLists.txt @@ -65,6 +65,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + add_definitions(-DWIN32=1 -DWIN_EXPORT) else() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) endif() diff --git a/src/common/data_provider/src/utilsWrapperWin.cpp b/src/common/data_provider/src/utilsWrapperWin.cpp index ab7781238e0..738f6c4ad9e 100644 --- a/src/common/data_provider/src/utilsWrapperWin.cpp +++ b/src/common/data_provider/src/utilsWrapperWin.cpp @@ -16,7 +16,6 @@ #include <string> // For std::string and std::wstring #include <locale> // For localization utilities (if needed for string conversion) -#define WMI_WUA_DLL #include "utilsWrapperWin.hpp" diff --git a/src/common/data_provider/src/utilsWrapperWin.hpp b/src/common/data_provider/src/utilsWrapperWin.hpp index 6422302eb70..4107fb7d683 100644 --- a/src/common/data_provider/src/utilsWrapperWin.hpp +++ b/src/common/data_provider/src/utilsWrapperWin.hpp @@ -10,7 +10,7 @@ */ #pragma once -#ifdef WMI_WUA_DLL +#ifdef _WIN32 #ifdef WIN_EXPORT #define EXPORTED __declspec(dllexport) #else diff --git a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h index 7dbfa43b8ac..9069410b81b 100644 --- a/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h +++ b/src/common/data_provider/tests/sysInfoWin/sysInfoWin_test.h @@ -9,13 +9,11 @@ * Foundation. */ -#ifndef _SYSINFO_WIN_TEST_H -#define _SYSINFO_WIN_TEST_H +#pragma once #include "gtest/gtest.h" #include "gmock/gmock.h" -#define WMI_WUA_DLL #include "utilsWrapperWin.hpp" class SysInfoWinTest : public ::testing::Test @@ -44,6 +42,3 @@ class MockComHelper : public IComHelper MOCK_METHOD(HRESULT, GetItem, (IUpdateHistoryEntryCollection* pHistory, LONG index, IUpdateHistoryEntry** pEntry), (override)); MOCK_METHOD(HRESULT, GetTitle, (IUpdateHistoryEntry* pEntry, BSTR& title), (override)); }; - - -#endif //_SYSINFO_WIN_TEST_H