Skip to content

Commit aaf58a5

Browse files
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 aaf58a5

File tree

1 file changed

+67
-28
lines changed

1 file changed

+67
-28
lines changed

mail.c

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@
3333
* SUCH DAMAGE.
3434
*/
3535

36+
#include "dfcompat.h"
37+
38+
#include <ctype.h>
3639
#include <errno.h>
3740
#include <inttypes.h>
3841
#include <signal.h>
42+
#include <stdio.h>
3943
#include <syslog.h>
4044
#include <unistd.h>
4145

@@ -341,18 +345,54 @@ parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
341345
goto again;
342346
}
343347

348+
static int
349+
writeline(struct queue *queue, const char *line, ssize_t linelen)
350+
{
351+
const char *walk;
352+
353+
while (linelen > 0) {
354+
/* if the line is too long, split on the last space of the line */
355+
if (linelen > 1000) {
356+
walk = line + 1000;
357+
while (!isspace(*walk)) {
358+
/*
359+
* if there is no spaces in the line we can
360+
* consider it as junk
361+
*/
362+
if (walk == line)
363+
errlogx(EX_DATAERR, "bad mail input format:"
364+
" from %s (uid %d) (envelope-from %s)",
365+
username, useruid, queue->sender);
366+
walk--;
367+
}
368+
} else {
369+
walk = line + linelen;
370+
}
371+
if (fwrite(line, walk - line, 1, queue->mailf) != 1)
372+
return (-1);
373+
if (linelen <= 1000)
374+
break;
375+
if (fwrite("\n", 1, 1, queue->mailf) != 1)
376+
return (-1);
377+
line = walk + 1;
378+
linelen = strlen(line);
379+
}
380+
return (0);
381+
}
382+
344383
int
345384
readmail(struct queue *queue, int nodot, int recp_from_header)
346385
{
347386
struct parse_state parse_state;
348-
char line[1000]; /* by RFC2822 */
349-
size_t linelen;
387+
char *line = NULL;
388+
ssize_t linelen;
389+
size_t linecap = 0;
390+
char newline[1000];
350391
size_t error;
351392
int had_headers = 0;
352393
int had_from = 0;
353394
int had_messagid = 0;
354395
int had_date = 0;
355-
int had_last_line = 0;
356396
int nocopy = 0;
357397

358398
parse_state.state = NONE;
@@ -372,24 +412,15 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
372412
return (-1);
373413

374414
while (!feof(stdin)) {
375-
if (fgets(line, sizeof(line) - 1, stdin) == NULL)
415+
newline[0] = '\0';
416+
if ((linelen = getline(&line, &linecap, stdin)) <= 0)
376417
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-
}
392418
if (!had_headers) {
419+
if (linelen > 1000)
420+
errlogx(EX_DATAERR, "bad mail input format:"
421+
" from %s (uid %d) (envelope-from %s)",
422+
username, useruid, queue->sender);
423+
393424
/*
394425
* Unless this is a continuation, switch of
395426
* the Bcc: nocopy flag.
@@ -425,36 +456,44 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
425456
}
426457
}
427458

428-
if (strcmp(line, "\n") == 0 && !had_headers) {
459+
if (line[0] == '\n' && !had_headers) {
429460
had_headers = 1;
430461
while (!had_date || !had_messagid || !had_from) {
431462
if (!had_date) {
432463
had_date = 1;
433-
snprintf(line, sizeof(line), "Date: %s\n", rfc822date());
464+
snprintf(newline, sizeof(newline), "Date: %s\n", rfc822date());
434465
} else if (!had_messagid) {
435466
/* XXX msgid, assign earlier and log? */
436467
had_messagid = 1;
437-
snprintf(line, sizeof(line), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
468+
snprintf(newline, sizeof(newline), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
438469
(uintmax_t)time(NULL),
439470
queue->id,
440471
(uintmax_t)random(),
441472
hostname());
442473
} else if (!had_from) {
443474
had_from = 1;
444-
snprintf(line, sizeof(line), "From: <%s>\n", queue->sender);
475+
snprintf(newline, sizeof(newline), "From: <%s>\n", queue->sender);
445476
}
446-
if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
447-
return (-1);
477+
if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)
478+
goto fail;
448479
}
449-
strcpy(line, "\n");
480+
strlcpy(newline, "\n", sizeof(newline));
450481
}
451482
if (!nodot && linelen == 2 && line[0] == '.')
452483
break;
453484
if (!nocopy) {
454-
if (fwrite(line, strlen(line), 1, queue->mailf) != 1)
455-
return (-1);
485+
if (newline[0] != '\0') {
486+
if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)
487+
goto fail;
488+
} else {
489+
if (writeline(queue, line, linelen) != 0)
490+
goto fail;
491+
}
456492
}
457493
}
458494

459495
return (0);
496+
fail:
497+
free(line);
498+
return (-1);
460499
}

0 commit comments

Comments
 (0)