blic ++ * License (version 2) as published by the FSF - Free Software ++ * Foundation. ++ */ ++ ++#pragma once ++ ++#include ++ ++#include "json.hpp" ++#include "igroup_wrapper.hpp" ++#include "ipasswd_wrapper.hpp" ++ ++#define EXPECTED_GROUPS_MAX 64 ++ ++class UserGroupsProvider ++{ ++ public: ++ /// @brief Constructs a UserGroupsProvider with specific wrappers. ++ /// @param groupWrapper A shared pointer to an IGroupWrapperFreeBSD instance for group operations. ++ /// @param passwdWrapper A shared pointer to an IPasswdWrapperFreeBSD instance for passwd operations. ++ /// @param sysWrapper A shared pointer to an ISystemWrapper instance for system operations. ++ explicit UserGroupsProvider(std::shared_ptr groupWrapper, ++ std::shared_ptr passwdWrapper); ++ ++ /// @brief Default constructor that initializes the UserGroupsProvider with default wrappers. ++ /// @note This constructor uses default implementations of IGroupWrapperFreeBSD, and IPasswdWrapperFreeBSD. ++ UserGroupsProvider(); ++ ++ /// @brief Collects user groups information. ++ /// @param uids A set of user IDs (UIDs) to filter the results. If empty, all users are collected. ++ /// @return A JSON array containing user groups information, where each entry includes UID, GID, and group details. ++ nlohmann::json collect(const std::set& uids = {}); ++ ++ /// @brief Retrieves group names associated with the specified UIDs. ++ /// @param uids A set of user IDs (UIDs) for which to retrieve group names. ++ /// @return A JSON object where keys are UIDs and values are arrays of group names associated with those UIDs. ++ /// If a UID has no associated groups, the value will be an empty array. ++ /// @note This method is useful for quickly mapping UIDs to their group names without retrieving full group details. ++ /// @note If `uids` is empty, it retrieves group names for all users. ++ nlohmann::json getGroupNamesByUid(const std::set& uids = {}); ++ ++ /// @brief Retrieves usernames associated with the specified GIDs. ++ /// @param gids A set of group IDs (GIDs) for which to retrieve usernames. ++ /// @return A JSON object where keys are GIDs and values are arrays of usernames associated with those GIDs. ++ /// If a GID has no associated usernames, the value will be an empty array. ++ /// @note This method is useful for quickly mapping GIDs to their usernames without retrieving full user details. ++ /// @note If `gids` is empty, it retrieves usernames for all groups. ++ nlohmann::json getUserNamesByGid(const std::set& gids = {}); ++ ++ private: ++ std::shared_ptr m_groupWrapper; ++ std::shared_ptr m_passwdWrapper; ++ ++ /// @brief Structure to hold user information. ++ struct UserInfo ++ { ++ const char* name; ++ uid_t uid; ++ gid_t gid; ++ }; ++ ++ /// @brief Retrieves groups for each user and returns a vector of pairs containing UID and their associated groups. ++ /// @param uids A set of user IDs (UIDs) to filter the results. If empty, all users are processed. ++ /// @return A vector of pairs, where each pair contains a UID and a vector of GIDs representing the groups associated with that UID. ++ /// @note This method is used internally to gather user-group associations before formatting the results into JSON. ++ /// @note If a user has no associated groups, the vector of GIDs will be empty. ++ std::vector>> getUserGroups(const std::set& uids); ++ ++ /// @brief Adds groups to the results JSON array for a specific user. ++ /// @param results A reference to the JSON array where the group information will be added. ++ /// @param uid The user ID for which the groups are being added. ++ /// @param groups A pointer to an array of group IDs (GIDs) associated with the user. ++ /// @param ngroups The number of groups in the `groups` array. ++ /// @note This method formats the group information into JSON objects and appends them to the results array. ++ void addGroupsToResults(nlohmann::json& results, uid_t uid, const gid_t* groups, int ngroups); ++}; diff --git a/security/wazuh-agent/files/patch-src_data__provider_src_extended__sources_groups_src-groups_freebsd.hpp b/security/wazuh-agent/files/patch-src_data__provider_src_extended__sources_groups_src-groups_freebsd.hpp new file mode 100644 index 000000000000..d65c4b178507 --- /dev/null +++ b/security/wazuh-agent/files/patch-src_data__provider_src_extended__sources_groups_src-groups_freebsd.hpp @@ -0,0 +1,95 @@ +--- /dev/null 2026-01-13 23:12:14.070467000 +0000 ++++ src/data_provider/src/extended_sources/groups/src/groups_freebsd.cpp 2026-01-13 22:43:51.150488000 +0000 +@@ -0,0 +1,92 @@ ++/* Copyright (C) 2015, Wazuh Inc. ++ * All rights reserved. ++ * ++ * 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 "groups_freebsd.hpp" ++#include "group_wrapper.hpp" ++ ++constexpr size_t MAX_GETPW_R_BUF_SIZE = 16 * 1024; ++ ++GroupsProvider::GroupsProvider(std::shared_ptr groupWrapper) ++ : m_groupWrapper(std::move(groupWrapper)) {} ++ ++GroupsProvider::GroupsProvider() ++ : m_groupWrapper(std::make_shared()) {} ++ ++nlohmann::json GroupsProvider::collect(const std::set& gids) ++{ ++ nlohmann::json results = nlohmann::json::array(); ++ struct group* groupResult ++ { ++ nullptr ++ }; ++ struct group group; ++ ++ size_t bufSize = MAX_GETPW_R_BUF_SIZE; ++ auto buf = std::make_unique(bufSize); ++ ++ if (!gids.empty()) ++ { ++ for (const auto& gid : gids) ++ { ++ while (m_groupWrapper->getgrgid_r(gid, &group, buf.get(), bufSize, &groupResult) == ERANGE) ++ { ++ bufSize *= 2; ++ buf = std::make_unique(bufSize); ++ } ++ ++ if (groupResult == nullptr) ++ { ++ continue; ++ } ++ ++ addGroupToResults(results, groupResult); ++ } ++ } ++ else ++ { ++ std::set groupsIn; ++ m_groupWrapper->setgrent(); ++ ++ while (1) ++ { ++ while (m_groupWrapper->getgrent_r(&group, buf.get(), bufSize, &groupResult) == ERANGE) ++ { ++ bufSize *= 2; ++ buf = std::make_unique(bufSize); ++ } ++ ++ if (groupResult == nullptr) ++ { ++ break; ++ } ++ ++ if (std::find(groupsIn.begin(), groupsIn.end(), groupResult->gr_gid) == groupsIn.end()) ++ { ++ addGroupToResults(results, groupResult); ++ groupsIn.insert(groupResult->gr_gid); ++ } ++ } ++ ++ m_groupWrapper->endgrent(); ++ groupsIn.clear(); ++ } ++ ++ return results; ++} ++ ++void GroupsProvider::addGroupToResults(nlohmann::json& results, const group* group) ++{ ++ nlohmann::json groupJson; ++ ++ groupJson["groupname"] = group->gr_name; ++ groupJson["gid"] = group->gr_gid; ++ groupJson["gid_signed"] = static_cast(group->gr_gid); ++ ++ results.push_back(groupJson); ++} diff --git a/security/wazuh-agent/files/patch-src_data__provider_src_extended__sources_groups_src-user_groups_freebsd.hpp b/security/wazuh-agent/files/patch-src_data__provider_src_extended__sources_groups_src-user_groups_freebsd.hpp new file mode 100644 index 000000000000..ef6229d3ef82 --- /dev/null +++ b/security/wazuh-agent/files/patch-src_data__provider_src_extended__sources_groups_src-user_groups_freebsd.hpp @@ -0,0 +1,262 @@ +--- /dev/null 2026-01-13 23:12:49.062343000 +0000 ++++ src/data_provider/src/extended_sources/groups/src/user_groups_freebsd.cpp 2026-01-13 22:43:51.150552000 +0000 +@@ -0,0 +1,259 @@ ++/* Copyright (C) 2015, Wazuh Inc. ++ * All rights reserved. ++ * ++ * 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 ++#include ++#include "user_groups_freebsd.hpp" ++#include "group_wrapper.hpp" ++#include "passwd_wrapper.hpp" ++ ++constexpr size_t MAX_GETPW_R_BUF_SIZE = 16 * 1024; ++ ++UserGroupsProvider::UserGroupsProvider(std::shared_ptr groupWrapper, ++ std::shared_ptr passwdWrapper) ++ : m_groupWrapper(std::move(groupWrapper)) ++ , m_passwdWrapper(std::move(passwdWrapper)) ++{ ++} ++ ++UserGroupsProvider::UserGroupsProvider() ++ : m_groupWrapper(std::make_shared()) ++ , m_passwdWrapper(std::make_shared()) ++{ ++} ++ ++nlohmann::json UserGroupsProvider::collect(const std::set& uids) ++{ ++ nlohmann::json results = nlohmann::json::array(); ++ auto usersGroups = getUserGroups(uids); ++ ++ for (const auto& [uid, groups] : usersGroups) ++ { ++ addGroupsToResults(results, uid, groups.data(), static_cast(groups.size())); ++ } ++ ++ return results; ++} ++ ++nlohmann::json UserGroupsProvider::getGroupNamesByUid(const std::set& uids) ++{ ++ const bool singleUid = (uids.size() == 1); ++ nlohmann::json result = singleUid ? nlohmann::json::array() : nlohmann::json::object(); ++ auto usersGroups = getUserGroups(uids); ++ ++ size_t bufSize = sysconf(_SC_GETGR_R_SIZE_MAX); ++ ++ if (bufSize > MAX_GETPW_R_BUF_SIZE) ++ { ++ bufSize = MAX_GETPW_R_BUF_SIZE; ++ } ++ ++ for (const auto& [uid, groups] : usersGroups) ++ { ++ nlohmann::json groupNames = nlohmann::json::array(); ++ ++ for (const auto& gid : groups) ++ { ++ struct group grp; ++ struct group* grpResult = nullptr; ++ auto groupBuf = std::make_unique(bufSize); ++ ++ if (m_groupWrapper->getgrgid_r(gid, &grp, groupBuf.get(), bufSize, &grpResult) == 0 && grpResult != nullptr) ++ { ++ groupNames.push_back(grpResult->gr_name); ++ } ++ } ++ ++ if (singleUid) ++ { ++ result = groupNames; ++ } ++ else ++ { ++ result[std::to_string(uid)] = groupNames; ++ } ++ } ++ ++ return result; ++} ++ ++nlohmann::json UserGroupsProvider::getUserNamesByGid(const std::set& gids) ++{ ++ const bool allGroups = gids.empty(); ++ const bool singleGid = (!allGroups && gids.size() == 1); ++ nlohmann::json result = singleGid ? nlohmann::json::array() : nlohmann::json::object(); ++ ++ size_t bufSize = sysconf(_SC_GETPW_R_SIZE_MAX); ++ ++ if (bufSize > MAX_GETPW_R_BUF_SIZE) ++ { ++ bufSize = MAX_GETPW_R_BUF_SIZE; ++ } ++ ++ std::map> gidToUsernames; ++ ++ if (allGroups) ++ { ++ struct group* grp = nullptr; ++ m_groupWrapper->setgrent(); ++ ++ while ((grp = m_groupWrapper->getgrent()) != nullptr) ++ { ++ gid_t gid = grp->gr_gid; ++ char** members = grp->gr_mem; ++ ++ while (members && *members) ++ { ++ gidToUsernames[gid].insert(*members); ++ ++members; ++ } ++ } ++ ++ m_groupWrapper->endgrent(); ++ } ++ else ++ { ++ for (const auto& gid : gids) ++ { ++ struct group grp; ++ struct group* grpResult = nullptr; ++ auto groupBuf = std::make_unique(bufSize); *** 863 LINES SKIPPED ***