Index: mail.c =================================================================== --- mail.c (revision 307623) +++ mail.c (working copy) @@ -38,6 +38,7 @@ #include #include #include +#include #include "dma.h" @@ -341,18 +342,49 @@ goto again; } +static int +writeline(struct queue *queue, const char *line, ssize_t linelen) +{ + const char *walk; + + while (linelen > 0) { + if (linelen > 1000) { + walk = line + 1000; + while (!isspace(*walk)) { + if (walk == line) + errlogx(EX_DATAERR, "bad mail input format:" + " from %s (uid %d) (envelope-from %s)", + username, useruid, queue->sender); + walk--; + } + } else { + walk = line + linelen; + } + if (fwrite(line, walk - line, 1, queue->mailf) != 1) + return (-1); + if (linelen <= 1000) + break; + if (fwrite("\n", 1, 1, queue->mailf) != 1) + return (-1); + line = walk + 1; + linelen = strlen(line); + } + return (0); +} + int readmail(struct queue *queue, int nodot, int recp_from_header) { struct parse_state parse_state; - char line[1000]; /* by RFC2822 */ - size_t linelen; + char *line = NULL; + ssize_t linelen; + size_t linecap = 0; + char newline[1000]; size_t error; int had_headers = 0; int had_from = 0; int had_messagid = 0; int had_date = 0; - int had_last_line = 0; int nocopy = 0; parse_state.state = NONE; @@ -372,24 +404,15 @@ return (-1); while (!feof(stdin)) { - if (fgets(line, sizeof(line) - 1, stdin) == NULL) + newline[0] = '\0'; + if ((linelen = getline(&line, &linecap, stdin)) <= 0) break; - if (had_last_line) - errlogx(EX_DATAERR, "bad mail input format:" - " from %s (uid %d) (envelope-from %s)", - username, useruid, queue->sender); - linelen = strlen(line); - if (linelen == 0 || line[linelen - 1] != '\n') { - /* - * This line did not end with a newline character. - * If we fix it, it better be the last line of - * the file. - */ - line[linelen] = '\n'; - line[linelen + 1] = 0; - had_last_line = 1; - } if (!had_headers) { + if (linelen > 1000) + errlogx(EX_DATAERR, "bad mail input format:" + " from %s (uid %d) (envelope-from %s)", + username, useruid, queue->sender); + /* * Unless this is a continuation, switch of * the Bcc: nocopy flag. @@ -425,16 +448,16 @@ } } - if (strcmp(line, "\n") == 0 && !had_headers) { + if (line[0] == '\n' && !had_headers) { had_headers = 1; while (!had_date || !had_messagid || !had_from) { if (!had_date) { had_date = 1; - snprintf(line, sizeof(line), "Date: %s\n", rfc822date()); + snprintf(newline, sizeof(newline), "Date: %s\n", rfc822date()); } else if (!had_messagid) { /* XXX msgid, assign earlier and log? */ had_messagid = 1; - snprintf(line, sizeof(line), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n", + snprintf(newline, sizeof(newline), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n", (uintmax_t)time(NULL), queue->id, (uintmax_t)random(), @@ -441,20 +464,28 @@ hostname()); } else if (!had_from) { had_from = 1; - snprintf(line, sizeof(line), "From: <%s>\n", queue->sender); + snprintf(newline, sizeof(newline), "From: <%s>\n", queue->sender); } - if (fwrite(line, strlen(line), 1, queue->mailf) != 1) - return (-1); + if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1) + goto fail; } - strcpy(line, "\n"); + strlcpy(newline, "\n", sizeof(newline)); } if (!nodot && linelen == 2 && line[0] == '.') break; if (!nocopy) { - if (fwrite(line, strlen(line), 1, queue->mailf) != 1) - return (-1); + if (newline[0] != '\0') { + if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1) + goto fail; + } else { + if (writeline(queue, line, linelen) != 0) + goto fail; + } } } return (0); +fail: + free(line); + return (-1); }