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+
344375int
345376readmail (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