Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ parse_conf(const char *config_path)
config.features |= FULLBOUNCE;
else if (strcmp(word, "NULLCLIENT") == 0 && data == NULL)
config.features |= NULLCLIENT;
else if (strcmp(word, "REWRITEFROM") == 0 && data == NULL)
config.features |= REWRITEFROM;
else {
errlogx(EX_CONFIG, "syntax error in %s:%d", config_path, lineno);
/* NOTREACHED */
Expand Down
8 changes: 8 additions & 0 deletions dma.8
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ setting it to
will send all mails as
.Ql Sm off Va username @percolator .
.Sm on
.Pp
You usually want to combine this setting with
.Sq REWRITEFROM .
.It Ic NULLCLIENT Xo
(boolean, default=commented)
.Xc
Expand All @@ -325,6 +328,11 @@ the defined
requires
.Sq SMARTHOST
to be set.
.It Ic REWRITEFROM Xo
(boolean, default=commented)
.Xc
Rewrite the message header "From" address to the envelope-from address.
The original unmodified header is added as "X-Original-From".
.El
.Ss Environment variables
The behavior of
Expand Down
6 changes: 5 additions & 1 deletion dma.conf
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

# Masquerade envelope from addresses with this address/hostname.
# Use this if mails are not accepted by destination mail servers because
# your sender domain is invalid.
# your sender domain is invalid. You usually also want REWRITEFROM.
# By default, MASQUERADE is not set.
# Format: MASQUERADE [user@][host]
# Examples:
Expand All @@ -68,3 +68,7 @@

# Directly forward the mail to the SMARTHOST bypassing aliases and local delivery
#NULLCLIENT

# Rewrite the message header "From" address to the envelope-from address.
# The original unmodified header is added as "X-Original-From".
# REWRITEFROM
10 changes: 10 additions & 0 deletions dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
#define ERRMSG_SIZE 1024
#define USERNAME_SIZE 50
#define EHLO_RESPONSE_SIZE BUF_SIZE
#define MSG_LINE_MAX 1000 /* maximum line length in a message, by RFC2822 */
#define MSG_HDR_FROM_MAX 10*MSG_LINE_MAX /* maximum size of "From" header lines */
#define MIN_RETRY 300 /* 5 minutes */
#define MAX_RETRY (3*60*60) /* retry at least every 3 hours */
#define MAX_TIMEOUT (5*24*60*60) /* give up after 5 days */
Expand All @@ -70,6 +72,7 @@
#define FULLBOUNCE 0x040 /* Bounce the full message */
#define TLS_OPP 0x080 /* Opportunistic STARTTLS */
#define NULLCLIENT 0x100 /* Nullclient support */
#define REWRITEFROM 0x200 /* rewrite header From to envelope from */

#ifndef CONF_PATH
#error Please define CONF_PATH
Expand Down Expand Up @@ -119,12 +122,19 @@ struct qitem {
};
LIST_HEAD(queueh, qitem);

struct msg_hdr {
char from_addr[MSG_LINE_MAX];
char from_lines[MSG_HDR_FROM_MAX];
char rewritten_from_lines[MSG_HDR_FROM_MAX];
};

struct queue {
struct queueh queue;
char *id;
FILE *mailf;
char *tmpf;
const char *sender;
struct msg_hdr header;
};

struct config {
Expand Down
107 changes: 96 additions & 11 deletions mail.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,56 @@ bounce(struct qitem *it, const char *reason)
exit(EX_IOERR);
}

static size_t
rewrite_header_from(struct msg_hdr *header, const char *sender)
{
size_t len_addr = strlen(header->from_addr);
size_t len_lines = strlen(header->from_lines);
size_t i = 0;

if (len_lines > len_addr && len_addr != 0) {
i = len_lines - len_addr;
/* XXX this doesn't work if from_addr is split into multiple lines */
while (strncmp(header->from_addr, header->from_lines + i, len_addr) != 0 && i >= 0) {
if ( i == 0 ) break;
i--;
}
}

if ( i == 0 ) {
syslog(LOG_INFO, "could not rewrite From in header");
} else if ( (len_lines - len_addr) + strlen(sender) + 1 > MSG_HDR_FROM_MAX ) {
syslog(LOG_INFO, "could not rewrite From in header: rewritten lines too long");
i = 0;
}

if ( i == 0 ) {
/* cannot rewrite so substitute with envelope-from anyway */
strcpy(stpcpy(stpcpy(header->rewritten_from_lines, "From: <"), sender), ">\n");
return (strlen(header->rewritten_from_lines));
}

/* do the rewrite */
strcpy(stpcpy(stpncpy(header->rewritten_from_lines,
header->from_lines, i),
sender),
header->from_lines + i + len_addr);

return (strlen(header->rewritten_from_lines));
}

typedef int
(*add_addr_funcptr_t)(struct queue *queue, const char *str, int expand);

int
add_header_from_addr(struct queue *queue, const char *str, int expand)
{
strcpy(queue->header.from_addr, str);
return (0);
}

struct parse_state {
char addr[1000];
char addr[MSG_LINE_MAX];
int pos;

enum {
Expand All @@ -162,7 +210,7 @@ struct parse_state {
* XXX local addresses will need treatment
*/
static int
parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
parse_addrs(struct parse_state *ps, char *s, struct queue *queue, add_addr_funcptr_t add_addr_funcptr)
{
char *addr;

Expand Down Expand Up @@ -337,8 +385,8 @@ parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
if (addr == NULL)
errlog(EX_SOFTWARE, NULL);

if (add_recp(queue, addr, EXPAND_WILDCARD) != 0)
errlogx(EX_DATAERR, "invalid recipient `%s'", addr);
if (add_addr_funcptr(queue, addr, EXPAND_WILDCARD) != 0)
errlogx(EX_DATAERR, "invalid address `%s'", addr);

goto again;
}
Expand All @@ -347,7 +395,7 @@ int
readmail(struct queue *queue, int nodot, int recp_from_header)
{
struct parse_state parse_state;
char line[1000]; /* by RFC2822 */
char line[MSG_LINE_MAX];
size_t linelen;
size_t error;
int had_headers = 0;
Expand All @@ -357,8 +405,10 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
int had_first_line = 0;
int had_last_line = 0;
int nocopy = 0;
size_t len_rewritten_from_lines;

parse_state.state = NONE;
add_addr_funcptr_t add_addr_funcptr = NULL;

error = fprintf(queue->mailf,
"Received: from %s (uid %d)\n"
Expand Down Expand Up @@ -403,8 +453,8 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
}
if (!had_headers) {
/*
* Unless this is a continuation, switch of
* the Bcc: nocopy flag.
* Unless this is a continuation, switch off
* the nocopy flag.
*/
if (!(line[0] == ' ' || line[0] == '\t'))
nocopy = 0;
Expand All @@ -413,28 +463,51 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
had_date = 1;
else if (strprefixcmp(line, "Message-Id:") == 0)
had_messagid = 1;
else if (strprefixcmp(line, "From:") == 0)
else if (strprefixcmp(line, "From:") == 0) {
had_from = 1;
if (config.features & REWRITEFROM) {
/* do not copy From, we'll add it later */
nocopy = 1;
}
}
else if (strprefixcmp(line, "Bcc:") == 0)
nocopy = 1;

if (parse_state.state != NONE) {
if (parse_addrs(&parse_state, line, queue) < 0) {
if (parse_addrs(&parse_state, line, queue, add_addr_funcptr) < 0) {
errlogx(EX_DATAERR, "invalid address in header\n");
/* NOTREACHED */
}
if (add_addr_funcptr == &add_header_from_addr && parse_state.state != QUIT) {
if ((strlen(queue->header.from_lines)+strlen(line)+1) > MSG_HDR_FROM_MAX)
errlogx(EX_DATAERR, "header From too long\n");
strcat(queue->header.from_lines, line);
}
}

if (recp_from_header && (
strprefixcmp(line, "To:") == 0 ||
strprefixcmp(line, "Cc:") == 0 ||
strprefixcmp(line, "Bcc:") == 0)) {
parse_state.state = START;
if (parse_addrs(&parse_state, line, queue) < 0) {
errlogx(EX_DATAERR, "invalid address in header\n");
add_addr_funcptr = &add_recp;
if (parse_addrs(&parse_state, line, queue, add_addr_funcptr) < 0) {
errlogx(EX_DATAERR, "invalid recipient in header\n");
/* NOTREACHED */
}
}

if (strprefixcmp(line, "From:") == 0) {
strcpy(queue->header.from_lines, line);
parse_state.state = START;
add_addr_funcptr = &add_header_from_addr;
if (parse_addrs(&parse_state, line, queue, add_addr_funcptr) < 0) {
errlogx(EX_DATAERR, "invalid From in header\n");
/* NOTREACHED */
}

}

}

if (strcmp(line, "\n") == 0 && !had_headers) {
Expand All @@ -453,11 +526,23 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
hostname());
} else if (!had_from) {
had_from = 1;
config.features &= ~REWRITEFROM;
snprintf(line, sizeof(line), "From: <%s>\n", queue->sender);
}
if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
return (-1);
}

if (config.features & REWRITEFROM) {
config.features &= ~REWRITEFROM;

len_rewritten_from_lines = rewrite_header_from(&queue->header, queue->sender);
if (fwrite(queue->header.rewritten_from_lines, len_rewritten_from_lines, 1, queue->mailf) != 1 ||
fwrite("X-Original-From:", 16, 1, queue->mailf) != 1 ||
fwrite(queue->header.from_lines + 5, strlen(queue->header.from_lines) - 5, 1, queue->mailf) != 1)
return (-1);
}

strcpy(line, "\n");
}
if (!nodot && linelen == 2 && line[0] == '.')
Expand Down