X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=smtp.c;h=1c99c69675917cbbda7c2e1f6ebf9e91faf8946c;hb=e4dd196b137223195739b9e0f50ec2a8a02b3534;hp=2517d15ab7230033bc51248f98f048ba6f7a032c;hpb=5fe46d67a2dbb4c36a8d0180e5623c7e09c9ca09;p=~andy%2Ffetchmail diff --git a/smtp.c b/smtp.c index 2517d15a..1c99c696 100644 --- a/smtp.c +++ b/smtp.c @@ -4,13 +4,14 @@ * Concept due to Harry Hochheiser. Implementation by ESR. Cleanup and * strict RFC821 compliance by Cameron MacPherson. * - * Copyright 1997 Eric S. Raymond + * Copyright 1997 Eric S. Raymond, 2009 Matthias Andree * For license terms, see the file COPYING in this directory. */ #include "config.h" #include "fetchmail.h" +#include #include #include #include @@ -39,6 +40,7 @@ static struct opt extensions[] = char smtp_response[MSGBUFSIZE]; +/* XXX: this must not be used for LMTP! */ int SMTP_helo(int sock, char smtp_mode, const char *host) /* send a "HELO" message to the SMTP listener */ { @@ -47,7 +49,7 @@ int SMTP_helo(int sock, char smtp_mode, const char *host) SockPrintf(sock,"HELO %s\r\n", host); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> HELO %s\n", smtp_mode, host); - ok = SMTP_ok(sock, smtp_mode); + ok = SMTP_ok(sock, smtp_mode, TIMEOUT_HELO); return ok; } @@ -55,7 +57,7 @@ static void SMTP_auth_error(int sock, const char *msg) { SockPrintf(sock, "*\r\n"); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); - if (outlevel >= O_MONITOR) report(stdout, msg); + if (outlevel >= O_MONITOR) report(stdout, "%s", msg); } static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, char *buf) @@ -79,10 +81,9 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, report(stdout, GT_("ESMTP CRAM-MD5 Authentication...\n")); SockPrintf(sock, "AUTH CRAM-MD5\r\n"); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); - strncpy(tmp, smtp_response, sizeof(tmp)); - tmp[sizeof(tmp)-1] = '\0'; + strlcpy(tmp, smtp_response, sizeof(tmp)); - if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */ + if (strncmp(tmp, "334", 3)) { /* Server rejects AUTH */ SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n")); return; } @@ -96,8 +97,8 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, } if (outlevel >= O_DEBUG) report(stdout, GT_("Challenge decoded: %s\n"), b64buf); - hmac_md5(password, strlen(password), - b64buf, strlen(b64buf), digest, sizeof(digest)); + hmac_md5((unsigned char *)password, strlen(password), + (unsigned char *)b64buf, strlen(b64buf), digest, sizeof(digest)); snprintf(tmp, sizeof(tmp), "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", username, digest[0], digest[1], digest[2], digest[3], @@ -107,7 +108,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, to64frombits(b64buf, tmp, strlen(tmp)); SockPrintf(sock, "%s\r\n", b64buf); - SMTP_ok(sock, smtp_mode); + SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT); } else if (strstr(buf, "PLAIN")) { int len; @@ -123,17 +124,16 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, } to64frombits(b64buf, tmp, len); SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf); - SMTP_ok(sock, smtp_mode); + SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT); } else if (strstr(buf, "LOGIN")) { if (outlevel >= O_MONITOR) report(stdout, GT_("ESMTP LOGIN Authentication...\n")); SockPrintf(sock, "AUTH LOGIN\r\n"); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); - strncpy(tmp, smtp_response, sizeof(tmp)); - tmp[sizeof(tmp)-1] = '\0'; + strlcpy(tmp, smtp_response, sizeof(tmp)); - if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */ + if (strncmp(tmp, "334", 3)) { /* Server rejects AUTH */ SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n")); return; } @@ -147,8 +147,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, to64frombits(b64buf, username, strlen(username)); SockPrintf(sock, "%s\r\n", b64buf); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); - strncpy(tmp, smtp_response, sizeof(tmp)); - tmp[sizeof(tmp)-1] = '\0'; + strlcpy(tmp, smtp_response, sizeof(tmp)); p = strchr(tmp, ' '); if (!p) { SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n")); @@ -162,7 +161,7 @@ static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, } to64frombits(b64buf, password, strlen(password)); SockPrintf(sock, "%s\r\n", b64buf); - SMTP_ok(sock, smtp_mode); + SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT); } return; } @@ -172,21 +171,30 @@ int SMTP_ehlo(int sock, char smtp_mode, const char *host, char *name, char *pass { struct opt *hp; char auth_response[511]; + SIGHANDLERTYPE alrmsave; + const int tmout = (mytimeout >= TIMEOUT_HELO ? mytimeout : TIMEOUT_HELO); SockPrintf(sock,"%cHLO %s\r\n", (smtp_mode == 'S') ? 'E' : smtp_mode, host); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> %cHLO %s\n", smtp_mode, (smtp_mode == 'S') ? 'E' : smtp_mode, host); + alrmsave = set_signal_handler(SIGALRM, null_signal_handler); + set_timeout(tmout); + *opt = 0; while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1) { - int n = strlen(smtp_response); + size_t n; + + set_timeout(0); + (void)set_signal_handler(SIGALRM, alrmsave); - if (smtp_response[strlen(smtp_response)-1] == '\n') - smtp_response[strlen(smtp_response)-1] = '\0'; - if (smtp_response[strlen(smtp_response)-1] == '\r') - smtp_response[strlen(smtp_response)-1] = '\0'; + n = strlen(smtp_response); + if (n > 0 && smtp_response[n-1] == '\n') + smtp_response[--n] = '\0'; + if (n > 0 && smtp_response[n-1] == '\r') + smtp_response[--n] = '\0'; if (n < 4) return SM_ERROR; smtp_response[n] = '\0'; @@ -206,6 +214,9 @@ int SMTP_ehlo(int sock, char smtp_mode, const char *host, char *name, char *pass } else if (smtp_response[3] != '-') return SM_ERROR; + + alrmsave = set_signal_handler(SIGALRM, null_signal_handler); + set_timeout(tmout); } return SM_UNRECOVERABLE; } @@ -225,7 +236,7 @@ int SMTP_from(int sock, char smtp_mode, 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, smtp_mode); + ok = SMTP_ok(sock, smtp_mode, TIMEOUT_MAIL); return ok; } @@ -237,7 +248,7 @@ int SMTP_rcpt(int sock, char smtp_mode, 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, smtp_mode); + ok = SMTP_ok(sock, smtp_mode, TIMEOUT_RCPT); return ok; } @@ -249,7 +260,7 @@ int SMTP_data(int sock, char smtp_mode) SockPrintf(sock,"DATA\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> DATA\n", smtp_mode); - ok = SMTP_ok(sock, smtp_mode); + ok = SMTP_ok(sock, smtp_mode, TIMEOUT_DATA); return ok; } @@ -261,7 +272,7 @@ int SMTP_rset(int sock, char smtp_mode) SockPrintf(sock,"RSET\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> RSET\n", smtp_mode); - ok = SMTP_ok(sock, smtp_mode); + ok = SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT); return ok; } @@ -273,15 +284,13 @@ int SMTP_quit(int sock, char smtp_mode) SockPrintf(sock,"QUIT\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP> QUIT\n", smtp_mode); - ok = SMTP_ok(sock, smtp_mode); + ok = SMTP_ok(sock, smtp_mode, TIMEOUT_DEFAULT); return ok; } int SMTP_eom(int sock, char smtp_mode) /* send a message data terminator to the SMTP listener */ { - int ok; - SockPrintf(sock,".\r\n"); if (outlevel >= O_MONITOR) report(stdout, "%cMTP>. (EOM)\n", smtp_mode); @@ -290,42 +299,51 @@ int SMTP_eom(int sock, char smtp_mode) * When doing LMTP, must process many of these at the outer level. */ if (smtp_mode == 'S') - ok = SMTP_ok(sock, smtp_mode); + return SMTP_ok(sock, smtp_mode, TIMEOUT_EOM); else - ok = SM_OK; - - return ok; + return SM_OK; } time_t last_smtp_ok = 0; -int SMTP_ok(int sock, char smtp_mode) -/* returns status of SMTP connection */ +int SMTP_ok(int sock, char smtp_mode, int mintimeout) +/**< returns status of SMTP connection and saves the message in + * smtp_response, without trailing [CR]LF, but with normalized CRLF + * between multiple lines of multi-line replies */ { SIGHANDLERTYPE alrmsave; + char reply[MSGBUFSIZE], *i; /* set an alarm for smtp ok */ alrmsave = set_signal_handler(SIGALRM, null_signal_handler); - set_timeout(mytimeout); + set_timeout(mytimeout >= mintimeout ? mytimeout : mintimeout); - while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1) + smtp_response[0] = '\0'; + + while ((SockRead(sock, reply, sizeof(reply)-1)) != -1) { - int n; + size_t n; /* restore alarm */ set_timeout(0); set_signal_handler(SIGALRM, alrmsave); - n = strlen(smtp_response); - if (n > 0 && smtp_response[n-1] == '\n') - n--; - if (n > 0 && smtp_response[n-1] == '\r') - n--; - smtp_response[n] = '\0'; + n = strlen(reply); + if (n > 0 && reply[n-1] == '\n') + reply[--n] = '\0'; + if (n > 0 && reply[n-1] == '\r') + reply[--n] = '\0'; + + /* stomp over control characters */ + for (i = reply; *i; i++) + if (iscntrl((unsigned char)*i)) + *i = '?'; + if (outlevel >= O_MONITOR) - report(stdout, "%cMTP< %s\n", smtp_mode, smtp_response); - if (n < 4 || - (smtp_response[3] != ' ' && smtp_response[3] != '-')) + report(stdout, "%cMTP< %s\n", smtp_mode, reply); + /* note that \0 is part of the strchr search string and the + * blank after the reply code is optional (RFC 5321 4.2.1) */ + if (n < 3 || !strchr(" -", reply[3])) { if (outlevel >= O_MONITOR) report(stderr, GT_("smtp listener protocol error\n")); @@ -334,16 +352,21 @@ int SMTP_ok(int sock, char smtp_mode) last_smtp_ok = time((time_t *) NULL); - if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && - smtp_response[3] == ' ') + strlcat(smtp_response, reply, sizeof(smtp_response)); + + if (strchr("123", reply[0]) + && isdigit((unsigned char)reply[1]) + && isdigit((unsigned char)reply[2]) + && strchr(" ", reply[3])) /* matches space and \0 */ { return SM_OK; - else if (smtp_response[3] != '-') + } else if (reply[3] != '-') return SM_ERROR; + strlcat(smtp_response, "\r\n", sizeof(smtp_response)); + /* set an alarm for smtp ok */ set_signal_handler(SIGALRM, null_signal_handler); set_timeout(mytimeout); - } /* restore alarm */