(demoting to serious, tagging upstream, retitling) Additional info:
fetchmail 6.3.4 and older do NOT log out of the upstream server after SIGPIPE (I don't know the rationale behind this - it's not in the comments), which prevents the deletions from happening properly. Retitling the bug accordingly. Workarounds: - have your upstream reject spam with improperly formatted envelopes, these should be rejected in the first SMTP dialogue - do not use multidrop with wildcard ("*"), but list allowed local accounts explicitly (since the bogus address will not match, the message will be forwarded to the postmaster address, which is under your control, and can also be empty to discard the message - this will prevent Exim from hanging up). - set expunge 10 (fetchmail will send QUIT after 10 messages and reconnect, to make deletions effective and limit the amount of refetching). Fix: block SIGPIPE; the SIGPIPE handler was wrong from the moment it was coded as it uses longjmp() which isn't safe in signal handlers. Functions that write to broken pipes will still report errors, but fetchmail won't corrupt internal state or defeat the logout. Patch attached. BEWARE: it is NOT run-time tested, I'm not fetching from multidrop accounts. Nico/Héctor, can we provide an inofficial package to Helge with the patch below to ask feedback if the fix is complete? It shouldn't matter if it's i386 rather than x86_64. Rationale for severity demotion: Since the breakage is partially induced by configuration and for instance works properly for singledrop, I don't think "grave" is justified. Perhaps further demotion to "important" is in order, but I'm not the Debian maintainer to remove the "unsuitable for release" tag that is attached to critical/grave/serious severities. -- Matthias Andree
--- ./fetchmail.c.orig 2006-08-21 01:39:54.000000000 +0200 +++ ./fetchmail.c 2006-08-21 01:37:47.000000000 +0200 @@ -577,7 +577,7 @@ set_signal_handler(SIGINT, terminate_run); set_signal_handler(SIGTERM, terminate_run); set_signal_handler(SIGALRM, terminate_run); - set_signal_handler(SIGPIPE, terminate_run); + set_signal_handler(SIGPIPE, SIG_IGN); set_signal_handler(SIGQUIT, terminate_run); /* here's the exclusion lock */ --- ./driver.c.orig 2006-08-21 01:37:09.000000000 +0200 +++ ./driver.c 2006-08-21 01:40:41.000000000 +0200 @@ -55,7 +55,6 @@ /* throw types for runtime errors */ #define THROW_TIMEOUT 1 /* server timed out */ -#define THROW_SIGPIPE 2 /* SIGPIPE on stream socket */ /* magic values for the message length array */ #define MSGLEN_UNKNOWN 0 /* length unknown (0 is impossible) */ @@ -113,13 +112,6 @@ idletimeout = 1; } -static RETSIGTYPE sigpipe_handler (int signal) -/* handle SIGPIPE signal indicating a broken stream socket */ -{ - (void)signal; - longjmp(restart, THROW_SIGPIPE); -} - #define CLEANUP_TIMEOUT 60 /* maximum timeout during cleanup */ static int cleanupSockClose (int fd) @@ -856,9 +848,6 @@ alrmsave = set_signal_handler(SIGALRM, timeout_handler); mytimeout = ctl->server.timeout; - /* set up the broken-pipe timeout */ - pipesave = set_signal_handler(SIGPIPE, sigpipe_handler); - if ((js = setjmp(restart))) { /* exception caught */ @@ -878,14 +867,7 @@ sigprocmask(SIG_UNBLOCK, &allsigs, NULL); #endif /* HAVE_SIGPROCMASK */ - if (js == THROW_SIGPIPE) - { - set_signal_handler(SIGPIPE, SIG_IGN); - report(stdout, - GT_("SIGPIPE thrown from an MDA or a stream socket error\n")); - wait(0); - } - else if (js == THROW_TIMEOUT) + if (js == THROW_TIMEOUT) { if (phase == OPEN_WAIT) report(stdout, @@ -1581,7 +1563,6 @@ set_timeout(0); /* cancel any pending alarm */ set_signal_handler(SIGALRM, alrmsave); - set_signal_handler(SIGPIPE, pipesave); return(err); }