2000-12-13 13:19:03 +00:00
|
|
|
/*
|
2019-07-10 13:00:47 +00:00
|
|
|
* Copyright (c) 1995-2019 Peter Simons <simons@cryp.to>
|
2010-02-24 16:01:14 +00:00
|
|
|
* Copyright (c) 2000-2001 Cable & Wireless GmbH
|
|
|
|
|
* Copyright (c) 1999-2000 CyberSolutions GmbH
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
|
* Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
|
* version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
|
* details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2000-12-13 13:19:03 +00:00
|
|
|
|
2013-02-09 19:13:50 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
|
2000-12-13 13:19:03 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
2000-12-13 15:35:14 +00:00
|
|
|
#include "librfc822/rfc822.h"
|
|
|
|
|
#include "libtext/text.h"
|
|
|
|
|
#include "petidomo.h"
|
2000-12-13 13:19:03 +00:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
RemoveCarrigeReturns(char * buffer)
|
|
|
|
|
{
|
|
|
|
|
char * src = buffer;
|
|
|
|
|
char * dst = buffer;
|
|
|
|
|
|
|
|
|
|
while(*src != '\0') {
|
2010-02-24 16:24:28 +00:00
|
|
|
switch(*src) {
|
|
|
|
|
case '\n':
|
|
|
|
|
*dst++ = ' ';
|
|
|
|
|
while(isspace((int)*src))
|
|
|
|
|
src++;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
}
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
*dst++ = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
isRFC822Address(const char * buffer)
|
|
|
|
|
{
|
|
|
|
|
char * address;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
rc = rfc822_parse_address(buffer, &address, NULL, NULL);
|
|
|
|
|
if (rc == RFC822_OK) {
|
2010-02-24 16:09:53 +00:00
|
|
|
free(address);
|
2010-02-24 16:24:28 +00:00
|
|
|
return TRUE;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
2000-12-15 15:48:00 +00:00
|
|
|
else
|
2010-02-24 16:24:28 +00:00
|
|
|
return FALSE;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ParseAddressLine(char * buffer)
|
|
|
|
|
{
|
|
|
|
|
struct rfc822_address_sep_state sep_state;
|
|
|
|
|
char * p,
|
2010-02-24 16:24:28 +00:00
|
|
|
* address;
|
2000-12-13 13:19:03 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
/* Handle continuation lines. */
|
|
|
|
|
|
|
|
|
|
RemoveCarrigeReturns(buffer);
|
|
|
|
|
|
|
|
|
|
/* Initialize the structure needed for address_sep(). */
|
|
|
|
|
|
|
|
|
|
sep_state.address_line = buffer;
|
|
|
|
|
sep_state.group_nest = 0;
|
|
|
|
|
|
|
|
|
|
/* We want only the first address, if multiple are there. */
|
|
|
|
|
|
|
|
|
|
while ((p = rfc822_address_sep(&sep_state)) != NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
if (*p == '\0')
|
|
|
|
|
continue;
|
|
|
|
|
else
|
|
|
|
|
break;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
/* line is empty */
|
|
|
|
|
return -1;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = rfc822_parse_address(p, &address, NULL, NULL);
|
|
|
|
|
if (rc == RFC822_OK && address != NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
strcpy(buffer, address);
|
|
|
|
|
free(address);
|
|
|
|
|
return 0;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ParseReplyToLine(char * buffer)
|
|
|
|
|
{
|
|
|
|
|
return ParseAddressLine(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ParseFromLine(char * buffer)
|
|
|
|
|
{
|
|
|
|
|
return ParseAddressLine(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ParseMessageIdLine(char * buffer)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
rc = ParseAddressLine(buffer);
|
|
|
|
|
if (rc != 0)
|
2010-02-24 16:24:28 +00:00
|
|
|
return rc; /* Error! */
|
2000-12-13 13:19:03 +00:00
|
|
|
|
|
|
|
|
memmove(buffer+1, buffer, strlen(buffer)+1);
|
|
|
|
|
buffer[0] = '<';
|
|
|
|
|
strcat(buffer, ">");
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ParseApproveLine(char * buffer)
|
|
|
|
|
{
|
|
|
|
|
char * src;
|
|
|
|
|
char * dst;
|
|
|
|
|
|
|
|
|
|
RemoveCarrigeReturns(buffer);
|
|
|
|
|
|
|
|
|
|
src = buffer;
|
|
|
|
|
dst = buffer;
|
|
|
|
|
|
|
|
|
|
/* Skip leading whitespace. */
|
|
|
|
|
|
|
|
|
|
while(isspace((int)*src))
|
|
|
|
|
src++;
|
|
|
|
|
|
|
|
|
|
/* Skip a quote if there is one. */
|
|
|
|
|
|
|
|
|
|
if (*src == '\"')
|
|
|
|
|
src++;
|
|
|
|
|
|
|
|
|
|
/* Copy String. */
|
|
|
|
|
|
|
|
|
|
while((*dst++ = *src++) != '\0')
|
|
|
|
|
;
|
|
|
|
|
dst--;
|
|
|
|
|
|
|
|
|
|
/* Kill trailing whitespace. */
|
|
|
|
|
|
|
|
|
|
while(isspace((int)dst[-1]))
|
|
|
|
|
*(--dst) = '\0';
|
|
|
|
|
|
|
|
|
|
/* Kill a quote if there is one. */
|
|
|
|
|
|
|
|
|
|
if (dst[-1] == '\"')
|
|
|
|
|
*(--dst) = '\0';
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CanonizeAddress(char ** buffer, const char * fqdn)
|
|
|
|
|
{
|
|
|
|
|
const struct PD_Config * MasterConfig;
|
|
|
|
|
char * newbuf;
|
|
|
|
|
char * local,
|
|
|
|
|
* host;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
assert(buffer != NULL);
|
|
|
|
|
assert(*buffer != NULL);
|
|
|
|
|
|
|
|
|
|
if (buffer == NULL || *buffer == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
rc = rfc822_parse_address(*buffer, NULL, &local, &host);
|
|
|
|
|
if (rc == RFC822_OK) {
|
|
|
|
|
if (local != NULL && host == NULL) {
|
2010-02-24 16:24:28 +00:00
|
|
|
if (fqdn == NULL) {
|
|
|
|
|
MasterConfig = getMasterConfig();
|
|
|
|
|
fqdn = MasterConfig->fqdn;
|
|
|
|
|
}
|
|
|
|
|
newbuf = xmalloc(strlen(*buffer) + strlen(fqdn) + 3);
|
|
|
|
|
sprintf(newbuf, "%s@%s", local, fqdn);
|
|
|
|
|
free(local);
|
|
|
|
|
*buffer = newbuf;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ParseMail(struct Mail **result, char * incoming_mail, const char * fqdn)
|
|
|
|
|
{
|
|
|
|
|
struct Mail * MailStruct;
|
|
|
|
|
char * currLine;
|
|
|
|
|
char * nextLine;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
/* Allocate structure. */
|
|
|
|
|
|
|
|
|
|
MailStruct = calloc(sizeof(struct Mail), 1);
|
|
|
|
|
if (MailStruct == NULL) {
|
2013-02-09 18:03:52 +00:00
|
|
|
syslog(LOG_ERR, "Failed to allocate memory for Mail data structure.");
|
2010-02-24 16:24:28 +00:00
|
|
|
return -1;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Rescue the mail in its original state, before the parsing
|
|
|
|
|
routines have havoc in the buffer. */
|
|
|
|
|
|
|
|
|
|
MailStruct->Header = strdup(incoming_mail);
|
|
|
|
|
if (MailStruct->Header == NULL) {
|
2013-02-09 18:03:52 +00:00
|
|
|
syslog(LOG_ERR, "Failed to allocate memory for the incoming mail.");
|
2010-02-24 16:24:28 +00:00
|
|
|
return -1;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
for (MailStruct->Body = MailStruct->Header;
|
2010-02-24 16:24:28 +00:00
|
|
|
*MailStruct->Body != '\n' && *MailStruct->Body != '\0';
|
|
|
|
|
MailStruct->Body = text_find_next_line(MailStruct->Body))
|
2000-12-13 13:19:03 +00:00
|
|
|
;
|
|
|
|
|
if (*MailStruct->Body == '\n') {
|
2010-02-24 16:24:28 +00:00
|
|
|
*MailStruct->Body = '\0';
|
|
|
|
|
MailStruct->Body++;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the envelope. */
|
|
|
|
|
|
|
|
|
|
currLine = incoming_mail;
|
|
|
|
|
nextLine = text_find_next_line(incoming_mail);
|
|
|
|
|
if (strncasecmp("From ", currLine, strlen("From ")) == 0) {
|
2010-02-24 16:24:28 +00:00
|
|
|
if (nextLine[-1] == '\n')
|
|
|
|
|
nextLine[-1] = '\0';
|
|
|
|
|
currLine += strlen("From ");
|
|
|
|
|
while (isspace((int)*currLine))
|
|
|
|
|
currLine++;
|
|
|
|
|
MailStruct->Envelope = currLine;
|
|
|
|
|
while (!isspace((int)*currLine))
|
|
|
|
|
currLine++;
|
|
|
|
|
*currLine = '\0';
|
|
|
|
|
CanonizeAddress(&(MailStruct->Envelope), fqdn);
|
|
|
|
|
currLine = nextLine;
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the incoming mail's header. */
|
|
|
|
|
|
|
|
|
|
for (nextLine = text_find_next_line(currLine);
|
2010-02-24 16:24:28 +00:00
|
|
|
*currLine != '\n' && *currLine != '\0';
|
|
|
|
|
currLine = nextLine, nextLine = text_find_next_line(currLine)) {
|
|
|
|
|
|
|
|
|
|
/* Find continuation lines. */
|
|
|
|
|
|
|
|
|
|
while (*nextLine == ' ' || *nextLine == '\t')
|
|
|
|
|
nextLine = text_find_next_line(nextLine);
|
|
|
|
|
|
|
|
|
|
/* remove trailing \n */
|
|
|
|
|
|
|
|
|
|
if (nextLine[-1] == '\n')
|
|
|
|
|
nextLine[-1] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Check whether it is a header we're interested in. */
|
|
|
|
|
|
|
|
|
|
if (strncasecmp("From:", currLine, strlen("From:")) == 0) {
|
|
|
|
|
if (MailStruct->From != NULL) {
|
|
|
|
|
syslog(LOG_INFO, "Received mail with multiple From: lines.");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
MailStruct->From = &currLine[strlen("From:")];
|
|
|
|
|
rc = ParseFromLine(MailStruct->From);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
return rc;
|
|
|
|
|
CanonizeAddress(&(MailStruct->From), fqdn);
|
|
|
|
|
} else if (strncasecmp("Reply-To:", currLine, strlen("Reply-To:")) == 0) {
|
|
|
|
|
if (MailStruct->Reply_To != NULL) {
|
|
|
|
|
syslog(LOG_INFO, "Received mail with multiple Reply-To: lines.");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
MailStruct->Reply_To = &currLine[strlen("Reply-To:")];
|
|
|
|
|
rc = ParseReplyToLine(MailStruct->Reply_To);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
return rc;
|
|
|
|
|
CanonizeAddress(&(MailStruct->Reply_To), fqdn);
|
|
|
|
|
} else if (strncasecmp("Message-Id:", currLine, strlen("Message-Id:")) == 0) {
|
|
|
|
|
if (MailStruct->Message_Id != NULL) {
|
|
|
|
|
syslog(LOG_NOTICE, "Received mail with multiple Message-Id: lines.");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
MailStruct->Message_Id = &currLine[strlen("Message-Id:")];
|
|
|
|
|
rc = ParseMessageIdLine(MailStruct->Message_Id);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
else if (strncasecmp("Approve:", currLine, strlen("Approve:")) == 0) {
|
|
|
|
|
if (MailStruct->Approve != NULL)
|
|
|
|
|
syslog(LOG_INFO, "Received mail with multiple Approve: lines.");
|
|
|
|
|
MailStruct->Approve = &currLine[strlen("Approve:")];
|
|
|
|
|
rc = ParseApproveLine(MailStruct->Approve);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
else if (strncasecmp("Approved:", currLine, strlen("Approved:")) == 0) {
|
|
|
|
|
if (MailStruct->Approve != NULL)
|
|
|
|
|
syslog(LOG_INFO, "Received mail with multiple Approve: lines.");
|
|
|
|
|
MailStruct->Approve = &currLine[strlen("Approved:")];
|
|
|
|
|
rc = ParseApproveLine(MailStruct->Approve);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
else if (strncasecmp("Subject:", currLine, strlen("Subject:")) == 0) {
|
|
|
|
|
if (MailStruct->Subject != NULL)
|
|
|
|
|
syslog(LOG_INFO, "Received mail with multiple Subject: lines.");
|
|
|
|
|
MailStruct->Subject = &currLine[strlen("Subject:")];
|
|
|
|
|
if (*MailStruct->Subject == ' ')
|
|
|
|
|
MailStruct->Subject += 1;
|
|
|
|
|
}
|
|
|
|
|
else if (strncasecmp("Sender:", currLine, strlen("Sender:")) == 0) {
|
|
|
|
|
if (MailStruct->Envelope != NULL)
|
|
|
|
|
syslog(LOG_NOTICE, "Received mail with multiple sender addresses.");
|
|
|
|
|
MailStruct->Envelope = &currLine[strlen("Sender:")];
|
|
|
|
|
if (*MailStruct->Envelope == ' ')
|
|
|
|
|
MailStruct->Envelope += 1;
|
|
|
|
|
}
|
|
|
|
|
else if (strncasecmp("Return-Path:", currLine, strlen("Return-Path:")) == 0 &&
|
|
|
|
|
MailStruct->Envelope == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (MailStruct->Envelope != NULL)
|
|
|
|
|
syslog(LOG_NOTICE, "Received mail with multiple sender addresses.");
|
|
|
|
|
MailStruct->Envelope = &currLine[strlen("Return-Path:")];
|
|
|
|
|
if (*MailStruct->Envelope == ' ')
|
|
|
|
|
MailStruct->Envelope += 1;
|
|
|
|
|
}
|
2000-12-13 13:19:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*result = MailStruct;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|