Package: fetchmail Version: 6.3.6-1 Severity: normal Tags: patch fetchmail aborts all attempts to download messages from a mailserver with a 'socket error'.
I was able to reproduce the error on two different systems (Debian Linux and Solaris) using two different mail servers (MS Exchange and Courier Imap). | $ cat config | poll localhost protocol imap user testuser password testpass folder | INBOX bsmtp /tmp/D3RvtNRoDx.bsmtp keep no rewrite | | $ fetchmail -f config | fetchmail: Server CommonName mismatch: bounty.schuettel.ch != localhost | fetchmail: Server certificate verification error: self signed | certificate | 46 messages for testuser at localhost (folder INBOX). | reading message [EMAIL PROTECTED]:1 of 46 (2397 header | octets)..fetchmail: socket error while fetching from [EMAIL PROTECTED] | fetchmail: Query status=2 (SOCKET) | $ fetchmail -v -v -v -f config | ... | fetchmail: IMAP< * 41 FETCH (RFC822.SIZE 2760) | fetchmail: IMAP< * 42 FETCH (RFC822.SIZE 1887) | fetchmail: IMAP< * 43 FETCH (RFC822.SIZE 1927) | fetchmail: IMAP< * 44 FETCH (RFC822.SIZE 3663) | fetchmail: IMAP< * 45 FETCH (RFC822.SIZE 3035) | fetchmail: IMAP< * 46 FETCH (RFC822.SIZE 2530) | fetchmail: IMAP< A0007 OK FETCH completed. | fetchmail: IMAP> A0008 FETCH 1 RFC822.HEADER | fetchmail: IMAP< * 1 FETCH (RFC822.HEADER {2397} | reading message [EMAIL PROTECTED]:1 of 46 (2397 header octets) | fetchmail: socket error while fetching from [EMAIL PROTECTED] | #fetchmail: 6.3.6 querying localhost (protocol IMAP) at Fri Mar 30 | 13:52:55 2007: poll completed | fetchmail: Query status=2 (SOCKET) | fetchmail: Deleting fetchids file. | fetchmail: normal termination, status 2 | fetchmail: Deleting fetchids file. I tried to analyse the problem using gdb and I found out that the following call to fetch_messages returns 2 (PS_SOCKET) and causes this 'socket error'. * driver.c | 1412 /* fetch in lockstep mode */ | 1413 err = fetch_messages(mailserver_socket, ctl, | 1414 count, &msgsizes, | 1415 maxfetch, | 1416 &fetches, &dispatches, &deletions); | 1417 if (err != PS_SUCCESS && err != PS_MAXFETCH) | 1418 goto cleanUp; It turns out the the following if-else statement returns the error-code 'PS_STOCKET' because n is not equal two strlen(buf). * transact.c | 1327 *cp++ = '\n'; | 1328 *cp++ = '\0'; | 1329 n = stuffline(ctl, buf); | 1330 | 1331 if (n == strlen(buf)) | 1332 return PS_SUCCESS; | 1333 else | 1334 return PS_SOCKET; | 1335 } * backtrace at 1334: | #0 readheaders (sock=7, fetchlen=1571, reallen=2716, ctl=0x8095688, num=356, suppress_readbody=0x0) at transact.c:1334 | #1 0x08055726 in fetch_messages (mailserver_socket=7, ctl=0x8095688, count=3606, msgsizes=0x80869a8, maxfetch=0, fetches=0xbfc5bcb4, dispatches=0xbfc5bcb0, | deletions=0xbfc5bcc4) at driver.c:621 | #2 0x08056f1c in do_session (ctl=0x8095688, proto=0x8081ca0, maxfetch=0) at driver.c:1413 | #3 0x0805751c in do_protocol (ctl=0x8095688, proto=0x8081ca0) at driver.c:1624 | #4 0x0806cdc5 in doIMAP (ctl=0x8095688) at imap.c:1302 | #5 0x080505e9 in query_host (ctl=0x8095688) at fetchmail.c:1480 | #6 0x0804e0ed in main (argc=3, argv=0xbfc5bf54) at fetchmail.c:739 And interestingly stuffline always returns 1, well.. after looking at the code it even made sense...: * sink.c | 687 n = 0; | 688 if (ctl->mda || ctl->bsmtp) { | 689 n = fwrite(buf, last - buf, 1, sinkfp); | 690 if (ferror(sinkfp)) n = -1; | 691 } else if (ctl->smtp_socket != -1) | 692 n = SockWrite(ctl->smtp_socket, buf, last - buf); | 693 | 694 phase = oldphase; | 695 | 696 return(n); * man fwrite | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); | The function fwrite() writes nmemb elements of data, each size bytes long, to | the stream pointed to by stream, obtaining them from the location given by ptr. ... I'm not sure, but it seems like author swaped the two args size and nmemb by accident, so instead of writing N elements with the size 1 he writes ONE elment with size N :). Of course that works as well, but then you can't compare the returned value (which is always 1) against the strlen of the buf... and therefore it always aborts. transact.c::1331 was the only place I've seen where the return value is actually checked against another value, usually it is only checked if it is -1 or not, so I'm not sure what the intented handling was. Anyway, it turns out that swaping the two parameters in the call to fwrite() fixes my problem pretty well (because then strlen(buf) == fwrite(buf)), but I don't know if this fix causes problems anywhere else. I've attached a small patch which does that. Regards, Reto Schuettel -- System Information: Debian Release: 4.0 APT prefers testing APT policy: (500, 'testing') Architecture: i386 (i686) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.18-4-k7 Locale: LANG=C, LC_CTYPE=de_CH (charmap=ISO-8859-1) Versions of packages fetchmail depends on: ii adduser 3.102 Add and remove users and groups ii debianutils 2.17 Miscellaneous utilities specific t ii libc6 2.3.6.ds1-13 GNU C Library: Shared libraries ii libssl0.9.8 0.9.8c-4 SSL shared libraries ii lsb-base 3.1-23.1 Linux Standard Base 3.1 init scrip Versions of packages fetchmail recommends: ii ca-certificates 20070303 Common CA Certificates PEM files -- no debconf information
--- fetchmail-6.3.6.orig/sink.c +++ fetchmail-6.3.6/sink.c @@ -686,7 +686,7 @@ n = 0; if (ctl->mda || ctl->bsmtp) { - n = fwrite(buf, last - buf, 1, sinkfp); + n = fwrite(buf, 1, last - buf, sinkfp); if (ferror(sinkfp)) n = -1; } else if (ctl->smtp_socket != -1) n = SockWrite(ctl->smtp_socket, buf, last - buf);