From 43114f7951d50831d7646f845d748f6432951d2d Mon Sep 17 00:00:00 2001 From: Alex Bartlow Date: Thu, 1 Feb 2018 11:53:10 -0500 Subject: [PATCH 1/2] Allow specifying a compile-time switch to use curl, which will enable TLS and authentication for email delivery --- etc/templates/en/messages.txt | 9 +++ install.sh | 105 ++++++++++++++++++++++++++++- src/Makefile | 5 ++ src/config/global-config.c | 63 +++++++++++++++++ src/config/global-config.h | 4 ++ src/config/mail-config.h | 6 ++ src/monitord/main.c | 2 + src/os_maild/config.c | 5 ++ src/os_maild/curlmail.c | 123 ++++++++++++++++++++++++++++++++++ src/os_maild/sendmail.c | 3 + 10 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 src/os_maild/curlmail.c diff --git a/etc/templates/en/messages.txt b/etc/templates/en/messages.txt index 726e027fc..b21af367c 100755 --- a/etc/templates/en/messages.txt +++ b/etc/templates/en/messages.txt @@ -41,6 +41,15 @@ yoursmtp="We found your SMTP server as" usesmtp="Do you want to use it?" usingsmtp="Using SMTP server: " whatsmtp="What's your SMTP server ip/host?" +useauthsmtp="Want to use authenticated SMTP?" + +noauthsmtp="SMTP authenticated not enabled" +yesauthsmtp="SMTP authenticated enabled" +userauthsmtp="Please, enter your SMTP username" +passauthsmtp="Please, enter your SMTP password" +usesecuresmtp="This server requires a secure connection (SSL)?" +nosecuresmtp="SMTP with SSL disabled" +yessecuresmtp="SMTP with SSL enabled" # Part 3.1/agent serveraddr="What's the IP Address or hostname of the OSSEC HIDS server?" diff --git a/install.sh b/install.sh index 32920ebf4..1e662818d 100755 --- a/install.sh +++ b/install.sh @@ -19,7 +19,6 @@ ### Looking up for the execution directory cd `dirname $0` - ### Looking for echo -n ECHO="echo -n" hs=`echo -n "a"` @@ -130,6 +129,8 @@ Install() chmod 600 ${OSSEC_INIT} cp -pr ${OSSEC_INIT} ${INSTALLDIR}${OSSEC_INIT} chmod 640 ${INSTALLDIR}${OSSEC_INIT} + mkdir ${INSTALLDIR}/lib + cp -R /lib/* ${INSTALLDIR}/lib # If update_rules is set, we need to tweak @@ -241,7 +242,104 @@ UseRootcheck() fi } +############### +# UseSecureSMTP() +############### +UseSecureSMTP() +{ + + # SMTP Authenticaction configuration (SSL) + echo "" + $ECHO " ${usesecuresmtp} ($yes/$no) [$yes]: " + + if [ "X${USER_ENABLE_SECURESMTP}" = "X" ]; then + read ESS + else + ESS=${USER_ENABLE_SECURESMTP} + fi + + echo "" + case $ESS in + $nomatch) + echo " - ${nosecuresmtp}." + ;; + *) + SECURESMTP="yes" + echo " - ${yessecuresmtp}." + ;; + esac + + # Adding to the config file + if [ "X${SECURESMTP}" = "Xyes" ]; then + echo "" >> $NEWCONFIG + echo " yes" >> $NEWCONFIG + echo "" >> $NEWCONFIG + else + echo "" >> $NEWCONFIG + echo " no" >> $NEWCONFIG + echo "" >> $NEWCONFIG + fi +} + + +############### +# UseAuthSMTP() +############### +UseAuthSMTP() +{ + + # SMTP Authenticaction configuration + echo "" + $ECHO " ${useauthsmtp} ($yes/$no) [$yes]: " + + if [ "X${USER_ENABLE_AUTHSMTP}" = "X" ]; then + read EAS + else + EAS=${USER_ENABLE_AUTHSMTP} + fi + + echo "" + case $EAS in + $nomatch) + echo " - ${noauthsmtp}." + ;; + *) + AUTHSMTP="yes" + echo " - ${yesauthsmtp}." + ;; + esac + + if [ "X${AUTHSMTP}" = "Xyes" ]; then + if [ "X${AUTHSMTP_USER}" = "X" ]; then + echo "" + $ECHO " ${userauthsmtp}: " + read AUTHSMTP_USER + fi + + if [ "X${AUTHSMTP_PASS}" = "X" ]; then + echo "" + $ECHO " ${passauthsmtp}: " + stty -echo # turn off terminal echo to prevent peeping! + read AUTHSMTP_PASS + stty echo # turn on + echo "" + fi + fi + # Adding to the config file + if [ "X${AUTHSMTP}" = "Xyes" ]; then + echo "" >> $NEWCONFIG + echo " yes" >> $NEWCONFIG + echo " $AUTHSMTP_USER" >> $NEWCONFIG + echo " $AUTHSMTP_PASS" >> $NEWCONFIG + echo "" >> $NEWCONFIG + UseSecureSMTP + else + echo "" >> $NEWCONFIG + echo " no" >> $NEWCONFIG + echo "" >> $NEWCONFIG + fi +} ########## @@ -552,6 +650,8 @@ ConfigureServer() echo " no" >> $NEWCONFIG fi + UseAuthSMTP + echo " " >> $NEWCONFIG echo "" >> $NEWCONFIG @@ -817,6 +917,9 @@ checkDependencies() PATH=$OLDOPATH export PATH + + # Re-export sendmail_curl if curl support should be compiled in + export SENDMAIL_CURL } ########## diff --git a/src/Makefile b/src/Makefile index 3d3fa925b..788bbe915 100644 --- a/src/Makefile +++ b/src/Makefile @@ -51,6 +51,11 @@ endif OSSEC_LDFLAGS=${LDFLAGS} -lm +ifeq (${SENDMAIL_CURL},yes) + DEFINES +=-DSENDMAIL_CURL=\"1\" + OSSEC_LDFLAGS+=-lcurl +endif + ifneq (${TARGET},winagent) ifeq (${uname_S},Linux) DEFINES+=-DINOTIFY_ENABLED diff --git a/src/config/global-config.c b/src/config/global-config.c index 345943a79..ad59c6feb 100644 --- a/src/config/global-config.c +++ b/src/config/global-config.c @@ -121,6 +121,11 @@ int Read_Global(XML_NODE node, void *configp, void *mailp) 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_pass = "smtp_password"; + const char *xml_secure_smtp = "secure_smtp"; + #ifdef LIBGEOIP_ENABLED const char *xml_geoip_db_path = "geoip_db_path"; const char *xml_geoip6_db_path = "geoip6_db_path"; @@ -201,6 +206,42 @@ int Read_Global(XML_NODE node, void *configp, void *mailp) return (OS_INVALID); } } + /* SMTP Authentication */ + 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); + } + } + /* Secure SMTP (SSL) */ + 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); + } + } /* Prelude support */ else if (strcmp(node[i]->element, xml_prelude) == 0) { if (strcmp(node[i]->content, "yes") == 0) { @@ -445,17 +486,39 @@ int Read_Global(XML_NODE node, void *configp, void *mailp) } os_strdup(node[i]->content, Mail->idsname); } + } else if(strcmp(node[i]->element, xml_smtp_user) == 0) { + if(Mail && (Mail->authsmtp)) + { + if(Mail->smtp_user) + { + free(Mail->smtp_user); + } + os_strdup(node[i]->content, Mail->smtp_user); + } + } else if(strcmp(node[i]->element, xml_smtp_pass) == 0) { + if(Mail && (Mail->authsmtp)) + { + if(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 SENDMAIL_CURL + os_strdup(node[i]->content, Mail->smtpserver); +#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); diff --git a/src/config/global-config.h b/src/config/global-config.h index 61a93cac1..1499d4469 100644 --- a/src/config/global-config.h +++ b/src/config/global-config.h @@ -50,6 +50,10 @@ typedef struct __Config { /* Mail alerting */ short int mailnotify; + /* Mail smtp auth */ + short int authsmtp; + short int securesmtp; + /* Custom Alert output*/ short int custom_alert_output; char *custom_alert_output_format; diff --git a/src/config/mail-config.h b/src/config/mail-config.h index f6864dc2e..f548c7f00 100644 --- a/src/config/mail-config.h +++ b/src/config/mail-config.h @@ -27,6 +27,12 @@ typedef struct _MailConfig { char *smtpserver; char *heloserver; + /* auth smtp options */ + int authsmtp; + char *smtp_user; + char *smtp_pass; + int securesmtp; + /* Granular e-mail options */ unsigned int *gran_level; unsigned int **gran_id; diff --git a/src/monitord/main.c b/src/monitord/main.c index fdf18e684..d7bb46398 100644 --- a/src/monitord/main.c +++ b/src/monitord/main.c @@ -145,6 +145,7 @@ int main(int argc, char **argv) mond.emailidsname = OS_GetOneContentforElement(&xml, xml_idsname); if (tmpsmtp && mond.emailfrom) { +#ifndef SENDMAIL_CURL mond.smtpserver = OS_GetHost(tmpsmtp, 5); if (!mond.smtpserver) { merror(INVALID_SMTP, ARGV0, tmpsmtp); @@ -154,6 +155,7 @@ int main(int argc, char **argv) mond.emailfrom = NULL; merror("%s: Invalid SMTP server. Disabling email reports.", ARGV0); } +#endif } else { if (tmpsmtp) { free(tmpsmtp); diff --git a/src/os_maild/config.c b/src/os_maild/config.c index 13f2f2f6f..b299e26be 100644 --- a/src/os_maild/config.c +++ b/src/os_maild/config.c @@ -37,6 +37,11 @@ int MailConf(int test_config, const char *cfgfile, MailConfig *Mail) Mail->gran_format = NULL; Mail->groupping = 1; Mail->strict_checking = 0; + Mail->authsmtp = -1; + Mail->smtp_user = NULL; + Mail->smtp_pass = NULL; + Mail->securesmtp = 0; + #ifdef LIBGEOIP_ENABLED Mail->geoip = 0; #endif diff --git a/src/os_maild/curlmail.c b/src/os_maild/curlmail.c new file mode 100644 index 000000000..b66181267 --- /dev/null +++ b/src/os_maild/curlmail.c @@ -0,0 +1,123 @@ +/* Sendmail implementation using curl instead of writing it ourselves. + * Useful for sending SMTP traffic over authenticated hosts. + * + */ + +#ifdef SENDMAIL_CURL +#include +#include "maild.h" +#include "mail_list.h" + +struct upload_status { + int lines_read; +}; + +static char *payload_text[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) { + struct upload_status *upload_ctx = (struct upload_status *)userp; + const char *data; + + if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { + return 0; + } + + data = payload_text[upload_ctx->lines_read]; + + if(data) { + size_t len = strlen(data); + memcpy(ptr, data, len); + upload_ctx->lines_read++; + + return len; + } + + return 0; +} + +int OS_Sendsms(MailConfig *mail, struct tm *p, MailMsg *msg) { + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *recipients = NULL; + struct upload_status upload_ctx; + + char hostname[1024]; + gethostname(hostname, 1024); + + char *messageId = NULL; + int i = 0; + + for(i = 0; i<5; i++) { + if(!payload_text[i]) { + payload_text[i] = (char*)malloc(128); + } + } + + strftime(payload_text[0], 127, "Date: %a, %d %b %Y %T %z\r\n", p); + sprintf(payload_text[1], "To: %s \r\n", mail->to[0]); + sprintf(payload_text[2], "From: %s \r\n", mail->from); + strftime(messageId, 127, "%a%d%b%Y%T%z", p); + sprintf(payload_text[3], "Message-ID: <%s@%s> \r\n", messageId, hostname); + sprintf(payload_text[4], "Subject: %s \r\n\r\n", msg->subject); + + payload_text[5] = msg->body; + + payload_text[6] = NULL; + + upload_ctx.lines_read = 0; + curl = curl_easy_init(); + + if(curl) { + char errbuf[CURL_ERROR_SIZE]; + errbuf[0] = 0; + fprintf(stderr, "curl_easy_setopt() URL: %s\n", mail->smtpserver); + curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/ssl/certs/cacert.pem"); + curl_easy_setopt(curl, CURLOPT_URL, mail->smtpserver); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, "10.0.0.2,8.8.8.8,8.8.4.4"); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + if(mail->authsmtp) { + curl_easy_setopt(curl, CURLOPT_USERNAME, mail->smtp_user); + curl_easy_setopt(curl, CURLOPT_PASSWORD, mail->smtp_pass); + } + + if(mail->securesmtp) { + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); + } + + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, mail->from); + recipients = curl_slist_append(recipients, mail->to[0]); + + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + + res = curl_easy_perform(curl); + + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s (%s)\n", curl_easy_strerror(res), errbuf); + } + + curl_slist_free_all(recipients); + + curl_easy_cleanup(curl); + } + + return (int)res; +} + +int OS_Sendmail(MailConfig *mail, struct tm *p) { + MailNode *mailmsg; + while((mailmsg = OS_PopLastMail()) != NULL) { + OS_Sendsms(mail, p, mailmsg->mail); + FreeMail(mailmsg); + } + + return 0; +} + +#endif diff --git a/src/os_maild/sendmail.c b/src/os_maild/sendmail.c index f793c24d4..db1cd7884 100644 --- a/src/os_maild/sendmail.c +++ b/src/os_maild/sendmail.c @@ -9,6 +9,7 @@ /* Basic e-mailing operations */ +#ifndef SENDMAIL_CURL #include "shared.h" #include "os_net/os_net.h" #include "maild.h" @@ -623,3 +624,5 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) memset_secure(snd_msg, '\0', 128); return (0); } +#endif + From b7e98ab4d9539f77e340119ee299c562f8f7858d Mon Sep 17 00:00:00 2001 From: Alex Bartlow Date: Thu, 1 Feb 2018 13:32:59 -0500 Subject: [PATCH 2/2] Remove hard-coded DNS servers from curlmail.c --- src/os_maild/curlmail.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/os_maild/curlmail.c b/src/os_maild/curlmail.c index b66181267..67d3bdad8 100644 --- a/src/os_maild/curlmail.c +++ b/src/os_maild/curlmail.c @@ -75,7 +75,6 @@ int OS_Sendsms(MailConfig *mail, struct tm *p, MailMsg *msg) { curl_easy_setopt(curl, CURLOPT_URL, mail->smtpserver); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, "10.0.0.2,8.8.8.8,8.8.4.4"); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); if(mail->authsmtp) {