Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# GitHub Actions workflows

- **codeql.yml** – CodeQL analysis (push/PR to master, weekly).
- **make-multi-platform.yml** – Build with Make on Rocky Linux 10 (server/agent) and Windows agent (cross-compile). Based on the multi-platform CI idea from PR #2158 by @cmac9203; adapted for this project’s Make build.
55 changes: 55 additions & 0 deletions .github/workflows/make-multi-platform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Multi-platform build workflow.
# Initial CI structure and idea from PR #2158 by @cmac9203. Adapted to use the
# project's Make-based build (OSSEC-HIDS does not use CMake).
name: Build (multi-platform)

on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]

jobs:
build-rocky:
name: Rocky Linux 10 (${{ matrix.target }})
runs-on: ubuntu-latest
container: rockylinux:10
strategy:
fail-fast: false
matrix:
target: [ server, agent ]

steps:
- uses: actions/checkout@v4

- name: Install build dependencies
run: |
dnf install -y gcc make openssl-devel pcre2-devel zlib-devel \
systemd-devel libevent-devel
dnf install -y file-devel || true

- name: Build
run: |
cd src
make TARGET=${{ matrix.target }} PCRE2_SYSTEM=yes -j$(nproc)

build-windows-agent:
name: Windows agent (cross-compile)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install MinGW and deps
run: |
sudo apt-get update -qq
sudo apt-get install -y build-essential mingw-w64 libssl-dev

- name: Fetch PCRE2 for Windows build
run: |
mkdir -p src/external
wget -q https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.32/pcre2-10.32.tar.gz -O - | tar xz -C src/external

- name: Build Windows agent
run: |
cd src
make TARGET=winagent -j$(nproc)
7 changes: 7 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ INSTALL_RESOLVCONF?=yes
USE_PRELUDE?=no
USE_ZEROMQ?=no
USE_GEOIP?=no
USE_CURL?=no
USE_INOTIFY=no
USE_PCRE2_JIT=yes
USE_SYSTEMD?=yes
Expand Down Expand Up @@ -259,6 +260,11 @@ ifneq (,$(filter ${USE_GEOIP},auto yes y Y 1))
OSSEC_LDFLAGS+=-lGeoIP
endif # USE_GEOIP

ifneq (,$(filter ${USE_CURL},yes y Y 1))
DEFINES+=-DUSE_SMTP_CURL
OSSEC_LDFLAGS+=-lcurl
endif # USE_CURL

ifneq (,$(filter ${USE_SQLITE},auto yes y Y 1))
DEFINES+=-DSQLITE_ENABLED
ANALYSISD_FLAGS="-lsqlite3"
Expand Down Expand Up @@ -618,6 +624,7 @@ settings:
@echo "USE settings:"
@echo " USE_ZEROMQ: ${USE_ZEROMQ}"
@echo " USE_GEOIP: ${USE_GEOIP}"
@echo " USE_CURL: ${USE_CURL}"
@echo " USE_PRELUDE: ${USE_PRELUDE}"
@echo " USE_OPENSSL: ${USE_OPENSSL}"
@echo " USE_INOTIFY: ${USE_INOTIFY}"
Expand Down
82 changes: 82 additions & 0 deletions src/config/global-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ int Read_Global(XML_NODE node, void *configp, void *mailp)
const char *xml_smtpserver = "smtp_server";
const char *xml_heloserver = "helo_server";
const char *xml_mailmaxperhour = "email_maxperhour";
const char *xml_auth_smtp = "auth_smtp";
const char *xml_smtp_user = "smtp_user";
const char *xml_smtp_password = "smtp_password";
const char *xml_secure_smtp = "secure_smtp";
const char *xml_smtp_port = "smtp_port";

#ifdef LIBGEOIP_ENABLED
const char *xml_geoip_db_path = "geoip_db_path";
Expand Down Expand Up @@ -453,17 +458,82 @@ int Read_Global(XML_NODE node, void *configp, void *mailp)
}
os_strdup(node[i]->content, Mail->idsname);
}
} else if (strcmp(node[i]->element, xml_auth_smtp) == 0) {
if (strcmp(node[i]->content, "yes") == 0) {
if (Config) {
Config->authsmtp = 1;
}
if (Mail) {
Mail->authsmtp = 1;
}
} else if (strcmp(node[i]->content, "no") == 0) {
if (Config) {
Config->authsmtp = 0;
}
if (Mail) {
Mail->authsmtp = 0;
}
} else {
return (OS_INVALID);
}
} else if (strcmp(node[i]->element, xml_secure_smtp) == 0) {
if (strcmp(node[i]->content, "yes") == 0) {
if (Config) {
Config->securesmtp = 1;
}
if (Mail) {
Mail->securesmtp = 1;
}
} else if (strcmp(node[i]->content, "no") == 0) {
if (Config) {
Config->securesmtp = 0;
}
if (Mail) {
Mail->securesmtp = 0;
}
} else {
return (OS_INVALID);
}
} else if (strcmp(node[i]->element, xml_smtp_user) == 0) {
if (Mail) {
if (Mail->smtp_user) {
free(Mail->smtp_user);
}
os_strdup(node[i]->content, Mail->smtp_user);
}
} else if (strcmp(node[i]->element, xml_smtp_password) == 0) {
if (Mail) {
if (Mail->smtp_pass) {
memset_secure(Mail->smtp_pass, 0, strlen(Mail->smtp_pass));
free(Mail->smtp_pass);
}
os_strdup(node[i]->content, Mail->smtp_pass);
}
} else if (strcmp(node[i]->element, xml_smtpserver) == 0) {
#ifndef WIN32
if (Mail && (Mail->mn)) {
if (node[i]->content[0] == '/') {
os_strdup(node[i]->content, Mail->smtpserver);
} else {
#ifdef USE_SMTP_CURL
/* Pre-resolve for CURLOPT_RESOLVE; DNS is unavailable after chroot */
if (Mail->smtpserver_resolved) {
free(Mail->smtpserver_resolved);
Mail->smtpserver_resolved = NULL;
}
Mail->smtpserver_resolved = OS_GetHost(node[i]->content, 5);
if (!Mail->smtpserver_resolved) {
merror(INVALID_SMTP, __local_name, node[i]->content);
return (OS_INVALID);
}
/* Hostname as-is for libcurl; common free + os_strdup below */
#else
Mail->smtpserver = OS_GetHost(node[i]->content, 5);
if (!Mail->smtpserver) {
merror(INVALID_SMTP, __local_name, node[i]->content);
return (OS_INVALID);
}
#endif
}
free(Mail->smtpserver);
os_strdup(node[i]->content, Mail->smtpserver);
Expand All @@ -473,6 +543,18 @@ int Read_Global(XML_NODE node, void *configp, void *mailp)
if (Mail && (Mail->mn)) {
os_strdup(node[i]->content, Mail->heloserver);
}
} else if (strcmp(node[i]->element, xml_smtp_port) == 0) {
if (Mail && (Mail->mn)) {
if (!OS_StrIsNum(node[i]->content)) {
merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
return (OS_INVALID);
}
Mail->smtp_port = atoi(node[i]->content);
if (Mail->smtp_port < 1 || Mail->smtp_port > 65535) {
merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
return (OS_INVALID);
}
}
} else if (strcmp(node[i]->element, xml_mailmaxperhour) == 0) {
if (Mail) {
if (!OS_StrIsNum(node[i]->content)) {
Expand Down
4 changes: 4 additions & 0 deletions src/config/global-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ typedef struct __Config {
/* Mail alerting */
short int mailnotify;

/* SMTP auth (USE_CURL build only) */
short int authsmtp;
short int securesmtp;

/* Custom Alert output*/
short int custom_alert_output;
char *custom_alert_output_format;
Expand Down
8 changes: 8 additions & 0 deletions src/config/mail-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ typedef struct _MailConfig {
char *idsname;
char *smtpserver;
char *heloserver;
char *smtpserver_resolved; /* pre-resolved IP for CURLOPT_RESOLVE when chrooted (USE_SMTP_CURL) */

/* SMTP auth (USE_CURL build only) */
int authsmtp; /* 0 = off (default), 1 = on */
int securesmtp; /* 0 = off (default), 1 = on */
int smtp_port; /* 0 = use default per mode (465/587/25); else override */
char *smtp_user;
char *smtp_pass;

/* Granular e-mail options */
unsigned int *gran_level;
Expand Down
17 changes: 17 additions & 0 deletions src/monitord/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,22 @@ int main(int argc, char **argv)
mond.emailidsname = OS_GetOneContentforElement(&xml, xml_idsname);

if (tmpsmtp && mond.emailfrom) {
#ifdef USE_SMTP_CURL
/* Validate hostname with OS_GetHost() but store original string for libcurl. */
if (tmpsmtp[0] != '/') {
char *validated_host = OS_GetHost(tmpsmtp, 5);
if (!validated_host) {
mond.smtpserver = NULL;
} else {
free(validated_host);
os_strdup(tmpsmtp, mond.smtpserver);
}
} else {
os_strdup(tmpsmtp, mond.smtpserver);
}
#else
mond.smtpserver = OS_GetHost(tmpsmtp, 5);
#endif
if (!mond.smtpserver) {
merror(INVALID_SMTP, ARGV0, tmpsmtp);
if (mond.emailfrom) {
Expand All @@ -154,6 +169,8 @@ int main(int argc, char **argv)
mond.emailfrom = NULL;
merror("%s: Invalid SMTP server. Disabling email reports.", ARGV0);
}
free(tmpsmtp);
tmpsmtp = NULL;
} else {
if (tmpsmtp) {
free(tmpsmtp);
Expand Down
19 changes: 19 additions & 0 deletions src/os_maild/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ int MailConf(int test_config, const char *cfgfile, MailConfig *Mail)
Mail->idsname = NULL;
Mail->smtpserver = NULL;
Mail->heloserver = NULL;
Mail->smtpserver_resolved = NULL;
Mail->authsmtp = 0;
Mail->securesmtp = 0;
Mail->smtp_port = 0;
Mail->smtp_user = NULL;
Mail->smtp_pass = NULL;
Mail->mn = 0;
Mail->priority = 0;
Mail->maxperhour = 12;
Expand All @@ -45,6 +51,19 @@ int MailConf(int test_config, const char *cfgfile, MailConfig *Mail)
return (OS_INVALID);
}

#ifndef USE_SMTP_CURL
if (Mail->authsmtp || Mail->securesmtp || Mail->smtp_port ||
Mail->smtp_user || Mail->smtp_pass) {
merror("%s: SMTP authentication/TLS options (auth_smtp, secure_smtp, smtp_port, smtp_user, smtp_password) require building with USE_CURL=yes.", ARGV0);
return (OS_INVALID);
}
#else
if (Mail->authsmtp && (!Mail->smtp_user || !Mail->smtp_pass)) {
merror("%s: auth_smtp=yes requires both smtp_user and smtp_password to be set.", ARGV0);
return (OS_INVALID);
Comment on lines +61 to +63
}
#endif

if (!Mail->mn) {
if (!test_config) {
verbose(MAIL_DIS, ARGV0);
Expand Down
Loading
Loading