38
38
#include <signal.h>
39
39
#include <syslog.h>
40
40
#include <unistd.h>
41
+ #include <ctype.h>
41
42
42
43
#include "dma.h"
43
44
@@ -341,18 +342,49 @@ parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
341
342
goto again ;
342
343
}
343
344
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
+
344
375
int
345
376
readmail (struct queue * queue , int nodot , int recp_from_header )
346
377
{
347
378
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 ];
350
383
size_t error ;
351
384
int had_headers = 0 ;
352
385
int had_from = 0 ;
353
386
int had_messagid = 0 ;
354
387
int had_date = 0 ;
355
- int had_last_line = 0 ;
356
388
int nocopy = 0 ;
357
389
358
390
parse_state .state = NONE ;
@@ -372,24 +404,15 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
372
404
return (-1 );
373
405
374
406
while (!feof (stdin )) {
375
- if (fgets (line , sizeof (line ) - 1 , stdin ) == NULL )
407
+ newline [0 ] = '\0' ;
408
+ if ((linelen = getline (& line , & linecap , stdin )) <= 0 )
376
409
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
- }
392
410
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
+
393
416
/*
394
417
* Unless this is a continuation, switch of
395
418
* the Bcc: nocopy flag.
@@ -425,36 +448,44 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
425
448
}
426
449
}
427
450
428
- if (strcmp ( line , "\n" ) == 0 && !had_headers ) {
451
+ if (line [ 0 ] == '\n' && !had_headers ) {
429
452
had_headers = 1 ;
430
453
while (!had_date || !had_messagid || !had_from ) {
431
454
if (!had_date ) {
432
455
had_date = 1 ;
433
- snprintf (line , sizeof (line ), "Date: %s\n" , rfc822date ());
456
+ snprintf (newline , sizeof (newline ), "Date: %s\n" , rfc822date ());
434
457
} else if (!had_messagid ) {
435
458
/* XXX msgid, assign earlier and log? */
436
459
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" ,
438
461
(uintmax_t )time (NULL ),
439
462
queue -> id ,
440
463
(uintmax_t )random (),
441
464
hostname ());
442
465
} else if (!had_from ) {
443
466
had_from = 1 ;
444
- snprintf (line , sizeof (line ), "From: <%s>\n" , queue -> sender );
467
+ snprintf (newline , sizeof (newline ), "From: <%s>\n" , queue -> sender );
445
468
}
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 ;
448
471
}
449
- strcpy ( line , "\n" );
472
+ strlcpy ( newline , "\n" , sizeof ( newline ) );
450
473
}
451
474
if (!nodot && linelen == 2 && line [0 ] == '.' )
452
475
break ;
453
476
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
+ }
456
484
}
457
485
}
458
486
459
487
return (0 );
488
+ fail :
489
+ free (line );
490
+ return (-1 );
460
491
}
0 commit comments