From e8ed37526bc563406ee0a712db239ac3d1695072 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 13 Nov 2015 17:25:57 +0000 Subject: [PATCH] Allow maild to send through a sendmail-like executable Users have long called for TLS support when sending mail from OSSEC. This is not trivial to add directly but this commit enables that support by delegating the task to a sendmail-like executable such as SSMTP or Msmtp. maild detects this mode of operation by checking for a / at the start of the smtp_server setting. It uses popen to launch the executable and passes the raw message to it via stdin. sendmail's -t argument tells it to parse the headers given in the message so smtp_server will typically be set to something like /usr/sbin/sendmail -t. In order for this to work, maild needs to be started without chrooting as it traditionally has done. It will therefore no longer chroot if it detects a / at the start of smtp_server. Privilege separation is still possible, hence the previous commit. It is best to view this commit with --ignore-all-space as there are far few changes than the regular diff would imply. --- src/config/global-config.c | 12 +- src/os_maild/maild.c | 12 +- src/os_maild/sendcustomemail.c | 240 +++++++------ src/os_maild/sendmail.c | 605 ++++++++++++++++++--------------- 4 files changed, 498 insertions(+), 371 deletions(-) diff --git a/src/config/global-config.c b/src/config/global-config.c index 8ee6b2ade..83634264b 100644 --- a/src/config/global-config.c +++ b/src/config/global-config.c @@ -441,10 +441,14 @@ int Read_Global(XML_NODE node, void *configp, void *mailp) } else if (strcmp(node[i]->element, xml_smtpserver) == 0) { #ifndef WIN32 if (Mail && (Mail->mn)) { - Mail->smtpserver = OS_GetHost(node[i]->content, 5); - if (!Mail->smtpserver) { - merror(INVALID_SMTP, __local_name, node[i]->content); - return (OS_INVALID); + if (node[i]->content[0] == '/') { + 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 diff --git a/src/os_maild/maild.c b/src/os_maild/maild.c index b7529aee7..ef4143319 100644 --- a/src/os_maild/maild.c +++ b/src/os_maild/maild.c @@ -160,18 +160,20 @@ int main(int argc, char **argv) ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno)); } - /* chroot */ - if (Privsep_Chroot(dir) < 0) { - ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno)); + if (mail.smtpserver[0] != '/') { + /* chroot */ + if (Privsep_Chroot(dir) < 0) { + ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno)); + } + nowChroot(); + debug1(CHROOT_MSG, ARGV0, dir); } - nowChroot(); /* Change user */ if (Privsep_SetUser(uid) < 0) { ErrorExit(SETUID_ERROR, ARGV0, user, errno, strerror(errno)); } - debug1(CHROOT_MSG, ARGV0, dir); debug1(PRIVSEP_MSG, ARGV0, user); /* Signal manipulation */ diff --git a/src/os_maild/sendcustomemail.c b/src/os_maild/sendcustomemail.c index 363c8e019..a7851ae6b 100644 --- a/src/os_maild/sendcustomemail.c +++ b/src/os_maild/sendcustomemail.c @@ -47,93 +47,83 @@ int OS_SendCustomEmail(char **to, char *subject, char *smtpserver, char *from, char *idsname, FILE *fp, const struct tm *p) { - int socket, i = 0; + FILE *sendmail = NULL; + int socket = -1, i = 0; char *msg; char snd_msg[128]; char buffer[2049]; buffer[2048] = '\0'; - /* Connect to the SMTP server */ - socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, smtpserver, 0, NULL); - if (socket < 0) { - return (socket); - } - - /* Receive the banner */ - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) { - merror(BANNER_ERROR); - if (msg) { - free(msg); + if (smtpserver[0] == '/') { + sendmail = popen(smtpserver, "w"); + if (!sendmail) { + return (OS_INVALID); + } + } else { + /* Connect to the SMTP server */ + socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, smtpserver, 0, NULL); + if (socket < 0) { + return (socket); } - close(socket); - return (OS_INVALID); - } - MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, ""); - free(msg); - /* Send HELO message */ - OS_SendTCP(socket, HELOMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - if (msg) { - /* In some cases (with virus scans in the middle) - * we may get two banners. Check for that in here. - */ - if (OS_Match(VALIDBANNER, msg)) { + /* Receive the banner */ + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) { + merror(BANNER_ERROR); + if (msg) { free(msg); + } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, ""); + free(msg); - /* Try again */ - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null"); - if (msg) { - free(msg); + /* Send HELO message */ + OS_SendTCP(socket, HELOMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + if (msg) { + /* In some cases (with virus scans in the middle) + * we may get two banners. Check for that in here. + */ + if (OS_Match(VALIDBANNER, msg)) { + free(msg); + + /* Try again */ + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null"); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); } + } else { + merror("%s:%s", HELO_ERROR, msg); + free(msg); close(socket); return (OS_INVALID); } } else { - merror("%s:%s", HELO_ERROR, msg); - free(msg); + merror("%s:%s", HELO_ERROR, "null"); close(socket); return (OS_INVALID); } - } else { - merror("%s:%s", HELO_ERROR, "null"); - close(socket); - return (OS_INVALID); } - } - - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", HELOMSG, msg); - free(msg); - /* Build "Mail from" msg */ - memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, MAILFROM, from); - OS_SendTCP(socket, snd_msg); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(FROM_ERROR); - if (msg) { - free(msg); - } - close(socket); - return (OS_INVALID); - } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", HELOMSG, msg); + free(msg); - /* Build "RCPT TO" msg */ - while (to[i]) { + /* Build "Mail from" msg */ memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, RCPTTO, to[i]); + snprintf(snd_msg, 127, MAILFROM, from); OS_SendTCP(socket, snd_msg); msg = OS_RecvTCP(socket, OS_SIZE_1024); if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(TO_ERROR, to[i]); + merror(FROM_ERROR); if (msg) { free(msg); } @@ -143,31 +133,59 @@ int OS_SendCustomEmail(char **to, char *subject, char *smtpserver, char *from, c MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); free(msg); - i++; - } - - /* Send the "DATA" msg */ - OS_SendTCP(socket, DATAMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) { - merror(DATA_ERROR); - if (msg) { + /* Build "RCPT TO" msg */ + while (to[i]) { + memset(snd_msg, '\0', 128); + snprintf(snd_msg, 127, RCPTTO, to[i]); + OS_SendTCP(socket, snd_msg); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror(TO_ERROR, to[i]); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); free(msg); + + i++; } - close(socket); - return (OS_INVALID); + + /* Send the "DATA" msg */ + OS_SendTCP(socket, DATAMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) { + merror(DATA_ERROR); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg); + free(msg); } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg); - free(msg); /* Build "From" and "To" in the e-mail header */ memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, TO, to[0]); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, FROM, from); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } /* Add CCs */ if (to[1]) { @@ -179,7 +197,12 @@ int OS_SendCustomEmail(char **to, char *subject, char *smtpserver, char *from, c memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, TO, to[i]); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } i++; } @@ -195,47 +218,70 @@ int OS_SendCustomEmail(char **to, char *subject, char *smtpserver, char *from, c strftime(snd_msg, 127, "Date: %a, %d %b %Y %T %z\r\n", p); #endif - OS_SendTCP(socket, snd_msg); + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } if (idsname) { /* Send server name header */ memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, XHEADER, idsname); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } } /* Send subject */ memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, SUBJECT, subject); - OS_SendTCP(socket, snd_msg); - OS_SendTCP(socket, ENDHEADER); + + if (sendmail) { + fprintf(sendmail, snd_msg); + fprintf(sendmail, ENDHEADER); + } else { + OS_SendTCP(socket, snd_msg); + OS_SendTCP(socket, ENDHEADER); + } /* Send body */ fseek(fp, 0, SEEK_SET); while (fgets(buffer, 2048, fp) != NULL) { - OS_SendTCP(socket, buffer); + if (sendmail) { + fprintf(sendmail, buffer); + } else { + OS_SendTCP(socket, buffer); + } } - /* Send end of data \r\n.\r\n */ - OS_SendTCP(socket, ENDDATA); - msg = OS_RecvTCP(socket, OS_SIZE_1024); + if (sendmail) { + fclose(sendmail); + } else { + /* Send end of data \r\n.\r\n */ + OS_SendTCP(socket, ENDDATA); + msg = OS_RecvTCP(socket, OS_SIZE_1024); - /* Check msg, since it may be null */ - if (msg) { - free(msg); - } + /* Check msg, since it may be null */ + if (msg) { + free(msg); + } - /* Quit and close socket */ - OS_SendTCP(socket, QUITMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); + /* Quit and close socket */ + OS_SendTCP(socket, QUITMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); - if (msg) { - free(msg); + if (msg) { + free(msg); + } + + close(socket); } memset_secure(snd_msg, '\0', 128); - close(socket); - return (0); } diff --git a/src/os_maild/sendmail.c b/src/os_maild/sendmail.c index e819c7731..510ecd960 100644 --- a/src/os_maild/sendmail.c +++ b/src/os_maild/sendmail.c @@ -48,148 +48,161 @@ int OS_Sendsms(MailConfig *mail, struct tm *p, MailMsg *sms_msg) { - int socket; + FILE *sendmail = NULL; + int socket = -1; size_t final_to_sz; char *msg; char snd_msg[128]; char final_to[512]; - /* Connect to the SMTP server */ - socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, mail->smtpserver, 0, NULL); - if (socket < 0) { - return (socket); - } - - /* Receive the banner */ - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) { - merror(BANNER_ERROR); - if (msg) { - free(msg); + if (mail->smtpserver[0] == '/') { + sendmail = popen(mail->smtpserver, "w"); + if (!sendmail) { + return (OS_INVALID); } - close(socket); - return (OS_INVALID); - } - MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, ""); - free(msg); - - /* Send HELO message */ - memset(snd_msg, '\0', 128); - if (mail->heloserver) { - snprintf(snd_msg, 127, "Helo %s\r\n", mail->heloserver); } else { - snprintf(snd_msg, 127, "Helo %s\r\n", "notify.ossec.net"); - } - OS_SendTCP(socket, snd_msg); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - if (msg) { - /* In some cases (with virus scans in the middle) - * we may get two banners. Check for that in here. - */ - if (OS_Match(VALIDBANNER, msg)) { + /* Connect to the SMTP server */ + socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, mail->smtpserver, 0, NULL); + if (socket < 0) { + return (socket); + } + + /* Receive the banner */ + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) { + merror(BANNER_ERROR); + if (msg) { free(msg); + } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, ""); + free(msg); - /* Try again */ - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null"); - if (msg) { - free(msg); + /* Send HELO message */ + memset(snd_msg, '\0', 128); + if (mail->heloserver) { + snprintf(snd_msg, 127, "Helo %s\r\n", mail->heloserver); + } else { + snprintf(snd_msg, 127, "Helo %s\r\n", "notify.ossec.net"); + } + OS_SendTCP(socket, snd_msg); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + if (msg) { + /* In some cases (with virus scans in the middle) + * we may get two banners. Check for that in here. + */ + if (OS_Match(VALIDBANNER, msg)) { + free(msg); + + /* Try again */ + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null"); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); } + } else { + merror("%s:%s", HELO_ERROR, msg); + free(msg); close(socket); return (OS_INVALID); } } else { - merror("%s:%s", HELO_ERROR, msg); - free(msg); + merror("%s:%s", HELO_ERROR, "null"); close(socket); return (OS_INVALID); } - } else { - merror("%s:%s", HELO_ERROR, "null"); + } + + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); + free(msg); + + /* Build "Mail from" msg */ + memset(snd_msg, '\0', 128); + snprintf(snd_msg, 127, MAILFROM, mail->from); + OS_SendTCP(socket, snd_msg); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror(FROM_ERROR); + if (msg) { + free(msg); + } close(socket); return (OS_INVALID); } - } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); + free(msg); - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); + /* Additional RCPT to */ + final_to[0] = '\0'; + final_to_sz = sizeof(final_to) - 2; - /* Build "Mail from" msg */ - memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, MAILFROM, mail->from); - OS_SendTCP(socket, snd_msg); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(FROM_ERROR); - if (msg) { - free(msg); - } - close(socket); - return (OS_INVALID); - } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); + if (mail->gran_to) { + int i = 0; + while (mail->gran_to[i] != NULL) { + if (mail->gran_set[i] != SMS_FORMAT) { + i++; + continue; + } + + memset(snd_msg, '\0', 128); + snprintf(snd_msg, 127, RCPTTO, mail->gran_to[i]); + OS_SendTCP(socket, snd_msg); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror(TO_ERROR, mail->gran_to[i]); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); + free(msg); - /* Additional RCPT to */ - final_to[0] = '\0'; - final_to_sz = sizeof(final_to) - 2; + /* Create header for to */ + memset(snd_msg, '\0', 128); + snprintf(snd_msg, 127, TO, mail->gran_to[i]); + strncat(final_to, snd_msg, final_to_sz); + final_to_sz -= strlen(snd_msg) + 2; - if (mail->gran_to) { - int i = 0; - while (mail->gran_to[i] != NULL) { - if (mail->gran_set[i] != SMS_FORMAT) { i++; continue; } + } - memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, RCPTTO, mail->gran_to[i]); - OS_SendTCP(socket, snd_msg); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(TO_ERROR, mail->gran_to[i]); - if (msg) { - free(msg); - } - close(socket); - return (OS_INVALID); + /* Send the "DATA" msg */ + OS_SendTCP(socket, DATAMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) { + merror(DATA_ERROR); + if (msg) { + free(msg); } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); - - /* Create header for to */ - memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, TO, mail->gran_to[i]); - strncat(final_to, snd_msg, final_to_sz); - final_to_sz -= strlen(snd_msg) + 2; - - i++; - continue; + close(socket); + return (OS_INVALID); } - } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg); + free(msg); - /* Send the "DATA" msg */ - OS_SendTCP(socket, DATAMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) { - merror(DATA_ERROR); - if (msg) { - free(msg); - } - close(socket); - return (OS_INVALID); + /* Build "From" and "To" in the e-mail header */ + OS_SendTCP(socket, final_to); } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg); - free(msg); - - /* Build "From" and "To" in the e-mail header */ - OS_SendTCP(socket, final_to); memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, FROM, mail->from); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } /* Send date */ memset(snd_msg, '\0', 128); @@ -201,50 +214,63 @@ int OS_Sendsms(MailConfig *mail, struct tm *p, MailMsg *sms_msg) strftime(snd_msg, 127, "Date: %a, %d %b %Y %T %z\r\n", p); #endif - OS_SendTCP(socket, snd_msg); + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } /* Send subject */ memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, SUBJECT, sms_msg->subject); - OS_SendTCP(socket, snd_msg); - OS_SendTCP(socket, ENDHEADER); - /* Send body */ - OS_SendTCP(socket, sms_msg->body); + if (sendmail) { + fprintf(sendmail, snd_msg); + fprintf(sendmail, ENDHEADER); + fprintf(sendmail, sms_msg->body); + fclose(sendmail); + } else { + OS_SendTCP(socket, snd_msg); + OS_SendTCP(socket, ENDHEADER); + + /* Send body */ + OS_SendTCP(socket, sms_msg->body); - /* Send end of data \r\n.\r\n */ - OS_SendTCP(socket, ENDDATA); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if (mail->strict_checking && ((msg == NULL) || (!OS_Match(VALIDMAIL, msg)))) { - merror(END_DATA_ERROR); + /* Send end of data \r\n.\r\n */ + OS_SendTCP(socket, ENDDATA); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if (mail->strict_checking && ((msg == NULL) || (!OS_Match(VALIDMAIL, msg)))) { + merror(END_DATA_ERROR); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); + } + /* Check msg, since it may be null */ if (msg) { free(msg); } - close(socket); - return (OS_INVALID); - } - /* Check msg, since it may be null */ - if (msg) { - free(msg); - } - /* Quit and close socket */ - OS_SendTCP(socket, QUITMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); + /* Quit and close socket */ + OS_SendTCP(socket, QUITMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + + if (msg) { + free(msg); + } - if (msg) { - free(msg); + close(socket); } memset_secure(snd_msg, '\0', 128); - close(socket); - return (0); } int OS_Sendmail(MailConfig *mail, struct tm *p) { - int socket; + FILE *sendmail = NULL; + int socket = -1; unsigned int i = 0; char *msg; char snd_msg[128]; @@ -259,100 +285,81 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) return (OS_INVALID); } - /* Connect to the SMTP server */ - socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, mail->smtpserver, 0, NULL); - if (socket < 0) { - return (socket); - } - - /* Receive the banner */ - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) { - merror(BANNER_ERROR); - if (msg) { - free(msg); + if (mail->smtpserver[0] == '/') { + sendmail = popen(mail->smtpserver, "w"); + if (!sendmail) { + return (OS_INVALID); } - close(socket); - return (OS_INVALID); - } - MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, ""); - free(msg); - - /* Send HELO message */ - memset(snd_msg, '\0', 128); - if (mail->heloserver) { - snprintf(snd_msg, 127, "Helo %s\r\n", mail->heloserver); } else { - snprintf(snd_msg, 127, "Helo %s\r\n", "notify.ossec.net"); - } - OS_SendTCP(socket, snd_msg); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - if (msg) { - /* In some cases (with virus scans in the middle) - * we may get two banners. Check for that in here. - */ - if (OS_Match(VALIDBANNER, msg)) { + /* Connect to the SMTP server */ + socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, mail->smtpserver, 0, NULL); + if (socket < 0) { + return (socket); + } + + /* Receive the banner */ + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) { + merror(BANNER_ERROR); + if (msg) { free(msg); + } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, ""); + free(msg); - /* Try again */ - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null"); - if (msg) { - free(msg); + /* Send HELO message */ + memset(snd_msg, '\0', 128); + if (mail->heloserver) { + snprintf(snd_msg, 127, "Helo %s\r\n", mail->heloserver); + } else { + snprintf(snd_msg, 127, "Helo %s\r\n", "notify.ossec.net"); + } + OS_SendTCP(socket, snd_msg); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + if (msg) { + /* In some cases (with virus scans in the middle) + * we may get two banners. Check for that in here. + */ + if (OS_Match(VALIDBANNER, msg)) { + free(msg); + + /* Try again */ + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null"); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); } + } else { + merror("%s:%s", HELO_ERROR, msg); + free(msg); close(socket); return (OS_INVALID); } } else { - merror("%s:%s", HELO_ERROR, msg); - free(msg); + merror("%s:%s", HELO_ERROR, "null"); close(socket); return (OS_INVALID); } - } else { - merror("%s:%s", HELO_ERROR, "null"); - close(socket); - return (OS_INVALID); } - } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); + free(msg); - /* Build "Mail from" msg */ - memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, MAILFROM, mail->from); - OS_SendTCP(socket, snd_msg); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(FROM_ERROR); - if (msg) { - free(msg); - } - close(socket); - return (OS_INVALID); - } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); - - /* Build "RCPT TO" msg */ - while (1) { - if (mail->to[i] == NULL) { - if (i == 0) { - merror(INTERNAL_ERROR); - close(socket); - return (OS_INVALID); - } - break; - } + /* Build "Mail from" msg */ memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, RCPTTO, mail->to[i++]); + snprintf(snd_msg, 127, MAILFROM, mail->from); OS_SendTCP(socket, snd_msg); msg = OS_RecvTCP(socket, OS_SIZE_1024); if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(TO_ERROR, mail->to[i - 1]); + merror(FROM_ERROR); if (msg) { free(msg); } @@ -361,61 +368,96 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) } MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); free(msg); - } - /* Additional RCPT to */ - if (mail->gran_to) { - i = 0; - while (mail->gran_to[i] != NULL) { - if (mail->gran_set[i] != FULL_FORMAT) { - i++; - continue; + /* Build "RCPT TO" msg */ + while (1) { + if (mail->to[i] == NULL) { + if (i == 0) { + merror(INTERNAL_ERROR); + close(socket); + return (OS_INVALID); + } + break; } - memset(snd_msg, '\0', 128); - snprintf(snd_msg, 127, RCPTTO, mail->gran_to[i]); + snprintf(snd_msg, 127, RCPTTO, mail->to[i++]); OS_SendTCP(socket, snd_msg); msg = OS_RecvTCP(socket, OS_SIZE_1024); if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { - merror(TO_ERROR, mail->gran_to[i]); + merror(TO_ERROR, mail->to[i - 1]); if (msg) { free(msg); } + close(socket); + return (OS_INVALID); + } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); + free(msg); + } + + /* Additional RCPT to */ + if (mail->gran_to) { + i = 0; + while (mail->gran_to[i] != NULL) { + if (mail->gran_set[i] != FULL_FORMAT) { + i++; + continue; + } + + memset(snd_msg, '\0', 128); + snprintf(snd_msg, 127, RCPTTO, mail->gran_to[i]); + OS_SendTCP(socket, snd_msg); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) { + merror(TO_ERROR, mail->gran_to[i]); + if (msg) { + free(msg); + } + + i++; + continue; + } + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); + free(msg); i++; continue; } - - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg); - free(msg); - i++; - continue; } - } - /* Send the "DATA" msg */ - OS_SendTCP(socket, DATAMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) { - merror(DATA_ERROR); - if (msg) { - free(msg); + /* Send the "DATA" msg */ + OS_SendTCP(socket, DATAMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) { + merror(DATA_ERROR); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); } - close(socket); - return (OS_INVALID); + MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg); + free(msg); } - MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg); - free(msg); - /* Building "From" and "To" in the e-mail header */ memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, TO, mail->to[0]); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, FROM, mail->from); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } /* Add CCs */ if (mail->to[1]) { @@ -427,7 +469,12 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, TO, mail->to[i]); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } i++; } @@ -444,7 +491,13 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, TO, mail->gran_to[i]); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } + i++; continue; } @@ -460,13 +513,22 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) strftime(snd_msg, 127, "Date: %a, %d %b %Y %T %z\r\n", p); #endif - OS_SendTCP(socket, snd_msg); + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } if (mail->idsname) { /* Send server name header */ memset(snd_msg, '\0', 128); snprintf(snd_msg, 127, XHEADER, mail->idsname); - OS_SendTCP(socket, snd_msg); + + if (sendmail) { + fprintf(sendmail, snd_msg); + } else { + OS_SendTCP(socket, snd_msg); + } } /* Send subject */ @@ -482,45 +544,58 @@ int OS_Sendmail(MailConfig *mail, struct tm *p) } else { snprintf(snd_msg, 127, SUBJECT, mailmsg->mail->subject); } - OS_SendTCP(socket, snd_msg); - OS_SendTCP(socket, ENDHEADER); + + if (sendmail) { + fprintf(sendmail, snd_msg); + fprintf(sendmail, ENDHEADER); + } else { + OS_SendTCP(socket, snd_msg); + OS_SendTCP(socket, ENDHEADER); + } /* Send body */ /* Send multiple emails together if we have to */ do { - OS_SendTCP(socket, mailmsg->mail->body); + if (sendmail) { + fprintf(sendmail, mailmsg->mail->body); + } else { + OS_SendTCP(socket, mailmsg->mail->body); + } mailmsg = OS_PopLastMail(); } while (mailmsg); - /* Send end of data \r\n.\r\n */ - OS_SendTCP(socket, ENDDATA); - msg = OS_RecvTCP(socket, OS_SIZE_1024); - if (mail->strict_checking && ((msg == NULL) || (!OS_Match(VALIDMAIL, msg)))) { - merror(END_DATA_ERROR); + if (sendmail) { + fclose(sendmail); + } else { + /* Send end of data \r\n.\r\n */ + OS_SendTCP(socket, ENDDATA); + msg = OS_RecvTCP(socket, OS_SIZE_1024); + if (mail->strict_checking && ((msg == NULL) || (!OS_Match(VALIDMAIL, msg)))) { + merror(END_DATA_ERROR); + if (msg) { + free(msg); + } + close(socket); + return (OS_INVALID); + } + + /* Check msg, since it may be null */ if (msg) { free(msg); } - close(socket); - return (OS_INVALID); - } - /* Check msg, since it may be null */ - if (msg) { - free(msg); - } + /* Quit and close socket */ + OS_SendTCP(socket, QUITMSG); + msg = OS_RecvTCP(socket, OS_SIZE_1024); - /* Quit and close socket */ - OS_SendTCP(socket, QUITMSG); - msg = OS_RecvTCP(socket, OS_SIZE_1024); + if (msg) { + free(msg); + } - if (msg) { - free(msg); + close(socket); } memset_secure(snd_msg, '\0', 128); - close(socket); - return (0); } -