Skip to content

Commit

Permalink
Allow maild to send through a sendmail-like executable
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
chewi committed Nov 16, 2015
1 parent 524724d commit e8ed375
Show file tree
Hide file tree
Showing 4 changed files with 498 additions and 371 deletions.
12 changes: 8 additions & 4 deletions src/config/global-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 7 additions & 5 deletions src/os_maild/maild.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
240 changes: 143 additions & 97 deletions src/os_maild/sendcustomemail.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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]) {
Expand All @@ -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++;
}
Expand All @@ -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);
}

Loading

0 comments on commit e8ed375

Please sign in to comment.