From 5fe46d67a2dbb4c36a8d0180e5623c7e09c9ca09 Mon Sep 17 00:00:00 2001 From: Matthias Andree Date: Tue, 20 Dec 2005 00:53:35 +0000 Subject: * SMTP/LMTP cleanup to fix these two bugs: - switch back to SMTP after having tried LMTP hosts (multiple smtphost hosts) - switch back to LMTP after sending a bounce. The patch removes the global state variable that was the root of this problem. Patch by Sunil Shetye. svn path=/branches/BRANCH_6-3/; revision=4581 --- NEWS | 8 ++++++ etrn.c | 4 +-- fetchmail.h | 1 + odmr.c | 4 +-- sink.c | 81 +++++++++++++++++++++++++++++++------------------------------ smtp.c | 52 +++++++++++++++++---------------------- smtp.h | 19 +++++++-------- 7 files changed, 85 insertions(+), 84 deletions(-) diff --git a/NEWS b/NEWS index 77e32675..51d516b3 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,14 @@ change. MA = Matthias Andree, ESR = Eric S. Raymond, RF = Rob Funk.) -------------------------------------------------------------------------------- +fetchmail 6.3.2 (to be released): + +* SMTP/LMTP cleanup to fix these two bugs: + - switch back to SMTP after having tried LMTP hosts (multiple smtphost hosts) + - switch back to LMTP after sending a bounce. + The patch removes the global state variable that was the root of this problem. + Patch by Sunil Shetye. (MA) + fetchmail 6.3.1 (released 2005-12-19): # SECURITY FIX IN THIS RELEASE diff --git a/etrn.c b/etrn.c index de97fea9..98f2f7b4 100644 --- a/etrn.c +++ b/etrn.c @@ -25,7 +25,7 @@ static int etrn_ok (int sock, char *argbuf) { int ok; - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, SMTP_MODE); if (ok == SM_UNRECOVERABLE) return(PS_PROTOCOL); else @@ -40,7 +40,7 @@ static int etrn_getrange(int sock, struct query *ctl, const char *id, char buf [MSGBUFSIZE+1]; struct idlist *qnp; /* pointer to Q names */ - if ((ok = SMTP_ehlo(sock, fetchmailhost, + if ((ok = SMTP_ehlo(sock, SMTP_MODE, fetchmailhost, ctl->server.esmtp_name, ctl->server.esmtp_password, &opts))) { diff --git a/fetchmail.h b/fetchmail.h index 3b673865..a638df9e 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -344,6 +344,7 @@ struct query int wehavesentauthnote; /* We've sent an authorization failure note */ int wedged; /* wedged by auth failures or timeouts? */ char *smtphost; /* actual SMTP host we connected to */ + char smtphostmode; /* what's the actual SMTP host's wire protocol? */ int smtp_socket; /* socket descriptor for SMTP connection */ unsigned int uid; /* UID of user to deliver to */ struct idlist *skipped; /* messages skipped on the mail server */ diff --git a/odmr.c b/odmr.c index 7d4d4dca..18ef2e63 100644 --- a/odmr.c +++ b/odmr.c @@ -35,7 +35,7 @@ static int odmr_ok (int sock, char *argbuf) { int ok; - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, SMTP_MODE); if (ok == SM_UNRECOVERABLE) return(PS_PROTOCOL); else @@ -51,7 +51,7 @@ static int odmr_getrange(int sock, struct query *ctl, const char *id, char buf [MSGBUFSIZE+1]; struct idlist *qnp; /* pointer to Q names */ - if ((ok = SMTP_ehlo(sock, fetchmailhost, + if ((ok = SMTP_ehlo(sock, SMTP_MODE, fetchmailhost, ctl->server.esmtp_name, ctl->server.esmtp_password, &opts))) { diff --git a/sink.c b/sink.c index 859aa834..532de189 100644 --- a/sink.c +++ b/sink.c @@ -58,7 +58,7 @@ void smtp_close(struct query *ctl, int sayquit) if (ctl->smtp_socket != -1) { if (sayquit) - SMTP_quit(ctl->smtp_socket); + SMTP_quit(ctl->smtp_socket, ctl->smtphostmode); SockClose(ctl->smtp_socket); ctl->smtp_socket = -1; } @@ -68,8 +68,6 @@ void smtp_close(struct query *ctl, int sayquit) int smtp_open(struct query *ctl) /* try to open a socket to the appropriate SMTP server for this query */ { - char *parsed_host = NULL; - /* maybe it's time to close the socket in order to force delivery */ if (last_smtp_ok > 0 && time((time_t *)NULL) - last_smtp_ok > mytimeout) { @@ -106,6 +104,7 @@ int smtp_open(struct query *ctl) struct idlist *idp; const char *id_me = run.invisible ? ctl->server.truename : fetchmailhost; int oldphase = phase; + char *parsed_host = NULL; errno = 0; @@ -126,13 +125,14 @@ int smtp_open(struct query *ctl) ctl->smtphost = idp->id; /* remember last host tried. */ if (ctl->smtphost[0]=='/') { - ctl->listener = LMTP_MODE; + ctl->smtphostmode = LMTP_MODE; xfree(parsed_host); if ((ctl->smtp_socket = UnixOpen(ctl->smtphost))==-1) continue; } else { + ctl->smtphostmode = ctl->listener; parsed_host = xstrdup(idp->id); if ((cp = strrchr(parsed_host, '/'))) { @@ -157,12 +157,9 @@ int smtp_open(struct query *ctl) return(ctl->smtp_socket); /* success */ } - /* are we doing SMTP or LMTP? */ - SMTP_setmode(ctl->listener); - /* first, probe for ESMTP */ - if (SMTP_ok(ctl->smtp_socket) == SM_OK && - SMTP_ehlo(ctl->smtp_socket, id_me, + if (SMTP_ok(ctl->smtp_socket, ctl->smtphostmode) == SM_OK && + SMTP_ehlo(ctl->smtp_socket, ctl->smtphostmode, id_me, ctl->server.esmtp_name, ctl->server.esmtp_password, &ctl->server.esmtp_options) == SM_OK) break; /* success */ @@ -189,8 +186,8 @@ int smtp_open(struct query *ctl) } } - if (SMTP_ok(ctl->smtp_socket) == SM_OK && - SMTP_helo(ctl->smtp_socket, id_me) == SM_OK) + if (SMTP_ok(ctl->smtp_socket, ctl->smtphostmode) == SM_OK && + SMTP_helo(ctl->smtp_socket, ctl->smtphostmode, id_me) == SM_OK) break; /* success */ smtp_close(ctl, 0); @@ -273,8 +270,6 @@ static int send_bouncemail(struct query *ctl, struct msgblk *msg, bounce_to = (run.bouncemail ? msg->return_path : run.postmaster); - SMTP_setmode(SMTP_MODE); - /* can't just use fetchmailhost here, it might be localhost */ if (fqdn_of_host == NULL) fqdn_of_host = host_fqdn(0); /* can't afford to bail out and @@ -287,18 +282,18 @@ static int send_bouncemail(struct query *ctl, struct msgblk *msg, if ((sock = SockOpen("localhost", SMTP_PORT, NULL)) == -1) return(FALSE); - if (SMTP_ok(sock) != SM_OK) + if (SMTP_ok(sock, SMTP_MODE) != SM_OK) { SockClose(sock); return FALSE; } - if (SMTP_helo(sock, fetchmailhost) != SM_OK - || SMTP_from(sock, "<>", (char *)NULL) != SM_OK - || SMTP_rcpt(sock, bounce_to) != SM_OK - || SMTP_data(sock) != SM_OK) + if (SMTP_helo(sock, SMTP_MODE, fetchmailhost) != SM_OK + || SMTP_from(sock, SMTP_MODE, "<>", (char *)NULL) != SM_OK + || SMTP_rcpt(sock, SMTP_MODE, bounce_to) != SM_OK + || SMTP_data(sock, SMTP_MODE) != SM_OK) { - SMTP_quit(sock); + SMTP_quit(sock, SMTP_MODE); SockClose(sock); return(FALSE); } @@ -411,7 +406,8 @@ static int send_bouncemail(struct query *ctl, struct msgblk *msg, } SockPrintf(sock, "--%s--\r\n", boundary); - if (SMTP_eom(sock) != SM_OK || SMTP_quit(sock)) + if (SMTP_eom(sock, SMTP_MODE) != SM_OK + || SMTP_quit(sock, SMTP_MODE) != SM_OK) { SockClose(sock); return(FALSE); @@ -504,7 +500,7 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg) */ if (smtperr >= 400) report(stderr, GT_("%cMTP error: %s\n"), - ctl->listener, + ctl->smtphostmode, responses[0]); switch (smtperr) @@ -588,7 +584,7 @@ static int handle_smtp_report_without_bounce(struct query *ctl, struct msgblk *m if (smtperr >= 400) report(stderr, GT_("%cMTP error: %s\n"), - ctl->listener, + ctl->smtphostmode, smtp_response); switch (smtperr) @@ -903,7 +899,8 @@ static int open_smtp_sink(struct query *ctl, struct msgblk *msg, ap = addr; } - if ((smtp_err = SMTP_from(ctl->smtp_socket, ap, options)) == SM_UNRECOVERABLE) + if ((smtp_err = SMTP_from(ctl->smtp_socket, ctl->smtphostmode, + ap, options)) == SM_UNRECOVERABLE) { smtp_close(ctl, 0); return(PS_TRANSIENT); @@ -912,7 +909,7 @@ static int open_smtp_sink(struct query *ctl, struct msgblk *msg, { int err = handle_smtp_report(ctl, msg); /* map to PS_TRANSIENT or PS_REFUSED */ - SMTP_rset(ctl->smtp_socket); /* stay on the safe side */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* stay on the safe side */ return(err); } @@ -930,7 +927,8 @@ static int open_smtp_sink(struct query *ctl, struct msgblk *msg, { const char *address; address = rcpt_address (ctl, idp->id, 1); - if ((smtp_err = SMTP_rcpt(ctl->smtp_socket, address)) == SM_UNRECOVERABLE) + if ((smtp_err = SMTP_rcpt(ctl->smtp_socket, ctl->smtphostmode, + address)) == SM_UNRECOVERABLE) { smtp_close(ctl, 0); transient: @@ -962,14 +960,14 @@ transient: if (outlevel >= O_VERBOSE) report(stderr, GT_("%cMTP listener doesn't like recipient address `%s'\n"), - ctl->listener, address); + ctl->smtphostmode, address); break; case PS_REFUSED: if (outlevel >= O_VERBOSE) report(stderr, GT_("%cMTP listener doesn't really like recipient address `%s'\n"), - ctl->listener, address); + ctl->smtphostmode, address); break; } } @@ -980,7 +978,7 @@ transient: * crap. If one of the recipients returned PS_TRANSIENT, * we return exactly that. */ - SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* required by RFC1870 */ goto transient; } #ifdef EXPLICIT_BOUNCE_ON_BAD_ADDRESS @@ -1010,10 +1008,10 @@ transient: { if (outlevel >= O_VERBOSE) report(stderr, GT_("no address matches; no postmaster set.\n")); - SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* required by RFC1870 */ return(PS_REFUSED); } - if ((smtp_err = SMTP_rcpt(ctl->smtp_socket, + if ((smtp_err = SMTP_rcpt(ctl->smtp_socket, ctl->smtphostmode, rcpt_address (ctl, run.postmaster, 0))) == SM_UNRECOVERABLE) { smtp_close(ctl, 0); @@ -1022,7 +1020,7 @@ transient: if (smtp_err != SM_OK) { report(stderr, GT_("can't even send to %s!\n"), run.postmaster); - SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* required by RFC1870 */ return(PS_REFUSED); } @@ -1034,7 +1032,8 @@ transient: * Tell the listener we're ready to send data. * Some listeners (like zmailer) may return antispam errors here. */ - if ((smtp_err = SMTP_data(ctl->smtp_socket)) == SM_UNRECOVERABLE) + if ((smtp_err = SMTP_data(ctl->smtp_socket, ctl->smtphostmode)) + == SM_UNRECOVERABLE) { smtp_close(ctl, 0); return(PS_TRANSIENT); @@ -1042,7 +1041,7 @@ transient: if (smtp_err != SM_OK) { int err = handle_smtp_report(ctl, msg); - SMTP_rset(ctl->smtp_socket); /* stay on the safe side */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* stay on the safe side */ return(err); } @@ -1243,7 +1242,7 @@ int open_sink(struct query *ctl, struct msgblk *msg, else if (!ctl->mda) { report(stderr, GT_("%cMTP connect to %s failed\n"), - ctl->listener, + ctl->smtphostmode, ctl->smtphost ? ctl->smtphost : "localhost"); #ifndef FALLBACK_MDA @@ -1356,7 +1355,8 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward) else if (forward) { /* write message terminator */ - if ((smtp_err = SMTP_eom(ctl->smtp_socket)) == SM_UNRECOVERABLE) + if ((smtp_err = SMTP_eom(ctl->smtp_socket, ctl->smtphostmode)) + == SM_UNRECOVERABLE) { smtp_close(ctl, 0); return(FALSE); @@ -1365,13 +1365,13 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward) { if (handle_smtp_report(ctl, msg) != PS_REFUSED) { - SMTP_rset(ctl->smtp_socket); /* stay on the safe side */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* stay on the safe side */ return(FALSE); } else { report(stderr, GT_("SMTP listener refused delivery\n")); - SMTP_rset(ctl->smtp_socket); /* stay on the safe side */ + SMTP_rset(ctl->smtp_socket, ctl->smtphostmode); /* stay on the safe side */ return(TRUE); } } @@ -1386,11 +1386,11 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward) * otherwise the message will get left in the queue and resent * to people who got it the first time. */ - if (ctl->listener == LMTP_MODE) + if (ctl->smtphostmode == LMTP_MODE) { if (lmtp_responses == 0) { - SMTP_ok(ctl->smtp_socket); + SMTP_ok(ctl->smtp_socket, ctl->smtphostmode); /* * According to RFC2033, 503 is the only legal response @@ -1423,7 +1423,8 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward) responses = xmalloc(sizeof(char *) * lmtp_responses); for (errors = i = 0; i < lmtp_responses; i++) { - if ((smtp_err = SMTP_ok(ctl->smtp_socket)) == SM_UNRECOVERABLE) + if ((smtp_err = SMTP_ok(ctl->smtp_socket, ctl->smtphostmode)) + == SM_UNRECOVERABLE) { smtp_close(ctl, 0); goto unrecov; diff --git a/smtp.c b/smtp.c index 083410be..2517d15a 100644 --- a/smtp.c +++ b/smtp.c @@ -39,23 +39,15 @@ static struct opt extensions[] = char smtp_response[MSGBUFSIZE]; -static char smtp_mode = 'S'; - -void SMTP_setmode(char sl) -/* set whether we are speaking SMTP or LMTP */ -{ - smtp_mode = sl; -} - -int SMTP_helo(int sock,const char *host) +int SMTP_helo(int sock, char smtp_mode, const char *host) /* send a "HELO" message to the SMTP listener */ { int ok; SockPrintf(sock,"HELO %s\r\n", host); if (outlevel >= O_MONITOR) - report(stdout, "SMTP> HELO %s\n", host); - ok = SMTP_ok(sock); + report(stdout, "%cMTP> HELO %s\n", smtp_mode, host); + ok = SMTP_ok(sock, smtp_mode); return ok; } @@ -66,7 +58,7 @@ static void SMTP_auth_error(int sock, const char *msg) if (outlevel >= O_MONITOR) report(stdout, msg); } -static void SMTP_auth(int sock, char *username, char *password, char *buf) +static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, char *buf) /* ESMTP Authentication support for fetchmail by Wojciech Polak */ { int c; @@ -115,7 +107,7 @@ static void SMTP_auth(int sock, char *username, char *password, char *buf) to64frombits(b64buf, tmp, strlen(tmp)); SockPrintf(sock, "%s\r\n", b64buf); - SMTP_ok(sock); + SMTP_ok(sock, smtp_mode); } else if (strstr(buf, "PLAIN")) { int len; @@ -131,7 +123,7 @@ static void SMTP_auth(int sock, char *username, char *password, char *buf) } to64frombits(b64buf, tmp, len); SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf); - SMTP_ok(sock); + SMTP_ok(sock, smtp_mode); } else if (strstr(buf, "LOGIN")) { if (outlevel >= O_MONITOR) @@ -170,12 +162,12 @@ static void SMTP_auth(int sock, char *username, char *password, char *buf) } to64frombits(b64buf, password, strlen(password)); SockPrintf(sock, "%s\r\n", b64buf); - SMTP_ok(sock); + SMTP_ok(sock, smtp_mode); } return; } -int SMTP_ehlo(int sock, const char *host, char *name, char *password, int *opt) +int SMTP_ehlo(int sock, char smtp_mode, const char *host, char *name, char *password, int *opt) /* send a "EHLO" message to the SMTP listener, return extension status bits */ { struct opt *hp; @@ -209,7 +201,7 @@ int SMTP_ehlo(int sock, const char *host, char *name, char *password, int *opt) } if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') { if (*opt & ESMTP_AUTH) - SMTP_auth(sock, name, password, auth_response); + SMTP_auth(sock, smtp_mode, name, password, auth_response); return SM_OK; } else if (smtp_response[3] != '-') @@ -218,7 +210,7 @@ int SMTP_ehlo(int sock, const char *host, char *name, char *password, int *opt) return SM_UNRECOVERABLE; } -int SMTP_from(int sock, const char *from, const char *opts) +int SMTP_from(int sock, char smtp_mode, const char *from, const char *opts) /* send a "MAIL FROM:" message to the SMTP listener */ { int ok; @@ -233,11 +225,11 @@ int SMTP_from(int sock, const char *from, const char *opts) SockPrintf(sock,"%s\r\n", buf); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> %s\n", smtp_mode, buf); - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, smtp_mode); return ok; } -int SMTP_rcpt(int sock, const char *to) +int SMTP_rcpt(int sock, char smtp_mode, const char *to) /* send a "RCPT TO:" message to the SMTP listener */ { int ok; @@ -245,11 +237,11 @@ int SMTP_rcpt(int sock, const char *to) SockPrintf(sock,"RCPT TO:<%s>\r\n", to); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> RCPT TO:<%s>\n", smtp_mode, to); - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, smtp_mode); return ok; } -int SMTP_data(int sock) +int SMTP_data(int sock, char smtp_mode) /* send a "DATA" message to the SMTP listener */ { int ok; @@ -257,11 +249,11 @@ int SMTP_data(int sock) SockPrintf(sock,"DATA\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> DATA\n", smtp_mode); - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, smtp_mode); return ok; } -int SMTP_rset(int sock) +int SMTP_rset(int sock, char smtp_mode) /* send a "RSET" message to the SMTP listener */ { int ok; @@ -269,11 +261,11 @@ int SMTP_rset(int sock) SockPrintf(sock,"RSET\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> RSET\n", smtp_mode); - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, smtp_mode); return ok; } -int SMTP_quit(int sock) +int SMTP_quit(int sock, char smtp_mode) /* send a "QUIT" message to the SMTP listener */ { int ok; @@ -281,11 +273,11 @@ int SMTP_quit(int sock) SockPrintf(sock,"QUIT\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> QUIT\n", smtp_mode); - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, smtp_mode); return ok; } -int SMTP_eom(int sock) +int SMTP_eom(int sock, char smtp_mode) /* send a message data terminator to the SMTP listener */ { int ok; @@ -298,7 +290,7 @@ int SMTP_eom(int sock) * When doing LMTP, must process many of these at the outer level. */ if (smtp_mode == 'S') - ok = SMTP_ok(sock); + ok = SMTP_ok(sock, smtp_mode); else ok = SM_OK; @@ -307,7 +299,7 @@ int SMTP_eom(int sock) time_t last_smtp_ok = 0; -int SMTP_ok(int sock) +int SMTP_ok(int sock, char smtp_mode) /* returns status of SMTP connection */ { SIGHANDLERTYPE alrmsave; diff --git a/smtp.h b/smtp.h index 3dc874ff..b65196a7 100644 --- a/smtp.h +++ b/smtp.h @@ -25,16 +25,15 @@ extern time_t last_smtp_ok; -void SMTP_setmode(char); -int SMTP_helo(int socket,const char *host); -int SMTP_ehlo(int socket,const char *host, char *name, char *passwd, int *opt); -int SMTP_from(int socket,const char *from,const char *opts); -int SMTP_rcpt(int socket,const char *to); -int SMTP_data(int socket); -int SMTP_eom(int socket); -int SMTP_rset(int socket); -int SMTP_quit(int socket); -int SMTP_ok(int socket); +int SMTP_helo(int socket, char smtp_mode, const char *host); +int SMTP_ehlo(int socket, char smtp_mode, const char *host, char *name, char *passwd, int *opt); +int SMTP_from(int socket, char smtp_mode, const char *from,const char *opts); +int SMTP_rcpt(int socket, char smtp_mode, const char *to); +int SMTP_data(int socket, char smtp_mode); +int SMTP_eom(int socket, char smtp_mode); +int SMTP_rset(int socket, char smtp_mode); +int SMTP_quit(int socket, char smtp_mode); +int SMTP_ok(int socket, char smtp_mode); extern char smtp_response[MSGBUFSIZE]; -- cgit v1.2.3