Skip to content

Commit 5e9e308

Browse files
author
Baptiste Daroussin
committed
Split body of mails not respecting RFC2822
For mails where the body does not respect RFC2822, try to split by words finding the last space before 1000's character If no spaces are found then consider the mail to be malformed anyway This should address #18
1 parent 6748bdd commit 5e9e308

File tree

1 file changed

+59
-28
lines changed

1 file changed

+59
-28
lines changed

mail.c

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <signal.h>
3939
#include <syslog.h>
4040
#include <unistd.h>
41+
#include <ctype.h>
4142

4243
#include "dma.h"
4344

@@ -341,18 +342,49 @@ parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
341342
goto again;
342343
}
343344

345+
static int
346+
writeline(struct queue *queue, const char *line, ssize_t linelen)
347+
{
348+
const char *walk;
349+
350+
while (linelen > 0) {
351+
if (linelen > 1000) {
352+
walk = line + 1000;
353+
while (!isspace(*walk)) {
354+
if (walk == line)
355+
errlogx(EX_DATAERR, "bad mail input format:"
356+
" from %s (uid %d) (envelope-from %s)",
357+
username, useruid, queue->sender);
358+
walk--;
359+
}
360+
} else {
361+
walk = line + linelen;
362+
}
363+
if (fwrite(line, walk - line, 1, queue->mailf) != 1)
364+
return (-1);
365+
if (linelen <= 1000)
366+
break;
367+
if (fwrite("\n", 1, 1, queue->mailf) != 1)
368+
return (-1);
369+
line = walk + 1;
370+
linelen = strlen(line);
371+
}
372+
return (0);
373+
}
374+
344375
int
345376
readmail(struct queue *queue, int nodot, int recp_from_header)
346377
{
347378
struct parse_state parse_state;
348-
char line[1000]; /* by RFC2822 */
349-
size_t linelen;
379+
char *line = NULL;
380+
ssize_t linelen;
381+
size_t linecap = 0;
382+
char newline[1000];
350383
size_t error;
351384
int had_headers = 0;
352385
int had_from = 0;
353386
int had_messagid = 0;
354387
int had_date = 0;
355-
int had_last_line = 0;
356388
int nocopy = 0;
357389

358390
parse_state.state = NONE;
@@ -372,24 +404,15 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
372404
return (-1);
373405

374406
while (!feof(stdin)) {
375-
if (fgets(line, sizeof(line) - 1, stdin) == NULL)
407+
newline[0] = '\0';
408+
if ((linelen = getline(&line, &linecap, stdin)) <= 0)
376409
break;
377-
if (had_last_line)
378-
errlogx(EX_DATAERR, "bad mail input format:"
379-
" from %s (uid %d) (envelope-from %s)",
380-
username, useruid, queue->sender);
381-
linelen = strlen(line);
382-
if (linelen == 0 || line[linelen - 1] != '\n') {
383-
/*
384-
* This line did not end with a newline character.
385-
* If we fix it, it better be the last line of
386-
* the file.
387-
*/
388-
line[linelen] = '\n';
389-
line[linelen + 1] = 0;
390-
had_last_line = 1;
391-
}
392410
if (!had_headers) {
411+
if (linelen > 1000)
412+
errlogx(EX_DATAERR, "bad mail input format:"
413+
" from %s (uid %d) (envelope-from %s)",
414+
username, useruid, queue->sender);
415+
393416
/*
394417
* Unless this is a continuation, switch of
395418
* the Bcc: nocopy flag.
@@ -425,36 +448,44 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
425448
}
426449
}
427450

428-
if (strcmp(line, "\n") == 0 && !had_headers) {
451+
if (line[0] == '\n' && !had_headers) {
429452
had_headers = 1;
430453
while (!had_date || !had_messagid || !had_from) {
431454
if (!had_date) {
432455
had_date = 1;
433-
snprintf(line, sizeof(line), "Date: %s\n", rfc822date());
456+
snprintf(newline, sizeof(newline), "Date: %s\n", rfc822date());
434457
} else if (!had_messagid) {
435458
/* XXX msgid, assign earlier and log? */
436459
had_messagid = 1;
437-
snprintf(line, sizeof(line), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
460+
snprintf(newline, sizeof(newline), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
438461
(uintmax_t)time(NULL),
439462
queue->id,
440463
(uintmax_t)random(),
441464
hostname());
442465
} else if (!had_from) {
443466
had_from = 1;
444-
snprintf(line, sizeof(line), "From: <%s>\n", queue->sender);
467+
snprintf(newline, sizeof(newline), "From: <%s>\n", queue->sender);
445468
}
446-
if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
447-
return (-1);
469+
if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)
470+
goto fail;
448471
}
449-
strcpy(line, "\n");
472+
strlcpy(newline, "\n", sizeof(newline));
450473
}
451474
if (!nodot && linelen == 2 && line[0] == '.')
452475
break;
453476
if (!nocopy) {
454-
if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
455-
return (-1);
477+
if (newline[0] != '\0') {
478+
if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)
479+
goto fail;
480+
} else {
481+
if (writeline(queue, line, linelen) != 0)
482+
goto fail;
483+
}
456484
}
457485
}
458486

459487
return (0);
488+
fail:
489+
free(line);
490+
return (-1);
460491
}

0 commit comments

Comments
 (0)