Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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