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+
344383int
345384readmail (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