diff --git a/security/wazuh-manager/Makefile b/security/wazuh-manager/Makefile index 1478ab9416b3..c7b2d1213a97 100644 --- a/security/wazuh-manager/Makefile +++ b/security/wazuh-manager/Makefile @@ -1,455 +1,456 @@ PORTNAME= wazuh DISTVERSIONPREFIX= v DISTVERSION= 4.14.1 -PORTREVISION= 6 +PORTREVISION= 7 CATEGORIES= security MASTER_SITES= https://packages.wazuh.com/deps/47/libraries/sources/:wazuh_sources \ LOCAL/acm/${PORTNAME}/:wazuh_cache PKGNAMESUFFIX= -manager DISTFILES= ${EXTERNAL_DISTFILES} \ ${PORTNAME}-cache-any-${DISTVERSION}${EXTRACT_SUFX}:wazuh_cache \ ${PORTNAME}-python-${DISTVERSION}${EXTRACT_SUFX}:wazuh_cache DIST_SUBDIR= ${PORTNAME}-${DISTVERSION} EXTRACT_ONLY= ${DISTNAME}${EXTRACT_SUFX} MAINTAINER= acm@FreeBSD.org COMMENT= Security tool to monitor and check logs and intrusions (manager) WWW= https://wazuh.com/ LICENSE= GPLv2 LICENSE_FILE= ${WRKSRC}/LICENSE ONLY_FOR_ARCHS= aarch64 amd64 BUILD_DEPENDS= autoconf>=2.71:devel/autoconf \ bash>0:shells/bash \ cmake:devel/cmake-core LIB_DEPENDS+= libarrow.so:databases/arrow \ libcurl.so:ftp/curl \ libepoll-shim.so:devel/libepoll-shim \ libffi.so:devel/libffi \ libgdbm.so:databases/gdbm \ libnghttp2.so:www/libnghttp2 \ libopenblas.so:math/openblas RUN_DEPENDS= bash>0:shells/bash USES= cpe dos2unix gmake perl5 python:3.11 readline shebangfix sqlite:3 uidfix USE_GITHUB= yes GH_TUPLE= alonsobsd:wazuh-freebsd:${WAZUH_EXTRAFILE_TAGNAME}:wazuh USE_RC_SUBR= ${PORTNAME}${PKGNAMESUFFIX} MAKE_ARGS+= TARGET=server INSTALLDIR=${WAZUHPREFIX} INSTALL_SHARED="${INSTALL_LIB}" PYTHON_SOURCE=yes OPTIMIZE_CPYTHON=no DOS2UNIX_FILES= ${WRKSRC}/api/api/configuration/api.yaml #WITH_CCACHE_BUILD= yes #CCACHE_DIR= /zdata/ccache WAZUH_CACHEFILE= ${PORTNAME}-cache-any-${DISTVERSION}${EXTRACT_SUFX} WAZUH_EXTRAFILE= alonsobsd-${PORTNAME}-freebsd-${WAZUH_EXTRAFILE_TAGNAME}_GH0${EXTRACT_SUFX} WAZUH_EXTRAFILE_TAGNAME=830a911 EXTERNAL_DISTFILES= audit-userspace.tar.gz:wazuh_sources \ benchmark.tar.gz:wazuh_sources \ bzip2.tar.gz:wazuh_sources \ cJSON.tar.gz:wazuh_sources \ cpp-httplib.tar.gz:wazuh_sources \ cpython-3.11.14.tar.gz:wazuh_cache \ curl.tar.gz:wazuh_sources \ flatbuffers.tar.gz:wazuh_sources \ googletest.tar.gz:wazuh_sources \ http-request-cd50797.tar.gz:wazuh_cache \ jemalloc.tar.gz:wazuh_sources \ libarchive.tar.gz:wazuh_sources \ libdb.tar.gz:wazuh_sources \ libffi.tar.gz:wazuh_sources \ libpcre2.tar.gz:wazuh_sources \ libplist.tar.gz:wazuh_sources \ libyaml.tar.gz:wazuh_sources \ lua.tar.gz:wazuh_sources \ lzma.tar.gz:wazuh_sources \ msgpack.tar.gz:wazuh_sources \ nlohmann.tar.gz:wazuh_cache \ openssl.tar.gz:wazuh_sources \ popt.tar.gz:wazuh_sources \ procps.tar.gz:wazuh_sources \ rocksdb.tar.gz:wazuh_sources \ simdjson.tar.gz:wazuh_sources \ sqlite.tar.gz:wazuh_sources \ zlib.tar.gz:wazuh_sources OPTIONS_DEFINE= INOTIFY PRELUDE ZEROMQ OPTIONS_GROUP_DATABASE= MYSQL PGSQL OPTIONS_GROUP= DATABASE INOTIFY_LIB_DEPENDS= libinotify.so:devel/libinotify PRELUDE_LIB_DEPENDS= libprelude.so:security/libprelude ZEROMQ_LIB_DEPENDS= libczmq.so:net/czmq INOTIFY_DESC= Kevent based real time monitoring PRELUDE_DESC= Sensor support from Prelude SIEM ZEROMQ_DESC= ZeroMQ support ZEROMQ_MAKE_ENV= USE_ZEROMQ=yes PRELUDE_MAKE_ENV= USE_PRELUDE=yes INOTIFY_MAKE_ENV= USE_INOTIFY=yes INOTIFY_USES= pkgconfig PGSQL_MAKE_ARGS=DATABASE=pgsql PGSQL_USES= pgsql MYSQL_MAKE_ARGS=DATABASE=mysql MYSQL_USES= mysql WAZUH_USER= wazuh WAZUH_GROUP= wazuh USERS= ${WAZUH_USER} GROUPS= ${WAZUH_GROUP} SUB_FILES= pkg-message CONFLICTS= ossec-* wazuh-agent WZBIN_FILES= agent_control wazuh-logcollector wazuh-execd manage_agents wazuh-modulesd \ wazuh-agentlessd wazuh-analysisd wazuh-monitord wazuh-reportd wazuh-maild \ wazuh-logtest-legacy wazuh-csyslogd wazuh-dbd verify-agent-conf clear_stats \ wazuh-regex wazuh-integratord wazuh-db wazuh-remoted wazuh-authd wazuh-keystore WZARBIN_FILES= default-firewall-drop pf npf ipfw firewalld-drop disable-account \ host-deny ip-customblock restart-wazuh route-null kaspersky wazuh-slack WZSHEBANG_FILES=chardetect connexion cygdb cython cythonize f2py fixup_pubsub_v1_keywords.py \ httpx jp.py jsonschema normalizer openapi-spec-validator \ pyrsa-decrypt pyrsa-encrypt pyrsa-keygen pyrsa-priv2pub pyrsa-sign \ pyrsa-verify rstpep2html.py rst2s5.py rst2xetex.py rst2man.py rst2odt.py \ rst2latex.py rst2pseudoxml.py rst2odt_prepstyles.py rst2html.py rst2html5.py \ rst2html4.py rst2xml.py tabulate uvicorn wsdump.py WAZUHMOD660= /queue/indexer /queue/vd WAZUHMOD750= / /logs/wazuh /logs/archives /logs/alerts /logs/firewall \ /logs/api /logs/cluster /bin /lib /queue /queue/agentless \ /queue/db /queue/diff /queue/fts /queue/keystore /queue/logcollector \ /queue/syscollector /queue/syscollector/db /ruleset \ /ruleset/decoders /ruleset/rules /ruleset/sca /wodles \ /active-response /active-response/bin /agentless /var /backup \ /backup/db /backup/agents /backup/groups /backup/shared \ /wodles/aws /wodles/aws/buckets_s3 /wodles/aws/services /wodles/aws/subscribers \ /wodles/azure /wodles/azure/azure_services /wodles/azure/db \ /wodles/docker /wodles/gcloud /wodles/gcloud/buckets /wodles/gcloud/pubsub \ /stats /integrations WAZUHMOD770= /etc/decoders /etc/lists /etc/lists/amazon /etc/lists/malicious-ioc /etc/rootcheck \ /etc/rules /etc/shared/default /logs /queue/agent-groups \ /queue/alerts /queue/cluster /queue/fim /queue/fim/db \ /queue/rids /queue/sockets /queue/tasks /etc /etc/shared \ /.ssh /var/db /var/download /var/db/agents /var/run /var/upgrade \ /var/selinux /var/wodles /var/multigroups /queue/rids /queue/router WAZUHPREFIX= /var/ossec WZPYTHONWHEELS= cffi-1.15.1-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ cryptography-44.0.1-cp37-abi3-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ greenlet-2.0.2-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ grpcio-1.69.0-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ lazy_object_proxy-1.10.0-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ markupsafe-2.1.2-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ multidict-5.2.0-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ numpy-1.26.4-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ psutil-5.9.0-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ pyarrow-21.0.0-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ pyyaml-6.0.1-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ rpds_py-0.15.2-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl \ uvloop-0.17.0-cp311-cp311-${FBSD_VERSION_BASE}_${ARCH_BASE}.whl ARCH_BASE= ${ARCH:S/aarch64/arm64/g} UNAME_r= ${_OSRELEASE:tl} FBSD_RELEASE= freebsd_${UNAME_r:S/./_/g:S/-/_/g} .include .if ${ARCH} == "aarch64" && ${OSVERSION} < 1400000 IGNORE= FreeBSD ${OSVERSION} ${ARCH} is not supported .endif .if ${ARCH} == "aarch64" FBSD14_PATCH_LEVEL= _p5 .endif .if ${ARCH} != "aarch64" FBSD13_PATCH_LEVEL= _p6 FBSD14_PATCH_LEVEL= _p5 .endif .if ${OSVERSION} >= 1300139 && ${OSVERSION} < 1400000 FBSD_VERSION_BASE=freebsd_13_5_release${FBSD13_PATCH_LEVEL} FBSD_MAJOR_VERSION=13 WAZUH_CACHENAME=${PORTNAME}-cache-fbsd13-${ARCH}-${DISTVERSION} DISTFILES+= ${WAZUH_CACHENAME}${EXTRACT_SUFX}:wazuh_cache .elif ${OSVERSION} >= 1400000 && ${OSVERSION} < 1500000 FBSD_VERSION_BASE=freebsd_14_3_release${FBSD14_PATCH_LEVEL} FBSD_MAJOR_VERSION=14 WAZUH_CACHENAME=${PORTNAME}-cache-fbsd14-${ARCH}-${DISTVERSION} DISTFILES+= ${WAZUH_CACHENAME}${EXTRACT_SUFX}:wazuh_cache .elif ${OSVERSION} >= 1500000 && ${OSVERSION} < 1600000 FBSD_VERSION_BASE=freebsd_15_0_release FBSD_MAJOR_VERSION=15 WAZUH_CACHENAME=${PORTNAME}-cache-fbsd15-${ARCH}-${DISTVERSION} DISTFILES+= ${WAZUH_CACHENAME}${EXTRACT_SUFX}:wazuh_cache .elif ${OSVERSION} >= 1600000 FBSD_VERSION_BASE=freebsd_16_0_current FBSD_MAJOR_VERSION=16 WAZUH_CACHENAME=${PORTNAME}-cache-fbsd16-${ARCH}-${DISTVERSION} DISTFILES+= ${WAZUH_CACHENAME}${EXTRACT_SUFX}:wazuh_cache .else IGNORE= FreeBSD ${OSVERSION} ${ARCH} is not supported .endif post-extract: .for FILE in ${EXTERNAL_DISTFILES} .if ${FILE} == "http-request-cd50797.tar.gz:wazuh_cache" @cd ${WRKSRC}/src/shared_modules && ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${_DISTDIR}/${FILE:S/:wazuh_cache//} ${EXTRACT_AFTER_ARGS} .else @cd ${WRKSRC}/src/external && ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${_DISTDIR}/${FILE:S/:wazuh_sources//:S/:wazuh_cache//} ${EXTRACT_AFTER_ARGS} .endif .endfor @cd ${WRKDIR} && ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${_DISTDIR}/${WAZUH_EXTRAFILE} ${EXTRACT_AFTER_ARGS} @${MV} ${WRKDIR}/${PORTNAME}-freebsd-${WAZUH_EXTRAFILE_TAGNAME} ${WRKDIR}/wazuh-freebsd @cd ${WRKSRC}/src && ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${_DISTDIR}/${WAZUH_CACHEFILE} ${EXTRACT_AFTER_ARGS} @cd ${WRKSRC}/src && ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${_DISTDIR}/${WAZUH_CACHENAME}${EXTRACT_SUFX} ${EXTRACT_AFTER_ARGS} @cd ${WRKSRC}/src && ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${_DISTDIR}/${PORTNAME}-python-${DISTVERSION}${EXTRACT_SUFX} ${EXTRACT_AFTER_ARGS} . for FILE in ${WZPYTHONWHEELS} @${MV} ${WRKSRC}/src/wazuh-cache/${FILE} ${WRKSRC}/src/wazuh-cache/${FILE:S/${FBSD_VERSION_BASE}/${FBSD_RELEASE}/} . endfor @${RM} ${WRKSRC}/src/external/cpython/python ${WRKSRC}/src/external/cpython/libpython* ${WRKSRC}/src/external/cpython/Modules/*.o @${MKDIR} ${WRKSRC}/ruleset/sca/freebsd + @${MKDIR} ${WRKSRC}/src/data_provider/src/extended_sources/wrappers/unix/freebsd @cd ${WRKDIR}/wazuh-freebsd/var/ossec/ruleset/sca && ${CP} *.yml ${WRKSRC}/ruleset/sca/freebsd/ ${FIND} ${WRKSRC}/ruleset/sca -type f -name "*.yml" -exec ${MV} "{}" "{}.disabled" \; ${CP} ${FILESDIR}/pthreads_portable.c ${WRKSRC}/src/shared/ ${CP} ${FILESDIR}/pthreads_portable.h ${WRKSRC}/src/headers/ post-patch: ${REINPLACE_CMD} -e 's|CC=|CC?=|g' -e 's|AR=|AR?=|g' ${WRKSRC}/src/external/bzip2/Makefile ${REINPLACE_CMD} -e 's|^\( *MULTIARCH=\).*--print-multiarch.*|\1|' ${WRKSRC}/src/external/cpython/configure ${REINPLACE_CMD} -e 's|coroutine|coroutines|g' ${WRKSRC}/framework/wazuh/core/cluster/client.py \ ${WRKSRC}/framework/wazuh/rbac/decorators.py do-build: cd ${WRKSRC} && ${CC} ${CFLAGS} -o check_pid ${FILESDIR}/check_pid.c cd ${WRKSRC}/src/ && ${SETENV} ${MAKE_ENV} STAGEDIR=${STAGEDIR} \ ${MAKE_CMD} ${MAKE_ARGS} do-install: ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/bin ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/lib ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/libexec ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/tmp ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/templates ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/.ssh .for DIRE in ${WAZUHMOD660} ${MKDIR} -m 0660 ${STAGEDIR}${WAZUHPREFIX}${DIRE} .endfor .for DIRE in ${WAZUHMOD750} ${MKDIR} -m 0750 ${STAGEDIR}${WAZUHPREFIX}${DIRE} .endfor .for DIRE in ${WAZUHMOD770} ${MKDIR} -m 0770 ${STAGEDIR}${WAZUHPREFIX}${DIRE} .endfor ${INSTALL_PROGRAM} ${WRKSRC}/check_pid ${STAGEDIR}${WAZUHPREFIX}/libexec/check_pid ${INSTALL_DATA} /dev/null ${STAGEDIR}${WAZUHPREFIX}/logs/ossec.log ${INSTALL_DATA} /dev/null ${STAGEDIR}${WAZUHPREFIX}/logs/ossec.json ${INSTALL_DATA} /dev/null ${STAGEDIR}${WAZUHPREFIX}/logs/active-responses.log .for FILE in ${WZBIN_FILES} ${INSTALL_PROGRAM} ${WRKSRC}/src/${FILE} ${STAGEDIR}${WAZUHPREFIX}/bin .endfor ${INSTALL_PROGRAM} ${WRKSRC}/src/syscheckd/build/bin/wazuh-syscheckd ${STAGEDIR}${WAZUHPREFIX}/bin ${INSTALL_SCRIPT} ${WRKSRC}/src/init/wazuh-server.sh ${STAGEDIR}${WAZUHPREFIX}/bin/wazuh-control ${TOUCH} ${STAGEDIR}${WAZUHPREFIX}/etc/localtime ${INSTALL_DATA} ${WRKSRC}/etc/internal_options.conf ${STAGEDIR}${WAZUHPREFIX}/etc ${INSTALL_DATA} ${WRKSRC}/src/wazuh_modules/syscollector/norm_config.json ${STAGEDIR}${WAZUHPREFIX}/queue/syscollector ${INSTALL_DATA} ${WRKSRC}/etc/local_internal_options.conf ${STAGEDIR}${WAZUHPREFIX}/etc/local_internal_options.conf.sample ${INSTALL_DATA} /dev/null ${STAGEDIR}${WAZUHPREFIX}/etc/client.keys.sample ${INSTALL_DATA} ${WRKSRC}/etc/ossec-server.conf ${STAGEDIR}${WAZUHPREFIX}/etc/ossec.conf.sample ${INSTALL_SCRIPT} ${WRKSRC}/src/agentlessd/scripts/* ${STAGEDIR}${WAZUHPREFIX}/agentless/ .for FILE in ${WZARBIN_FILES} ${INSTALL_PROGRAM} ${WRKSRC}/src/${FILE} ${STAGEDIR}${WAZUHPREFIX}/active-response/bin .endfor ${INSTALL_SCRIPT} ${WRKSRC}/src/active-response/*.sh ${STAGEDIR}${WAZUHPREFIX}/active-response/bin ${INSTALL_SCRIPT} ${WRKSRC}/src/active-response/*.py ${STAGEDIR}${WAZUHPREFIX}/active-response/bin ${INSTALL_PROGRAM} ${WRKSRC}/src/default-firewall-drop ${STAGEDIR}${WAZUHPREFIX}/active-response/bin/firewall-drop # Install rules files ${INSTALL_DATA} ${WRKSRC}/ruleset/rules/*.xml ${STAGEDIR}${WAZUHPREFIX}/ruleset/rules ${INSTALL_DATA} ${WRKDIR}/wazuh-freebsd/var/ossec/ruleset/rules/*.xml ${STAGEDIR}${WAZUHPREFIX}/ruleset/rules # Install decoders files ${INSTALL_DATA} ${WRKSRC}/ruleset/decoders/*.xml ${STAGEDIR}${WAZUHPREFIX}/ruleset/decoders ${INSTALL_DATA} ${WRKDIR}/wazuh-freebsd/var/ossec/ruleset/decoders/*.xml ${STAGEDIR}${WAZUHPREFIX}/ruleset/decoders ${INSTALL_DATA} ${WRKSRC}/ruleset/rootcheck/db/*.txt ${STAGEDIR}${WAZUHPREFIX}/etc/rootcheck ${INSTALL_DATA} ${WRKSRC}/etc/local_decoder.xml ${STAGEDIR}${WAZUHPREFIX}/etc/decoders/local_decoder.xml.sample ${INSTALL_DATA} ${WRKSRC}/etc/local_rules.xml ${STAGEDIR}${WAZUHPREFIX}/etc/rules/local_rules.xml.sample ${INSTALL_DATA} ${WRKSRC}/ruleset/lists/amazon/* ${STAGEDIR}${WAZUHPREFIX}/etc/lists/amazon/ ${INSTALL_DATA} ${WRKSRC}/ruleset/lists/malicious-ioc/* ${STAGEDIR}${WAZUHPREFIX}/etc/lists/malicious-ioc/ ${INSTALL_DATA} ${WRKSRC}/ruleset/lists/audit-keys ${STAGEDIR}${WAZUHPREFIX}/etc/lists/audit-keys ${INSTALL_DATA} ${WRKSRC}/ruleset/lists/security-eventchannel ${STAGEDIR}${WAZUHPREFIX}/etc/lists/security-eventchannel ${INSTALL_SCRIPT} ${WRKSRC}/integrations/maltiverse.py ${STAGEDIR}${WAZUHPREFIX}/integrations/maltiverse.py ${INSTALL_SCRIPT} ${WRKSRC}/integrations/pagerduty.py ${STAGEDIR}${WAZUHPREFIX}/integrations/pagerduty.py ${INSTALL_SCRIPT} ${WRKSRC}/integrations/slack.py ${STAGEDIR}${WAZUHPREFIX}/integrations/slack.py ${INSTALL_SCRIPT} ${WRKSRC}/integrations/shuffle.py ${STAGEDIR}${WAZUHPREFIX}/integrations/shuffle.py ${INSTALL_SCRIPT} ${WRKSRC}/integrations/virustotal.py ${STAGEDIR}${WAZUHPREFIX}/integrations/virustotal.py ${INSTALL_DATA} /dev/null ${STAGEDIR}${WAZUHPREFIX}/queue/agents-timestamp ${INSTALL_DATA} ${WRKSRC}/ruleset/rootcheck/db/*.txt ${STAGEDIR}${WAZUHPREFIX}/etc/shared/default ${INSTALL_DATA} ${WRKSRC}/etc/agent.conf ${STAGEDIR}${WAZUHPREFIX}/etc/shared/default/agent.conf.sample ${INSTALL_DATA} ${WRKSRC}/etc/agent.conf ${STAGEDIR}${WAZUHPREFIX}/etc/shared/agent-template.conf ${INSTALL_SCRIPT} ${WRKSRC}/wodles/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/utils.py ${STAGEDIR}${WAZUHPREFIX}/wodles/utils.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/aws_s3.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/aws-s3.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/aws_tools.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/aws_tools.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/wazuh_integration.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/wazuh_integration.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/aws_bucket.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/aws_bucket.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/cloudtrail.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/cloudtrail.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/config.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/config.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/guardduty.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/guardduty.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/load_balancers.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/load_balancers.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/server_access.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/server_access.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/umbrella.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/umbrella.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/vpcflow.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/vpcflow.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/buckets_s3/waf.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/buckets_s3/waf.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/services/aws_service.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/services/aws_service.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/services/cloudwatchlogs.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/services/cloudwatchlogs.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/services/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/services/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/services/inspector.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/services/inspector.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/subscribers/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/subscribers/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/subscribers/sqs_queue.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/subscribers/sqs_queue.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/subscribers/s3_log_handler.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/subscribers/s3_log_handler.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/aws/subscribers/sqs_message_processor.py ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/subscribers/sqs_message_processor.py ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/wodles/aws/aws-s3 ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/exceptions.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/exceptions.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/gcloud.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/gcloud.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/integration.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/integration.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/tools.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/tools.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/buckets/bucket.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/buckets/bucket.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/buckets/access_logs.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/buckets/access_logs.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/gcloud/pubsub/subscriber.py ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/pubsub/subscriber.py ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/wodles/gcloud/gcloud ${INSTALL_SCRIPT} ${WRKSRC}/wodles/docker-listener/DockerListener.py ${STAGEDIR}${WAZUHPREFIX}/wodles/docker/DockerListener.py ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/wodles/docker/DockerListener ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/azure-logs.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure-logs.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/azure_utils.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure_utils.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/azure_services/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure_services/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/azure_services/analytics.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure_services/analytics.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/azure_services/graph.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure_services/graph.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/azure_services/storage.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure_services/storage.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/db/__init__.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/db/__init__.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/db/orm.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/db/orm.py ${INSTALL_SCRIPT} ${WRKSRC}/wodles/azure/db/utils.py ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/db/utils.py ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/wodles/azure/azure-logs ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/integrations/maltiverse ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/integrations/pagerduty ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/integrations/slack ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/integrations/virustotal ${INSTALL_SCRIPT} ${WRKSRC}/framework/wrappers/generic_wrapper.sh ${STAGEDIR}${WAZUHPREFIX}/integrations/shuffle # Install SCA files ${FIND} ${WRKSRC}/ruleset/sca -type f -name "*.yml.disabled" -exec ${INSTALL_DATA} "{}" ${STAGEDIR}${WAZUHPREFIX}/ruleset/sca/ \; ${INSTALL_LIB} ${WRKSRC}/src/libwazuhext.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/libwazuhshared.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/build/shared_modules/content_manager/libcontent_manager.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/build/shared_modules/indexer_connector/libindexer_connector.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/build/wazuh_modules/inventory_harvester/libinventory_harvester.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/build/shared_modules/router/librouter.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/build/wazuh_modules/vulnerability_scanner/libvulnerability_scanner.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/data_provider/build/lib/libsysinfo.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/external/jemalloc/lib/libjemalloc.so.2 ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/external/rocksdb/build/librocksdb.so.8.3.2 ${STAGEDIR}${WAZUHPREFIX}/lib/librocksdb.so.8 ${INSTALL_LIB} ${WRKSRC}/src/shared_modules/dbsync/build/lib/libdbsync.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/shared_modules/rsync/build/lib/librsync.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/syscheckd/build/lib/libfimdb.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_LIB} ${WRKSRC}/src/wazuh_modules/syscollector/build/lib/libsyscollector.so ${STAGEDIR}${WAZUHPREFIX}/lib ${INSTALL_DATA} ${WRKSRC}/src/wazuh_modules/vulnerability_scanner/indexer/template/index-template.json ${STAGEDIR}${WAZUHPREFIX}/templates/vd_states_template.json ${INSTALL_DATA} ${WRKSRC}/src/wazuh_modules/vulnerability_scanner/indexer/template/update-mappings.json ${STAGEDIR}${WAZUHPREFIX}/templates/vd_states_update_mappings.json ${INSTALL_DATA} ${WRKSRC}/src/wazuh_modules/inventory_harvester/indexer/template/wazuh-states-inventory-* ${STAGEDIR}${WAZUHPREFIX}/templates/ ${INSTALL_DATA} ${WRKSRC}/VERSION.json ${STAGEDIR}${WAZUHPREFIX} cd ${WRKSRC}/src/ && ${SETENV} ${MAKE_ENV} STAGEDIR=${STAGEDIR} \ ${MAKE_CMD} install_python ${MAKE_ARGS} cd ${WRKSRC}/src/ && ${SETENV} ${MAKE_ENV} STAGEDIR=${STAGEDIR} \ ${MAKE_CMD} install_dependencies ${MAKE_ARGS} cd ${WRKSRC}/src/ && ${SETENV} ${MAKE_ENV} STAGEDIR=${STAGEDIR} \ ${MAKE_CMD} install_framework ${MAKE_ARGS} cd ${WRKSRC}/src/ && ${SETENV} ${MAKE_ENV} STAGEDIR=${STAGEDIR} \ ${MAKE_CMD} install_api ${MAKE_ARGS} cd ${WRKSRC}/src/ && ${SETENV} ${MAKE_ENV} STAGEDIR=${STAGEDIR} \ ${MAKE_CMD} install_mitre ${MAKE_ARGS} cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} \ ${MAKE_CMD} --quiet -C framework install INSTALLDIR=${STAGEDIR}${WAZUHPREFIX} cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} \ ${MAKE_CMD} --quiet -C api install INSTALLDIR=${STAGEDIR}${WAZUHPREFIX} @cd ${STAGEDIR}${WAZUHPREFIX}/framework/python/lib && \ ${STAGEDIR}${WAZUHPREFIX}/framework/python/bin/python3 -m compileall -x 'bad_coding|badsyntax|lib2to3/tests/data' -f -p ${WAZUHPREFIX}/framework/python/lib/ "${PYTHON_VERSION}" @cd ${STAGEDIR}${WAZUHPREFIX}/framework/python/lib && \ ${STAGEDIR}${WAZUHPREFIX}/framework/python/bin/python3 -O -m compileall -x 'bad_coding|badsyntax|lib2to3/tests/data' -f -p ${WAZUHPREFIX}/framework/python/lib/ "${PYTHON_VERSION}" @cd ${STAGEDIR}${WAZUHPREFIX}/framework/python/lib && \ ${STAGEDIR}${WAZUHPREFIX}/framework/python/bin/python3 -OO -m compileall -x 'bad_coding|badsyntax|lib2to3/tests/data' -f -p ${WAZUHPREFIX}/framework/python/lib/ "${PYTHON_VERSION}" ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/etc/templates ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/databases ${MKDIR} ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/src cd ${WRKSRC}/etc/templates && ${COPYTREE_SHARE} config \ ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/etc/templates/ cd ${WRKSRC}/src && ${COPYTREE_SHARE} init \ ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/src/ cd ${WRKSRC}/ruleset && ${COPYTREE_SHARE} sca \ ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/ ${INSTALL_SCRIPT} ${WRKSRC}/gen_ossec.sh ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/ ${INSTALL_SCRIPT} ${WRKSRC}/add_localfiles.sh ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/ ${INSTALL_DATA} ${WRKSRC}/src/os_dbd/mysql.schema ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/databases ${INSTALL_DATA} ${WRKSRC}/src/os_dbd/postgresql.schema ${STAGEDIR}${WAZUHPREFIX}/packages_files/manager_installation_scripts/databases @${FIND} ${STAGEDIR}${WAZUHPREFIX}/framework/python/lib/${PYTHON_VERSION}/site-packages/numpy/distutils/ -type f -name "*.bak" -delete -o -name "*.orig" -delete @${RM} ${STAGEDIR}${WAZUHPREFIX}/framework/python/lib/${PYTHON_VERSION}/site-packages/numpy/f2py/tests/src/temp @${RM} ${STAGEDIR}${WAZUHPREFIX}/framework/python/lib/${PYTHON_VERSION}/site-packages/numpy/core/tests/examples/temp post-install: @${STRIP_CMD} ${STAGEDIR}${WAZUHPREFIX}/framework/python/bin/${PYTHON_VERSION} @${FIND} ${STAGEDIR}${WAZUHPREFIX}/framework -type f -name "*.so" -exec ${STRIP_CMD} "{}" \; .for FILE in ${WZSHEBANG_FILES} @${REINPLACE_CMD} -i "" -e 's|${STAGEDIR}||g' ${STAGEDIR}${WAZUHPREFIX}/framework/python/bin/${FILE} .endfor .include diff --git a/security/wazuh-manager/files/patch-src_data__provider-CMakeLists.txt b/security/wazuh-manager/files/patch-src_data__provider-CMakeLists.txt new file mode 100644 index 000000000000..03dd0efcd223 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider-CMakeLists.txt @@ -0,0 +1,39 @@ +--- src/data_provider/CMakeLists.txt 2025-11-07 08:46:03.000000000 +0000 ++++ src/data_provider/CMakeLists.txt 2026-01-13 15:21:46.999172000 +0000 +@@ -104,7 +104,6 @@ + include_directories(${CMAKE_SOURCE_DIR}/src/extended_sources/wrappers/unix/darwin) + endif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + +- + if(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") + link_directories(${INSTALL_PREFIX}/lib) + endif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") +@@ -119,6 +118,11 @@ + include_directories(${CMAKE_SOURCE_DIR}/src/extended_sources/wrappers/unix/darwin) + endif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + ++if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ include_directories(${CMAKE_SOURCE_DIR}/src/extended_sources/wrappers/unix/) ++ include_directories(${CMAKE_SOURCE_DIR}/src/extended_sources/wrappers/unix/freebsd) ++endif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ + link_directories(${SRC_FOLDER}) + link_directories(${SRC_FOLDER}/external/sqlite/) + link_directories(${SRC_FOLDER}/external/cJSON/) +@@ -210,6 +214,7 @@ + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR + CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR ++ CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_subdirectory(src/extended_sources) + endif() +@@ -250,7 +255,7 @@ + target_link_libraries(sysinfo cjson ${SRC_FOLDER}/external/libplist/bin/lib/libplist-2.0.a ${iokit_lib} ${corefoundation_lib} groups users services browser_extensions) + endif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + +-target_link_libraries(sysinfo wazuhext) ++target_link_libraries(sysinfo nghttp2 wazuhext users groups) + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(CURL_DEP "wazuhext") diff --git a/security/wazuh-manager/files/patch-src_data__provider_CMakeLists.txt b/security/wazuh-manager/files/patch-src_data__provider_CMakeLists.txt deleted file mode 100644 index a5527dcc913a..000000000000 --- a/security/wazuh-manager/files/patch-src_data__provider_CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ ---- src/data_provider/CMakeLists.txt.orig 2023-05-22 04:53:06 UTC -+++ src/data_provider/CMakeLists.txt -@@ -153,7 +153,7 @@ elseif(APPLE) - target_link_libraries(sysinfo cjson ${SRC_FOLDER}/external/libplist/bin/lib/libplist-2.0.a) - endif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - --target_link_libraries(sysinfo wazuhext) -+target_link_libraries(sysinfo nghttp2 wazuhext) - - - if(APPLE) diff --git a/security/wazuh-manager/files/patch-src-data_provider-src_sysInfoFreeBSD.cpp b/security/wazuh-manager/files/patch-src_data__provider_src-sysInfoFreeBSD.cpp similarity index 68% rename from security/wazuh-manager/files/patch-src-data_provider-src_sysInfoFreeBSD.cpp rename to security/wazuh-manager/files/patch-src_data__provider_src-sysInfoFreeBSD.cpp index 9fb64aa3c105..8ef1dd376f3e 100644 --- a/security/wazuh-manager/files/patch-src-data_provider-src_sysInfoFreeBSD.cpp +++ b/security/wazuh-manager/files/patch-src_data__provider_src-sysInfoFreeBSD.cpp @@ -1,434 +1,634 @@ ---- src/data_provider/src/sysInfoFreeBSD.cpp.orig 2025-11-07 04:46:03.000000000 -0400 -+++ src/data_provider/src/sysInfoFreeBSD.cpp 2026-01-06 19:37:15.309352000 -0400 -@@ -11,20 +11,28 @@ +--- src/data_provider/src/sysInfoFreeBSD.cpp 2025-11-07 08:46:03.000000000 +0000 ++++ src/data_provider/src/sysInfoFreeBSD.cpp 2026-01-14 16:59:37.014537000 +0000 +@@ -11,20 +11,33 @@ #include "sysInfo.hpp" #include "cmdHelper.h" #include "stringHelper.h" +#include "timeHelper.h" #include "osinfo/sysOsParsers.h" +#include "sqliteWrapperTemp.h" +#include "filesystemHelper.h" #include #include #include #include "sharedDefs.h" +#include ++#include "groups_freebsd.hpp" ++#include "user_groups_freebsd.hpp" ++#include "logged_in_users_freebsd.hpp" ++#include "sudoers_unix.hpp" ++#include "users_freebsd.hpp" +const std::string PKG_DB_PATHNAME {"/var/db/pkg/local.sqlite"}; +const std::string PKG_QUERY {"SELECT p.name, p.maintainer, p.version, p.arch, p.comment, p.flatsize, p.time, v.annotation AS repository,p.origin FROM packages p LEFT JOIN (SELECT pa.package_id, pa.value_id FROM pkg_annotation pa JOIN annotation t ON t.annotation_id = pa.tag_id AND t.annotation = 'repository') pr ON pr.package_id = p.id LEFT JOIN annotation v ON v.annotation_id = pr.value_id;"}; + static void getMemory(nlohmann::json& info) { + constexpr auto vmFree{"vm.stats.vm.v_free_count"}; + constexpr auto vmInactive{"vm.stats.vm.v_inactive_count"}; constexpr auto vmPageSize{"vm.stats.vm.v_page_size"}; - constexpr auto vmTotal{"vm.vmtotal"}; + constexpr auto vmTotal{"hw.physmem"}; uint64_t ram{0}; - const std::vector mib{CTL_HW, HW_PHYSMEM}; size_t len{sizeof(ram)}; - auto ret{sysctl(const_cast(mib.data()), mib.size(), &ram, &len, nullptr, 0)}; + auto ret{sysctlbyname(vmTotal, &ram, &len, nullptr, 0)}; if (ret) { -@@ -52,11 +60,23 @@ +@@ -52,11 +65,23 @@ }; } - struct vmtotal vmt {}; + uint64_t freeMem{0}; + len = sizeof(freeMem); + ret = sysctlbyname(vmFree, &freeMem, &len, nullptr, 0); - len = sizeof(vmt); + if (ret) + { + throw std::system_error + { + ret, + std::system_category(), + "Error reading free memory size." + }; + } - ret = sysctlbyname(vmTotal, &vmt, &len, nullptr, 0); + uint64_t inactiveMem{0}; + len = sizeof(inactiveMem); + ret = sysctlbyname(vmInactive, &inactiveMem, &len, nullptr, 0); if (ret) { -@@ -64,11 +84,11 @@ +@@ -64,11 +89,11 @@ { ret, std::system_category(), - "Error reading total memory." + "Error reading inactive memory size." }; } - const auto ramFree{(vmt.t_free * pageSize) / KByte}; + const auto ramFree{(freeMem + inactiveMem) * pageSize / KByte}; info["ram_free"] = ramFree; info["ram_usage"] = 100 - (100 * ramFree / ramTotal); } -@@ -96,7 +116,43 @@ +@@ -96,7 +121,43 @@ static std::string getSerialNumber() { - return UNKNOWN_VALUE; + size_t len{0}; + auto ret{sysctlbyname("kern.hostuuid", nullptr, &len, nullptr, 0)}; + + if (ret) + { + throw std::system_error + { + ret, + std::system_category(), + "Error reading serial number (aka hostuuid)." + }; + } + + const auto spBuff{std::make_unique(len + 1)}; + + if (!spBuff) + { + throw std::runtime_error + { + "Error allocating memory to read the serial number (aka hostuuid)." + }; + } + + ret = sysctlbyname("kern.hostuuid", spBuff.get(), &len, nullptr, 0); + + if (ret) + { + throw std::system_error + { + ret, + std::system_category(), + "Error reading serial number (aka hostuuid)." + }; + } + + spBuff.get()[len] = 0; + return std::string{reinterpret_cast(spBuff.get())}; } static int getCpuCores() -@@ -184,8 +240,12 @@ +@@ -184,8 +245,12 @@ nlohmann::json SysInfo::getProcessesInfo() const { - // Currently not supported for this OS - return nlohmann::json {}; + nlohmann::json ret; + getProcessesInfo([&ret](nlohmann::json & data) + { + ret.push_back(data); + }); + return ret; } nlohmann::json SysInfo::getOsInfo() const -@@ -196,11 +256,12 @@ +@@ -196,11 +261,12 @@ if (!spParser->parseUname(Utils::exec("uname -r"), ret)) { - ret["os_name"] = "BSD"; ret["os_platform"] = "bsd"; ret["os_version"] = UNKNOWN_VALUE; } + ret["os_name"] = "FreeBSD"; + if (uname(&uts) >= 0) { ret["sysname"] = uts.sysname; -@@ -215,44 +276,257 @@ +@@ -215,44 +281,260 @@ nlohmann::json SysInfo::getPorts() const { - // Currently not supported for this OS. - return nlohmann::json {}; -} + nlohmann::json ports {}; + + /* USER COMMAND PID FD PROTO LOCAL_ADDRESS FOREIGN_ADDRESS PATH_STATE CONN_STATE */ + +#if __FreeBSD_version > 1500045 + const auto query{exec(R"(sockstat -46qs --libxo json)")}; -void SysInfo::getProcessesInfo(std::function /*callback*/) const -{ - // Currently not supported for this OS. --} + if (!query.empty()) + { + nlohmann::json portsjson; + portsjson = nlohmann::json::parse(query); + auto &portsResult = portsjson["sockstat"]["socket"]; - --void SysInfo::getPackages(std::function callback) const --{ -- const auto query{Utils::exec(R"(pkg query -a "%n|%m|%v|%q|%c")")}; ++ + for(auto &port : portsResult) { + std::string localip = ""; + std::string localport = ""; + std::string remoteip = ""; + std::string remoteport = ""; + std::string statedata = ""; - ++ + if (port["pid"] != nullptr) { + + localip = port["local"]["address"]; + remoteip = port["foreign"]["address"]; + statedata = port["conn-state"] != nullptr ? (port["conn-state"] == "LISTEN" ? "listening" : Utils::toLowerCase(port["conn-state"])) : statedata; + + if (port["local"]["address"] == "*") { + if ((port["proto"] == "udp4") || (port["proto"] == "tcp4")) { + localip = "0.0.0.0"; + } else { + localip = "::"; + } + } + + localport = port["local"]["port"]; + + if (port["foreign"]["address"] == "*") { + if ((port["proto"] == "udp4") || (port["proto"] == "tcp4")) { + remoteip = 0.0.0.0; + } else { + remoteip = "::"; + } + } + + remoteport = port["foreign"]["port"]; + + nlohmann::json portRecord {}; + + portRecord["protocol"] = port["proto"]; + portRecord["local_ip"] = localip; + portRecord["local_port"] = localport == "*" ? "0" : localport; + portRecord["remote_ip"] = remoteip; + portRecord["remote_port"] = remoteport == "*" ? "0" : remoteport; + portRecord["tx_queue"] = 0; + portRecord["rx_queue"] = 0; + portRecord["inode"] = port["fd"]; + portRecord["state"] = statedata == "??" ? "" : statedata; + portRecord["pid"] = port["pid"]; + portRecord["process"] = port["command"]; + + ports.push_back(portRecord); + } + } + } +#else + const auto query{Utils::exec(R"(sockstat -46qs)")}; + - if (!query.empty()) - { -- const auto lines{Utils::split(query, '\n')}; ++ if (!query.empty()) ++ { + const auto lines{Utils::split(Utils::trimToOneSpace(query), '\n')}; - ++ + std::regex expression(R"(^(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s*(\S+)\s+(\S+)\s+(\S+)(?:\s+(\S+))?\s*$)"); + - for (const auto& line : lines) - { -- const auto data{Utils::split(line, '|')}; -- nlohmann::json package; ++ for (const auto& line : lines) ++ { + std::smatch data; - -- package["name"] = data[0]; -- package["vendor"] = data[1]; -- package["version"] = data[2]; -- package["install_time"] = UNKNOWN_VALUE; -- package["location"] = UNKNOWN_VALUE; -- package["architecture"] = data[3]; -- package["groups"] = UNKNOWN_VALUE; -- package["description"] = data[4]; -- package["size"] = 0; -- package["priority"] = UNKNOWN_VALUE; -- package["source"] = UNKNOWN_VALUE; -- package["format"] = "pkg"; -- // The multiarch field won't have a default value ++ + if (std::regex_search(line, data, expression)) + { + std::string localip = ""; + std::string localport = ""; + std::string remoteip = ""; + std::string remoteport = ""; + std::string statedata = ""; - -- callback(package); ++ + auto localdata{Utils::split(data[6], ':')}; + auto remotedata{Utils::split(data[7], ':')}; + + if (data[8].matched ) { + statedata = data[8] == "LISTEN" ? "listening" : Utils::toLowerCase(data[8]); + } + + localport = localdata[localdata.size() - 1]; + localdata.pop_back(); + localip = Utils::join(localdata, ":"); + remoteport = remotedata[remotedata.size() - 1]; + remotedata.pop_back(); + remoteip = Utils::join(remotedata, ":"); + + if(localip == "*") { + if((data[5] == "tcp4") || (data[5] == "udp4")) { + localip = "0.0.0.0"; + } else { + localip = "::"; + } + } + + if(remoteip == "*") { + if((data[5] == "tcp4") || (data[5] == "udp4")) { + remoteip = "0.0.0.0"; + } else { + remoteip = "::"; + } + } + + if(data[0] != "?") { + nlohmann::json port {}; + + port["protocol"] = data[5]; + port["local_ip"] = localip; + port["local_port"] = localport == "*" ? "0" : localport; + port["remote_ip"] = remoteip; + port["remote_port"] = remoteport == "*" ? "0" : remoteport; + port["tx_queue"] = 0; + port["rx_queue"] = 0; + port["inode"] = data[4]; + port["state"] = statedata == "??" ? "" : statedata; + port["pid"] = data[3]; + port["process"] = data[2]; + + ports.push_back(port); + } + } + } + } +#endif + return ports; -+} -+ + } + +-void SysInfo::getPackages(std::function callback) const +void SysInfo::getProcessesInfo(std::function callback) const -+{ + { +- const auto query{Utils::exec(R"(pkg query -a "%n|%m|%v|%q|%c")")}; + const auto query{Utils::exec(R"(ps -ax -w -o pid,comm,state,ppid,usertime,systime,user,ruser,svuid,group,rgroup,svgid,pri,nice,ssiz,vsz,rss,pmem,etimes,sid,pgid,tpgid,tty,cpu,nlwp,args --libxo json)")}; -+ -+ if (!query.empty()) -+ { + + if (!query.empty()) + { +- const auto lines{Utils::split(query, '\n')}; + nlohmann::json psjson; ++ int64_t agenttime = {Utils::getSecondsFromEpoch()}; ++ int64_t etimes{0}; + psjson = nlohmann::json::parse(query); + auto &processes = psjson["process-information"]["process"]; -+ + +- for (const auto& line : lines) + for(auto &process : processes) { + std::string user_time{""}; + std::string system_time{""}; ++ etimes = std::stoll(process["elapsed-times"].get()); + + user_time = process["user-time"].get(); + system_time = process["system-time"].get(); + + nlohmann::json jsProcessInfo{}; + jsProcessInfo["pid"] = process["pid"].get(); + jsProcessInfo["name"] = process["command"].get(); + jsProcessInfo["state"] = process["state"].get(); + jsProcessInfo["ppid"] = process["ppid"].get(); + jsProcessInfo["utime"] = Utils::timeToSeconds(user_time); + jsProcessInfo["stime"] = Utils::timeToSeconds(system_time); + jsProcessInfo["cmd"] = process["command"].get(); + jsProcessInfo["argvs"] = process["arguments"].get(); + jsProcessInfo["euser"] = process["user"].get(); + jsProcessInfo["ruser"] = process["real-user"].get(); + jsProcessInfo["suser"] = process["saved-uid"].get(); + jsProcessInfo["egroup"] = process["group"].get(); + jsProcessInfo["rgroup"] = process["real-group"].get(); + jsProcessInfo["sgroup"] = process["saved-gid"].get(); + jsProcessInfo["fgroup"] = process["group"].get(); + jsProcessInfo["priority"] = process["priority"].get(); + jsProcessInfo["nice"] = process["nice"].get(); + jsProcessInfo["size"] = process["stack-size"].get(); + jsProcessInfo["vm_size"] = process["virtual-size"].get(); + jsProcessInfo["resident"] = process["rss"].get(); + //jsProcessInfo["share"] = process["percent-memory"].get(); -+ jsProcessInfo["start_time"] = process["elapsed-times"].get() == "-" ? "0" : process["elapsed-times"].get(); ++ jsProcessInfo["start_time"] = agenttime - etimes; + jsProcessInfo["pgrp"] = process["process-group"].get(); + jsProcessInfo["session"] = process["sid"].get(); + jsProcessInfo["tgid"] = process["terminal-process-gid"].get(); + //jsProcessInfo["tty"] = process["tty"].get(); // this field should be TEXT into local.db + jsProcessInfo["processor"] = process["on-cpu"].get(); + jsProcessInfo["nlwp"] = process["threads"].get(); + + callback(jsProcessInfo); + } + } +} + +void SysInfo::getPackages(std::function callback) const +{ + if (Utils::existsRegular(PKG_DB_PATHNAME)) + { + try -+ { + { +- const auto data{Utils::split(line, '|')}; +- nlohmann::json package; + std::shared_ptr sqliteConnection = std::make_shared(PKG_DB_PATHNAME, SQLITE_OPEN_READONLY); -+ + +- package["name"] = data[0]; +- package["vendor"] = data[1]; +- package["version"] = data[2]; +- package["install_time"] = UNKNOWN_VALUE; +- package["location"] = UNKNOWN_VALUE; +- package["architecture"] = data[3]; +- package["groups"] = UNKNOWN_VALUE; +- package["description"] = data[4]; +- package["size"] = 0; +- package["priority"] = UNKNOWN_VALUE; +- package["source"] = UNKNOWN_VALUE; +- package["format"] = "pkg"; +- // The multiarch field won't have a default value + SQLite::Statement stmt + { + sqliteConnection, + PKG_QUERY + }; -+ + +- callback(package); + while (SQLITE_ROW == stmt.step()) + { + try + { + auto pkg_name{ stmt.column(0) }; + auto pkg_maintainer{ stmt.column(1) }; + auto pkg_version{ stmt.column(2) }; + auto pkg_arch{ stmt.column(3) }; + auto pkg_comment{ stmt.column(4) }; + auto pkg_flatsize{ stmt.column(5) }; + auto pkg_time{ stmt.column(6) }; + auto pkg_repository{ stmt.column(7) }; + auto pkg_origin{ stmt.column(8) }; + + const auto archdata{Utils::split(pkg_arch->value(std::string{}), ':')}; + const auto sectiondata{Utils::split(pkg_origin->value(std::string{}), '/')}; + + nlohmann::json package; + + package["name"] = pkg_name->value(std::string{}); + package["vendor"] = pkg_maintainer->value(std::string{}); + package["version"] = pkg_version->value(std::string{}); + package["install_time"] = pkg_time->value(std::string{}); + package["location"] = UNKNOWN_VALUE; + package["architecture"] = archdata[2]; + package["groups"] = UNKNOWN_VALUE; + package["description"] = pkg_comment->value(std::string{}); + package["size"] = pkg_flatsize->value(uint64_t{}); + package["priority"] = UNKNOWN_VALUE; + package["source"] = pkg_repository->value(std::string{}); + package["section"] = sectiondata[0]; + package["format"] = "pkg"; + // The multiarch field won't have a default value + + callback(package); + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } + } } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + } } } +@@ -264,14 +546,188 @@ + + nlohmann::json SysInfo::getGroups() const + { +- //TODO: Pending implementation. +- return nlohmann::json(); ++ nlohmann::json result; ++ GroupsProvider groupsProvider; ++ UserGroupsProvider userGroupsProvider; ++ ++ auto collectedGroups = groupsProvider.collect({}); ++ ++ for (auto& group : collectedGroups) ++ { ++ nlohmann::json groupItem {}; ++ ++ groupItem["group_id"] = group["gid"]; ++ groupItem["group_name"] = (group.contains("groupname") && !group["groupname"].get().empty()) ? group["groupname"] : UNKNOWN_VALUE; ++ groupItem["group_description"] = UNKNOWN_VALUE; ++ groupItem["group_id_signed"] = group["gid_signed"]; ++ groupItem["group_uuid"] = UNKNOWN_VALUE; ++ groupItem["group_is_hidden"] = 0; ++ ++ std::set gids {static_cast(group["gid"].get())}; ++ auto collectedUsersGroups = userGroupsProvider.getUserNamesByGid(gids); ++ ++ if (collectedUsersGroups.empty()) ++ { ++ groupItem["group_users"] = UNKNOWN_VALUE; ++ } ++ else ++ { ++ std::string usersConcatenated; ++ ++ for (const auto& user : collectedUsersGroups) ++ { ++ if (!usersConcatenated.empty()) ++ { ++ usersConcatenated += secondaryArraySeparator; ++ } ++ ++ usersConcatenated += user.get(); ++ } ++ ++ groupItem["group_users"] = usersConcatenated; ++ } ++ ++ result.push_back(std::move(groupItem)); ++ ++ } ++ ++ return result; + } + + nlohmann::json SysInfo::getUsers() const + { +- //TODO: Pending implementation. +- return nlohmann::json(); ++ nlohmann::json result; ++ ++ UsersProvider usersProvider; ++ auto collectedUsers = usersProvider.collect(); ++ ++ LoggedInUsersProvider loggedInUserProvider; ++ auto collectedLoggedInUser = loggedInUserProvider.collect(); ++ ++ UserGroupsProvider userGroupsProvider; ++ ++ for (auto& user : collectedUsers) ++ { ++ nlohmann::json userItem {}; ++ ++ std::string username = (user.contains("username") && !user["username"].get().empty()) ? user["username"] : UNKNOWN_VALUE; ++ ++ userItem["user_id"] = user["uid"]; ++ userItem["user_full_name"] = user["description"]; ++ userItem["user_home"] = user["directory"]; ++ userItem["user_is_remote"] = user["include_remote"]; ++ userItem["user_name"] = username; ++ userItem["user_shell"] = user["shell"]; ++ userItem["user_uid_signed"] = user["uid_signed"]; ++ userItem["user_group_id_signed"] = user["gid_signed"]; ++ userItem["user_group_id"] = user["gid"]; ++ ++ std::set uid {static_cast(user["uid"].get())}; ++ auto collectedUsersGroups = userGroupsProvider.getGroupNamesByUid(uid); ++ ++ if (collectedUsersGroups.empty()) ++ { ++ userItem["user_groups"] = UNKNOWN_VALUE; ++ } ++ else ++ { ++ std::string accumGroups; ++ ++ for (const auto& group : collectedUsersGroups) ++ { ++ if (!accumGroups.empty()) ++ { ++ accumGroups += secondaryArraySeparator; ++ } ++ ++ accumGroups += group.get(); ++ } ++ ++ userItem["user_groups"] = accumGroups; ++ } ++ ++ // Only in windows ++ userItem["user_type"] = UNKNOWN_VALUE; ++ ++ // Macos or windows ++ userItem["user_uuid"] = UNKNOWN_VALUE; ++ ++ // Macos ++ userItem["user_is_hidden"] = 0; ++ userItem["user_created"] = 0; ++ userItem["user_auth_failed_count"] = 0; ++ userItem["user_auth_failed_timestamp"] = 0; ++ ++ auto matched = false; ++ auto lastLogin = 0; ++ ++ userItem["host_ip"] = UNKNOWN_VALUE; ++ ++ //TODO: Avoid this iteration, move logic to LoggedInUsersProvider ++ for (auto& item : collectedLoggedInUser) ++ { ++ // By default, user is not logged in. ++ userItem["login_status"] = 0; ++ ++ // tty,host,time and pid can take more than one value due to different logins. ++ if (item["user"] == username) ++ { ++ matched = true; ++ userItem["login_status"] = 1; ++ ++ auto newDate = item["time"].get(); ++ ++ if (newDate > lastLogin) ++ { ++ lastLogin = newDate; ++ userItem["user_last_login"] = newDate; ++ userItem["login_tty"] = item["tty"].get(); ++ userItem["login_type"] = item["type"].get(); ++ userItem["process_pid"] = item["pid"].get(); ++ } ++ ++ const auto& hostStr = item["host"].get_ref(); ++ ++ if (!hostStr.empty()) ++ { ++ userItem["host_ip"] = userItem["host_ip"].get() == UNKNOWN_VALUE ++ ? hostStr ++ : (userItem["host_ip"].get() + primaryArraySeparator + hostStr); ++ } ++ } ++ } ++ ++ if (!matched) ++ { ++ userItem["login_status"] = 0; ++ userItem["login_tty"] = UNKNOWN_VALUE; ++ userItem["login_type"] = UNKNOWN_VALUE; ++ userItem["process_pid"] = 0; ++ userItem["user_last_login"] = 0; ++ } ++ ++ matched = false; ++ ++ if (!matched) ++ { ++ userItem["user_password_expiration_date"] = 0; ++ userItem["user_password_hash_algorithm"] = UNKNOWN_VALUE; ++ userItem["user_password_inactive_days"] = 0; ++ userItem["user_password_last_change"] = 0; ++ userItem["user_password_max_days_between_changes"] = 0; ++ userItem["user_password_min_days_between_changes"] = 0; ++ userItem["user_password_status"] = UNKNOWN_VALUE; ++ userItem["user_password_warning_days_before_expiration"] = 0; ++ } ++ ++ ++ // By default, user is not sudoer. ++ userItem["user_roles"] = UNKNOWN_VALUE; ++ ++ result.push_back(std::move(userItem)); ++ } ++ ++ return result; + } + + nlohmann::json SysInfo::getServices() const diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources-CMakeLists.txt b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources-CMakeLists.txt new file mode 100644 index 000000000000..458b05f1655e --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources-CMakeLists.txt @@ -0,0 +1,18 @@ +--- src/data_provider/src/extended_sources/CMakeLists.txt 2025-11-07 08:46:03.000000000 +0000 ++++ src/data_provider/src/extended_sources/CMakeLists.txt 2026-01-13 15:00:46.789677000 +0000 +@@ -1,6 +1,11 @@ + include_directories(wrappers) + +-add_subdirectory(groups) +-add_subdirectory(services) +-add_subdirectory(users) +-add_subdirectory(browser_extensions) ++if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ add_subdirectory(groups) ++ add_subdirectory(users) ++else() ++ add_subdirectory(groups) ++ add_subdirectory(services) ++ add_subdirectory(users) ++ add_subdirectory(browser_extensions) ++endif() diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups-CMakeLists.txt b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups-CMakeLists.txt new file mode 100644 index 000000000000..0f34a531e850 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups-CMakeLists.txt @@ -0,0 +1,22 @@ +--- src/data_provider/src/extended_sources/groups/CMakeLists.txt 2026-01-13 15:01:19.871247000 +0000 ++++ src/data_provider/src/extended_sources/groups/CMakeLists.txt 2026-01-13 15:07:52.828437000 +0000 +@@ -18,6 +18,8 @@ + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/linux) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/darwin) ++ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/freebsd) + endif() + endif() + +@@ -35,6 +37,10 @@ + list(APPEND SRC_FILES + src/groups_linux.cpp + src/user_groups_linux.cpp) ++ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ list(APPEND SRC_FILES ++ src/groups_freebsd.cpp ++ src/user_groups_freebsd.cpp) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + find_library(OPEN_DIRECTORY OpenDirectory) + find_library(FOUNDATION Foundation) diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups_include-groups_freebsd.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups_include-groups_freebsd.hpp new file mode 100644 index 000000000000..a756e0bb02f7 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups_include-groups_freebsd.hpp @@ -0,0 +1,46 @@ +--- /dev/null 2026-01-13 23:10:56.926889000 +0000 ++++ src/data_provider/src/extended_sources/groups/include/groups_freebsd.hpp 2026-01-13 22:43:51.149789000 +0000 +@@ -0,0 +1,43 @@ ++/* 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. ++ */ ++ ++#pragma once ++ ++#include ++ ++#include "json.hpp" ++#include "igroup_wrapper.hpp" ++ ++/// @brief Class for collecting group information on FreeBSD systems. ++/// ++/// This class provides methods to collect group information from the ++/// Darwin operating system. It uses the system's group database to retrieve ++/// group details such as group name and GID. The collected data is returned ++/// in JSON format. ++class GroupsProvider ++{ ++ public: ++ explicit GroupsProvider(std::shared_ptr groupWrapper); ++ ++ /// @brief Default destructor. ++ GroupsProvider(); ++ ++ /// @brief Collects group information based on provided group IDs. ++ /// @param gids A set of group IDs to collect information for. ++ /// @return A JSON array containing group information. ++ nlohmann::json collect(const std::set& gids = {}); ++ ++ private: ++ std::shared_ptr m_groupWrapper; ++ ++ /// @brief Adds a group to the results JSON array. ++ /// @param results A reference to the JSON array where the group information will be added. ++ /// @param group A pointer to the group structure containing the group information. ++ void addGroupToResults(nlohmann::json& results, const struct group* group); ++}; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups_include-user_groups_freebsd.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups_include-user_groups_freebsd.hpp new file mode 100644 index 000000000000..3fdc455fed39 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_groups_include-user_groups_freebsd.hpp @@ -0,0 +1,84 @@ +--- /dev/null 2026-01-13 23:11:31.853795000 +0000 ++++ src/data_provider/src/extended_sources/groups/include/user_groups_freebsd.hpp 2026-01-13 22:43:51.149735000 +0000 +@@ -0,0 +1,81 @@ ++/* 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. ++ */ ++ ++#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-manager/files/patch-src_data__provider_src_extended__sources_groups_src-groups_freebsd.hpp b/security/wazuh-manager/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-manager/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-manager/files/patch-src_data__provider_src_extended__sources_groups_src-user_groups_freebsd.hpp b/security/wazuh-manager/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-manager/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); ++ ++ if (m_groupWrapper->getgrgid_r(gid, &grp, groupBuf.get(), bufSize, &grpResult) == 0 && grpResult != nullptr) ++ { ++ char** members = grpResult->gr_mem; ++ ++ while (members && *members) ++ { ++ gidToUsernames[gid].insert(*members); ++ ++members; ++ } ++ } ++ } ++ } ++ ++ struct passwd* pwd = nullptr; ++ ++ m_passwdWrapper->setpwent(); ++ ++ while ((pwd = m_passwdWrapper->getpwent()) != nullptr) ++ { ++ if (allGroups || gids.count(pwd->pw_gid)) ++ { ++ gidToUsernames[pwd->pw_gid].insert(pwd->pw_name); ++ } ++ } ++ ++ m_passwdWrapper->endpwent(); ++ ++ for (const auto& [gid, usernames] : gidToUsernames) ++ { ++ nlohmann::json jsonUsernames = nlohmann::json::array(); ++ ++ for (const auto& name : usernames) ++ { ++ jsonUsernames.push_back(name); ++ } ++ ++ if (singleGid) ++ { ++ result = jsonUsernames; ++ } ++ else ++ { ++ result[std::to_string(gid)] = jsonUsernames; ++ } ++ } ++ ++ return result; ++} ++ ++std::vector>> UserGroupsProvider::getUserGroups(const std::set& uids) ++{ ++ std::vector>> userGroups; ++ struct passwd pwd; ++ struct passwd* pwdResults = nullptr; ++ ++ size_t bufSize = sysconf(_SC_GETPW_R_SIZE_MAX); ++ ++ if (bufSize > MAX_GETPW_R_BUF_SIZE) ++ { ++ bufSize = MAX_GETPW_R_BUF_SIZE; ++ } ++ ++ auto buf = std::make_unique(bufSize); ++ ++ auto processUser = [&](const struct passwd * pwdInfo) ++ { ++ UserInfo user {pwdInfo->pw_name, pwdInfo->pw_uid, pwdInfo->pw_gid}; ++ ++ std::vector groups(EXPECTED_GROUPS_MAX); ++ int nGroups = EXPECTED_GROUPS_MAX; ++ ++ if (m_groupWrapper->getgrouplist(user.name, user.gid, groups.data(), &nGroups) < 0) ++ { ++ groups.resize(nGroups); ++ ++ if (m_groupWrapper->getgrouplist(user.name, user.gid, groups.data(), &nGroups) < 0) ++ { ++ // std::cerr << "Could not get user's group list" << std::endl; ++ return; ++ } ++ ++ groups.resize(nGroups); ++ } ++ else ++ { ++ groups.resize(nGroups); ++ } ++ ++ userGroups.emplace_back(user.uid, std::move(groups)); ++ }; ++ ++ if (!uids.empty()) ++ { ++ for (const auto& uid : uids) ++ { ++ if (m_passwdWrapper->getpwuid_r(uid, &pwd, buf.get(), bufSize, &pwdResults) == 0 && pwdResults != nullptr) ++ { ++ processUser(pwdResults); ++ } ++ } ++ } ++ else ++ { ++ std::set processed_uids; ++ m_passwdWrapper->setpwent(); ++ ++ while (m_passwdWrapper->getpwent_r(&pwd, buf.get(), bufSize, &pwdResults) == 0 && pwdResults != nullptr) ++ { ++ if (processed_uids.insert(pwdResults->pw_uid).second) ++ { ++ processUser(pwdResults); ++ } ++ } ++ ++ m_passwdWrapper->endpwent(); ++ } ++ ++ return userGroups; ++} ++ ++void UserGroupsProvider::addGroupsToResults(nlohmann::json& results, uid_t uid, const gid_t* groups, int nGroups) ++{ ++ for (int i = 0; i < nGroups; i++) ++ { ++ nlohmann::json groupJson; ++ ++ groupJson["uid"] = uid; ++ groupJson["gid"] = groups[i]; ++ ++ results.push_back(groupJson); ++ } ++} diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users-CMakeLists.txt b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users-CMakeLists.txt new file mode 100644 index 000000000000..2dc3067c5068 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users-CMakeLists.txt @@ -0,0 +1,21 @@ +--- src/data_provider/src/extended_sources/users/CMakeLists.txt 2025-11-07 08:46:03.000000000 +0000 ++++ src/data_provider/src/extended_sources/users/CMakeLists.txt 2026-01-12 14:53:32.100182000 +0000 +@@ -18,6 +18,8 @@ + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/linux) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/darwin) ++ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/freebsd) + endif() + endif() + +@@ -40,6 +42,9 @@ + + list(APPEND SRC_FILES src/users_darwin.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../wrappers/unix/darwin/od_wrapper.mm) + set(PLATFORM_LIBS_USERS ${OPEN_DIRECTORY} ${FOUNDATION}) ++ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ list(APPEND SRC_FILES src/logged_in_users_freebsd.cpp) ++ list(APPEND SRC_FILES src/users_freebsd.cpp) + endif() + endif() + diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_include-logged_in_users_freebsd.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_include-logged_in_users_freebsd.hpp new file mode 100644 index 000000000000..83195510bddb --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_include-logged_in_users_freebsd.hpp @@ -0,0 +1,37 @@ +--- /dev/null 2026-01-13 23:08:55.189229000 +0000 ++++ src/data_provider/src/extended_sources/users/include/logged_in_users_freebsd.hpp 2026-01-13 22:43:51.148959000 +0000 +@@ -0,0 +1,34 @@ ++/* 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. ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++#include ++ ++#include "json.hpp" ++#include "iutmpx_wrapper.hpp" ++ ++class LoggedInUsersProvider ++{ ++ public: ++ explicit LoggedInUsersProvider(std::shared_ptr utmpxWrapper); ++ ++ LoggedInUsersProvider(); ++ ++ nlohmann::json collect(); ++ ++ private: ++ std::shared_ptr m_utmpxWrapper; ++ ++ static std::mutex utmpxMutex; ++ static const std::map loginTypes; ++}; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_include-users_freebsd.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_include-users_freebsd.hpp new file mode 100644 index 000000000000..f6884ce8f1fc --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_include-users_freebsd.hpp @@ -0,0 +1,69 @@ +--- /dev/null 2026-01-13 23:09:49.988051000 +0000 ++++ src/data_provider/src/extended_sources/users/include/users_freebsd.hpp 2026-01-13 22:43:51.149043000 +0000 +@@ -0,0 +1,66 @@ ++/* 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 ++#include ++ ++#include "json.hpp" ++ ++#include "ipasswd_wrapper.hpp" ++ ++/// @brief Provides user information on FreeBSD systems. ++/// ++/// Collects user data by combining information from the passwd database, ++/// ++/// Dependencies are injected via wrappers for testability and abstraction. ++class UsersProvider ++{ ++ public: ++ /// @brief Constructs a UsersProvider with the given wrappers. ++ /// @param passwdWrapper Wrapper for password database operations. ++ /// @param sysWrapper Wrapper for system-level operations. ++ explicit UsersProvider( ++ std::shared_ptr passwdWrapper); ++ ++ /// @brief Default constructor. ++ UsersProvider(); ++ ++ /// @brief Collects all user information, optionally including remote users. ++ /// @param include_remote Whether to include remote users in the collection (default: true). ++ /// @return JSON array of user information objects. ++ nlohmann::json collect(bool include_remote = true); ++ ++ /// @brief Collects user information filtered by usernames and UIDs, optionally including remote users. ++ /// @param usernames Set of usernames to filter. ++ /// @param uids Set of UIDs to filter. ++ /// @param include_remote Whether to include remote users in the collection. ++ /// @return JSON array of user information objects matching the constraints. ++ nlohmann::json collectWithConstraints(const std::set& usernames, ++ const std::set& uids, ++ bool include_remote); ++ ++ private: ++ /// @brief Generates a JSON representation of a user from passwd struct. ++ /// @param pwd Pointer to passwd struct representing the user. ++ /// @param include_remote Boolean indicating whether remote users are included. ++ /// @return JSON object representing the user. ++ nlohmann::json genUserJson(const struct passwd* pwd, bool include_remote); ++ ++ /// @brief Collects local users filtered by usernames and UIDs. ++ /// @param usernames Set of usernames to filter. ++ /// @param uids Set of UIDs to filter. ++ /// @return JSON array of local user information. ++ nlohmann::json collectUsers(const std::set& usernames, ++ const std::set& uids); ++ ++ /// @brief Passwd wrapper dependency. ++ std::shared_ptr m_passwdWrapper; ++}; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_src-logged_in_users_freebsd.cpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_src-logged_in_users_freebsd.cpp new file mode 100644 index 000000000000..d5359d1524b8 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_src-logged_in_users_freebsd.cpp @@ -0,0 +1,72 @@ +--- /dev/null 2026-01-13 23:08:16.219538000 +0000 ++++ src/data_provider/src/extended_sources/users/src/logged_in_users_freebsd.cpp 2026-01-13 22:43:51.148867000 +0000 +@@ -0,0 +1,69 @@ ++/* 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 "logged_in_users_freebsd.hpp" ++#include "utmpx_wrapper.hpp" ++ ++#include ++#include ++ ++#include ++#include ++ ++std::mutex LoggedInUsersProvider::utmpxMutex; ++ ++const std::map LoggedInUsersProvider::loginTypes = ++{ ++ {EMPTY, "empty"}, ++ {BOOT_TIME, "boot_time"}, ++ {NEW_TIME, "new_time"}, ++ {OLD_TIME, "old_time"}, ++ {INIT_PROCESS, "init"}, ++ {LOGIN_PROCESS, "login"}, ++ {USER_PROCESS, "user"}, ++ {DEAD_PROCESS, "dead"}, ++}; ++ ++LoggedInUsersProvider::LoggedInUsersProvider(std::shared_ptr wrapper) ++ : m_utmpxWrapper(std::move(wrapper)) {} ++ ++LoggedInUsersProvider::LoggedInUsersProvider() ++ : m_utmpxWrapper(std::make_shared()) {} ++ ++nlohmann::json LoggedInUsersProvider::collect() ++{ ++ std::lock_guard lock(utmpxMutex); ++ nlohmann::json results = nlohmann::json::array(); ++ struct utmpx* entry = nullptr; ++ ++ m_utmpxWrapper->setutxent(); ++ ++ while ((entry = m_utmpxWrapper->getutxent()) != nullptr) ++ { ++ if (entry->ut_pid == 1) ++ { ++ continue; ++ } ++ ++ nlohmann::json row; ++ auto it = loginTypes.find(entry->ut_type); ++ row["type"] = (it != loginTypes.end()) ? it->second : "unknown"; ++ ++ row["user"] = std::string(entry->ut_user, strnlen(entry->ut_user, sizeof(entry->ut_user))); ++ row["tty"] = std::string(entry->ut_line, strnlen(entry->ut_line, sizeof(entry->ut_line))); ++ row["host"] = std::string(entry->ut_host, strnlen(entry->ut_host, sizeof(entry->ut_host))); ++ row["time"] = entry->ut_tv.tv_sec; ++ row["pid"] = entry->ut_pid; ++ ++ results.push_back(std::move(row)); ++ } ++ ++ m_utmpxWrapper->endutxent(); ++ return results; ++} diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_src-users_freebsd.cpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_src-users_freebsd.cpp new file mode 100644 index 000000000000..195be19ed3a9 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_users_src-users_freebsd.cpp @@ -0,0 +1,106 @@ +--- /dev/null 2026-01-13 23:07:27.483265000 +0000 ++++ src/data_provider/src/extended_sources/users/src/users_freebsd.cpp 2026-01-13 22:53:15.807751000 +0000 +@@ -0,0 +1,103 @@ ++/* 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 ++#include ++#include ++ ++#include "users_freebsd.hpp" ++#include "passwd_wrapper.hpp" ++ ++constexpr size_t MAX_GETPW_R_BUF_SIZE = 16 * 1024; ++ ++UsersProvider::UsersProvider( ++ std::shared_ptr passwdWrapper) ++ : m_passwdWrapper(std::move(passwdWrapper)) {} ++ ++UsersProvider::UsersProvider() ++ : m_passwdWrapper(std::make_shared()) {} ++ ++nlohmann::json UsersProvider::collect(bool include_remote) ++{ ++ return collectWithConstraints({}, {}, include_remote); ++} ++ ++nlohmann::json UsersProvider::collectWithConstraints(const std::set& usernames, ++ const std::set& uids, ++ bool include_remote) ++{ ++// if (include_remote) ++// { ++// return collectRemoteUsers(usernames, uids); ++// } ++ ++ return collectUsers(usernames, uids); ++} ++ ++nlohmann::json UsersProvider::genUserJson(const struct passwd* pwd, bool include_remote) ++{ ++ nlohmann::json r; ++ r["uid"] = pwd->pw_uid; ++ r["gid"] = pwd->pw_gid; ++ r["uid_signed"] = static_cast(pwd->pw_uid); ++ r["gid_signed"] = static_cast(pwd->pw_gid); ++ ++ r["username"] = (pwd->pw_name != nullptr) ? pwd->pw_name : ""; ++ r["description"] = (pwd->pw_gecos != nullptr) ? pwd->pw_gecos : ""; ++ r["directory"] = (pwd->pw_dir != nullptr) ? pwd->pw_dir : ""; ++ r["shell"] = (pwd->pw_shell != nullptr) ? pwd->pw_shell : ""; ++ ++ r["pid_with_namespace"] = "0"; ++ r["include_remote"] = static_cast(include_remote); ++ ++ return r; ++} ++ ++nlohmann::json UsersProvider::collectUsers(const std::set& usernames, ++ const std::set& uids) ++{ ++ nlohmann::json results = nlohmann::json::array(); ++ ++ size_t bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); ++ ++ if (bufsize > MAX_GETPW_R_BUF_SIZE) ++ { ++ bufsize = MAX_GETPW_R_BUF_SIZE; ++ } ++ ++ auto buf = std::make_unique(bufsize); ++ ++ struct passwd pwd; ++ struct passwd* pwd_results ++ { ++ nullptr ++ }; ++ ++ m_passwdWrapper->setpwent(); ++ ++ while (m_passwdWrapper->getpwent_r(&pwd, buf.get(), bufsize, &pwd_results) == 0 && pwd_results != nullptr) ++ { ++ if (!usernames.empty() && usernames.find(pwd_results->pw_name) == usernames.end()) ++ { ++ continue; ++ } ++ else if (!uids.empty() && uids.find(pwd_results->pw_uid) == uids.end()) ++ { ++ continue; ++ } ++ ++ results.push_back(genUserJson(pwd_results, true)); ++ } ++ ++ m_passwdWrapper->endpwent(); ++ ++ return results; ++} diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix-iutmpx_wrapper.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix-iutmpx_wrapper.hpp new file mode 100644 index 000000000000..2f646ad8c1d6 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix-iutmpx_wrapper.hpp @@ -0,0 +1,12 @@ +--- src/data_provider/src/extended_sources/wrappers/unix/iutmpx_wrapper.hpp 2025-11-07 08:46:03.000000000 +0000 ++++ src/data_provider/src/extended_sources/wrappers/unix/iutmpx_wrapper.hpp 2026-01-12 14:51:47.552260000 +0000 +@@ -20,7 +20,9 @@ + + /// @brief Sets the utmpx file to be used by the library functions. + /// @param file Path to the utmpx file. ++#if !defined(__FreeBSD__) + virtual void utmpxname(const char* file) = 0; ++#endif + + /// @brief Resets the input stream to the beginning of the utmpx file. + virtual void setutxent() = 0; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix-utmpx_wrapper.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix-utmpx_wrapper.hpp new file mode 100644 index 000000000000..edf75f578f7b --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix-utmpx_wrapper.hpp @@ -0,0 +1,16 @@ +--- src/data_provider/src/extended_sources/wrappers/unix/utmpx_wrapper.hpp 2025-11-07 08:46:03.000000000 +0000 ++++ src/data_provider/src/extended_sources/wrappers/unix/utmpx_wrapper.hpp 2026-01-12 14:51:47.552488000 +0000 +@@ -18,11 +18,12 @@ + public: + /// @brief Sets the utmpx file to be used by the library functions. + /// @param file Path to the utmpx file. ++#if !defined(__FreeBSD__) + void utmpxname(const char* file) override + { + ::utmpxname(file); + } +- ++#endif + /// @brief Resets the input stream to the beginning of the utmpx file. + void setutxent() override + { diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-group_wrapper.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-group_wrapper.hpp new file mode 100644 index 000000000000..57202254a120 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-group_wrapper.hpp @@ -0,0 +1,93 @@ +--- /dev/null 2026-01-13 23:16:40.390101000 +0000 ++++ src/data_provider/src/extended_sources/wrappers/unix/freebsd/group_wrapper.hpp 2026-01-13 22:43:51.149572000 +0000 +@@ -0,0 +1,90 @@ ++/* 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. ++ */ ++ ++#pragma once ++ ++#include "igroup_wrapper.hpp" ++ ++#include ++#include ++ ++/// @brief Wrapper class for group-related operations on FreeBSD systems. ++/// ++/// Provides methods to retrieve group lists and counts for users, allowing for dependency injection ++/// and easier testing. This class implements the IGroupWrapperFreeBSD interface and uses the system calls ++/// to interact with the group database. ++class GroupWrapperFreeBSD : public IGroupWrapperFreeBSD ++{ ++ public: ++ /// @brief Retrieves the group entry for a given group ID. ++ /// @param gid The group ID to search for. ++ /// @param resultbuf A pointer to a group structure where the result will be stored. ++ /// @param buffer A buffer to hold the string data for the group entry. ++ /// @param buflen The size of the buffer. ++ /// @param result A pointer to a group structure pointer that will point to the result. ++ /// @return 0 on success, or an error code on failure. ++ int getgrgid_r(gid_t gid, struct group* resultbuf, char* buffer, size_t buflen, struct group** result) const override ++ { ++ return ::getgrgid_r(gid, resultbuf, buffer, buflen, result); ++ } ++ ++ /// @brief Retrieves a group by its GID. ++ /// @param gid The group ID for which to retrieve the group structure. ++ /// @return A pointer to the group structure if found, or nullptr if not found. ++ struct group* getgrgid(gid_t gid) const override ++ { ++ return ::getgrgid(gid); ++ } ++ ++ /// @brief Retrieves the group entry for a given group name. ++ /// @param resultbuf A pointer to a group structure where the result will be stored. ++ /// @param buffer A buffer to hold the string data for the group entry. ++ /// @param buflen The size of the buffer. ++ /// @param result A pointer to a group structure pointer that will point to the result. ++ int getgrent_r(struct group* resultbuf, char* buffer, size_t buflen, struct group** result) const override ++ { ++ return ::getgrent_r(resultbuf, buffer, buflen, result); ++ } ++ ++ /// @brief Retrieves the next group entry from the group database. ++ /// @return A pointer to the next group structure, or nullptr if there are no more entries. ++ struct group* getgrent() const override ++ { ++ return ::getgrent(); ++ } ++ ++ /// @brief Rewind the group-file stream. ++ void setgrent() const override ++ { ++ ::setgrent(); ++ } ++ /// @brief Close the group-file stream. ++ void endgrent() const override ++ { ++ ::endgrent(); ++ } ++ /// @brief Retrieves a group by its name. ++ /// @param name The name of the group to retrieve. ++ /// @return A pointer to the group structure if found, or nullptr if not found. ++ struct group* getgrnam(const char* name) const override ++ { ++ return ::getgrnam(name); ++ } ++ ++ /// @brief Retrieves the list of groups for a user. ++ /// @param user The username for which to retrieve the group list. ++ /// @param group The primary group ID of the user. ++ /// @param groups Pointer to an array where the group IDs will be stored. ++ /// @param ngroups Pointer to an integer that indicates the size of the groups array. ++ /// @return The number of groups the user belongs to, or -1 on error. ++ int getgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) const override ++ { ++ return ::getgrouplist(user, group, groups, ngroups); ++ } ++}; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-igroup_wrapper.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-igroup_wrapper.hpp new file mode 100644 index 000000000000..a62f2fa241fc --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-igroup_wrapper.hpp @@ -0,0 +1,70 @@ +--- /dev/null 2026-01-13 23:16:28.442788000 +0000 ++++ src/data_provider/src/extended_sources/wrappers/unix/freebsd/igroup_wrapper.hpp 2026-01-13 22:43:51.149445000 +0000 +@@ -0,0 +1,67 @@ ++/* 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. ++ */ ++ ++#pragma once ++ ++#include ++ ++/// @brief Interface for group-related operations on FreeBSD systems. ++/// ++/// Provides methods to retrieve group lists and counts for users, allowing for dependency injection ++/// and easier testing. This interface abstracts the system calls used to interact with the group database. ++class IGroupWrapperFreeBSD ++{ ++ public: ++ /// @brief Default constructor. ++ virtual ~IGroupWrapperFreeBSD() = default; ++ ++ /// @brief Retrieves the group entry for a given group ID. ++ /// @param gid The group ID to search for. ++ /// @param resultbuf A pointer to a group structure where the result will be stored. ++ /// @param buffer A buffer to hold the string data for the group entry. ++ /// @param buflen The size of the buffer. ++ /// @param result A pointer to a group structure pointer that will point to the result. ++ /// @return 0 on success, or an error code on failure. ++ virtual int getgrgid_r(gid_t gid, struct group* resultbuf, char* buffer, size_t buflen, struct group** result) const = 0; ++ ++ /// @brief Retrieves the group entry for a given group name. ++ /// @param resultbuf A pointer to a group structure where the result will be stored. ++ /// @param buffer A buffer to hold the string data for the group entry. ++ /// @param buflen The size of the buffer. ++ /// @param result A pointer to a group structure pointer that will point to the result. ++ virtual int getgrent_r(struct group* resultbuf, char* buffer, size_t buflen, struct group** result) const = 0; ++ ++ /// @brief Retrieves a group by its GID. ++ /// @param gid The group ID for which to retrieve the group structure. ++ /// @return A pointer to the group structure if found, or nullptr if not found. ++ virtual struct group* getgrgid(gid_t gid) const = 0; ++ ++ /// @brief Retrieves the next group entry from the group database. ++ /// @return A pointer to the next group structure, or nullptr if there are no more entries ++ virtual struct group* getgrent() const = 0; ++ ++ /// @brief Rewind the group-file stream. ++ virtual void setgrent() const = 0; ++ ++ /// @brief Close the group-file stream. ++ virtual void endgrent() const = 0; ++ ++ /// @brief Retrieves a group by its name. ++ /// @param name The name of the group to retrieve. ++ /// @return A pointer to the group structure if found, or nullptr if not found. ++ virtual struct group* getgrnam(const char* name) const = 0; ++ ++ /// @brief Retrieves the list of groups for a user. ++ /// @param user The username for which to retrieve the group list. ++ /// @param group The primary group ID of the user. ++ /// @param groups Pointer to an array where the group IDs will be stored. ++ /// @param ngroups Pointer to an integer that indicates the size of the groups array. ++ /// @return The number of groups the user belongs to, or -1 on error. ++ virtual int getgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) const = 0; ++}; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-ipasswd_wrapper.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-ipasswd_wrapper.hpp new file mode 100644 index 000000000000..a2119a381499 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-ipasswd_wrapper.hpp @@ -0,0 +1,72 @@ +--- /dev/null 2026-01-13 23:17:10.457712000 +0000 ++++ src/data_provider/src/extended_sources/wrappers/unix/freebsd/ipasswd_wrapper.hpp 2026-01-13 22:43:51.149517000 +0000 +@@ -0,0 +1,69 @@ ++/* 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. ++ */ ++ ++#pragma once ++ ++#include ++ ++// Interface for the pwd darwin wrapper ++class IPasswdWrapperFreeBSD ++{ ++ public: ++ /// Destructor ++ virtual ~IPasswdWrapperFreeBSD() = default; ++ ++ /// @brief Retrieves the passwd entry for the given username. ++ /// @param name The username to search for. ++ /// @return A pointer to the passwd structure, or nullptr if not found. ++ virtual struct passwd* getpwnam(const char* name) = 0; ++ ++ /// @brief Retrieves the passwd entry for the given user ID. ++ /// @param uid The user ID to search for. ++ /// @return A pointer to the passwd structure, or nullptr if not found. ++ virtual struct passwd* getpwuid(uid_t uid) = 0; ++ ++ /// @brief Retrieves the passwd entry for the given user ID. ++ /// @param uid User ID to search. ++ /// @param pwd Pointer to a passwd structure to fill. ++ /// @param buf Buffer used to store string fields. ++ /// @param buflen Size of the buffer. ++ /// @param result Pointer to store the result (null if not found). ++ /// @return 0 on success, or an error number on failure. ++ virtual int getpwuid_r(uid_t uid, struct passwd* pwd, ++ char* buf, size_t buflen, struct passwd** result) = 0; ++ ++ /// @brief Retrieves the passwd entry for the given username. ++ /// @param name Username to search. ++ /// @param pwd Pointer to a passwd structure to fill. ++ /// @param buf Buffer used to store string fields. ++ /// @param buflen Size of the buffer. ++ /// @param result Pointer to store the result (null if not found). ++ /// @return 0 on success, or an error number on failure. ++ virtual int getpwnam_r(const char* name, struct passwd* pwd, ++ char* buf, size_t buflen, struct passwd** result) = 0; ++ ++ /// @brief Rewinds the passwd database to the beginning. ++ virtual void setpwent() = 0; ++ ++ /// @brief Retrieves the next entry from the passwd database. ++ /// @return A pointer to the passwd structure, or nullptr if no more entries. ++ virtual struct passwd* getpwent() = 0; ++ ++ /// @brief Retrieves the next entry from the passwd database. ++ /// @param pwd Pointer to a passwd structure to fill. ++ /// @param buf Buffer used to store string fields. ++ /// @param buflen Size of the buffer. ++ /// @param result Pointer to store the result (null if not found). ++ /// @return 0 on success, or an error number on failure. ++ virtual int getpwent_r(struct passwd* pwd, char* buf, ++ size_t buflen, struct passwd** result) = 0; ++ ++ /// @brief Closes the passwd database. ++ virtual void endpwent() = 0; ++}; diff --git a/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-passwd_wrapper.hpp b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-passwd_wrapper.hpp new file mode 100644 index 000000000000..9d12098e14f5 --- /dev/null +++ b/security/wazuh-manager/files/patch-src_data__provider_src_extended__sources_wrappers_unix_freebsd-passwd_wrapper.hpp @@ -0,0 +1,96 @@ +--- /dev/null 2026-01-13 23:17:03.875999000 +0000 ++++ src/data_provider/src/extended_sources/wrappers/unix/freebsd/passwd_wrapper.hpp 2026-01-13 22:43:51.149624000 +0000 +@@ -0,0 +1,93 @@ ++/* 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. ++ */ ++ ++#pragma once ++ ++#include "ipasswd_wrapper.hpp" ++ ++/// @brief Wrapper class for FreeBSD-specific passwd database access. ++/// ++/// Encapsulates system calls used to retrieve user information on FreeBSD, ++/// allowing for dependency injection and easier testing. ++class PasswdWrapperFreeBSD : public IPasswdWrapperFreeBSD ++{ ++ public: ++ /// @brief Retrieves the passwd entry for the given username. ++ /// @param name The username to search for. ++ /// @return A pointer to the passwd structure, or nullptr if not found. ++ struct passwd* getpwnam(const char* name) override ++ { ++ return ::getpwnam(name); ++ } ++ ++ /// @brief Retrieves the passwd entry for the given user ID. ++ /// @param uid The user ID to search for. ++ /// @return A pointer to the passwd structure, or nullptr if not found. ++ struct passwd* getpwuid(uid_t uid) override ++ { ++ return ::getpwuid(uid); ++ } ++ ++ /// @brief Retrieves the passwd entry for the given user ID. ++ /// @param uid User ID to search. ++ /// @param pwd Pointer to a passwd structure to fill. ++ /// @param buf Buffer used to store string fields. ++ /// @param buflen Size of the buffer. ++ /// @param result Pointer to store the result (null if not found). ++ /// @return 0 on success, or an error number on failure. ++ int getpwuid_r(uid_t uid, struct passwd* pwd, ++ char* buf, size_t buflen, struct passwd** result) override ++ { ++ return ::getpwuid_r(uid, pwd, buf, buflen, result); ++ } ++ ++ /// @brief Retrieves the passwd entry for the given username. ++ /// @param name Username to search. ++ /// @param pwd Pointer to a passwd structure to fill. ++ /// @param buf Buffer used to store string fields. ++ /// @param buflen Size of the buffer. ++ /// @param result Pointer to store the result (null if not found). ++ /// @return 0 on success, or an error number on failure. ++ int getpwnam_r(const char* name, struct passwd* pwd, ++ char* buf, size_t buflen, struct passwd** result) override ++ { ++ return ::getpwnam_r(name, pwd, buf, buflen, result); ++ } ++ ++ /// @brief Rewinds the passwd database to the beginning. ++ void setpwent() override ++ { ++ ::setpwent(); ++ } ++ ++ /// @brief Retrieves the next entry from the passwd database. ++ /// @return A pointer to the passwd structure, or nullptr if no more entries. ++ struct passwd* getpwent() override ++ { ++ return ::getpwent(); ++ } ++ ++ /// @brief Retrieves the next entry from the passwd database. ++ /// @param pwd Pointer to a passwd structure to fill. ++ /// @param buf Buffer used to store string fields. ++ /// @param buflen Size of the buffer. ++ /// @param result Pointer to store the result (null if not found). ++ /// @return 0 on success, or an error number on failure. ++ int getpwent_r(struct passwd* pwd, char* buf, ++ size_t buflen, struct passwd** result) override ++ { ++ return ::getpwent_r(pwd, buf, buflen, result); ++ } ++ ++ /// @brief Closes the passwd database. ++ void endpwent() override ++ { ++ ::endpwent(); ++ } ++};