fetchmail-friends
[Top] [All Lists]

[fetchmail]Re: Mail System Error - Returned Mail

2001-06-18 13:38:24
Hello,

In general, it's not possible to guarantee that fetchmail will deal
gracefully with arbitrarily broken messages.  Among other things,
it's hard to 100% exclude buffer overflows in a language with
dynamic memory allocation features as weak as C's.

I agree. Dealing with data from unknown sources in C is always
somewhere between painful and almost impossible.

For this reason I have toyed with the idea of rewriting fetchmail in
Python.

Not a bad idea. Up to now I've only toyed around with Python, but I
liked it. The only real reason against your undertaking may be, that
there are still a lot more people knowing C than Python. So the list
of possible contributers might be much shorter.

You're welcome to try fixing this particular problem.  Perhaps you'll
see something obvious that I'm missing.

At the end is a patch, which fixes this particular problem for me. It
tries to detect, if SockRead could not deliver a complete line and
reads on then, resizing the line-array on each pass. I'm not sure, if
it's really the right way, but it worked for me during some small
tests. The patch is against 5.8.7.

Regards,

Stephan

*** fetchmail-5.8.7-orig/transact.c     Sun Jun 17 17:01:30 2001
--- fetchmail-5.8.7/transact.c  Mon Jun 18 22:05:50 2001
***************
*** 387,392 ****
--- 387,393 ----
      for (remaining = fetchlen; remaining > 0 || protocol->delimited; 
remaining -= linelen)
      {
        char *line;
+       int overlong = FALSE;
  
        line = xmalloc(sizeof(buf));
        linelen = 0;
***************
*** 404,409 ****
--- 405,423 ----
            linelen += n;
            msgblk.msglen += n;
  
+               /*
+                * Try to gracefully handle the case, where the length of a
+                * line exceeds MSGBUFSIZE.
+                */
+               if ( n && buf[n-1] != '\n' ) {
+                       unsigned int llen = strlen(line);
+                       overlong = TRUE;
+                       line = realloc(line, llen + n + 1);
+                       strcpy(line + llen, buf);
+                       ch = ' '; /* So the next iteration starts */
+                       continue;
+               }
+ 
            /* lines may not be properly CRLF terminated; fix this for qmail */
            if (ctl->forcecr)
            {
***************
*** 416,432 ****
                }
            }
  
!           /*
!            * Decode MIME encoded headers. We MUST do this before
!            * looking at the Content-Type / Content-Transfer-Encoding
!            * headers (RFC 2046).
!            */
!           if (ctl->mimedecode)
!               UnMimeHeader(buf);
! 
!           line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
  
!           strcat(line, buf);
  
            /* check for end of headers */
            if (EMPTYLINE(line))
--- 430,456 ----
                }
            }
  
!               /*
!                * Decode MIME encoded headers. We MUST do this before
!                * looking at the Content-Type / Content-Transfer-Encoding
!                * headers (RFC 2046).
!                */
!               if ( ctl->mimedecode && overlong ) {
!                       /*
!                        * If we received an overlong line, we have to decode 
the
!                        * whole line at once.
!                        */
!                       line = (char *) realloc(line, strlen(line) + 
strlen(buf) +1);
!                       strcat(line, buf);
!                       UnMimeHeader(line);
!               }
!               else {
!                       if ( ctl->mimedecode )
!                               UnMimeHeader(buf);
  
!                       line = (char *) realloc(line, strlen(line) + 
strlen(buf) +1);
!                       strcat(line, buf);
!               }
  
            /* check for end of headers */
            if (EMPTYLINE(line))
***************
*** 444,451 ****
             */
            if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
            {
-               free(line);
                has_nuls = (linelen != strlen(line));
                goto process_headers;
            }
  
--- 468,475 ----
             */
            if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
            {
                has_nuls = (linelen != strlen(line));
+               free(line);
                goto process_headers;
            }
  


<Prev in Thread] Current Thread [Next in Thread>