]> Pileus Git - ~andy/fetchmail/blobdiff - smtp.c
Merge Fabrice Bellet's patch to fix recentcount/count after IMAP
[~andy/fetchmail] / smtp.c
diff --git a/smtp.c b/smtp.c
index ee99bcf7c0e55c2b41e63b54be9fff1bc0ffc64c..2595a57ef139cf084ae86d3fd5acebc25e958871 100644 (file)
--- a/smtp.c
+++ b/smtp.c
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
+#include <signal.h>
 #include "fetchmail.h"
 #include "socket.h"
 #include "smtp.h"
 #include "config.h"
-
-static void SMTP_auth(int, char *);
+#include "i18n.h"
 
 struct opt
 {
@@ -37,8 +37,6 @@ static struct opt extensions[] =
 };
 
 char smtp_response[MSGBUFSIZE];
-char esmtp_auth_username[65];
-char esmtp_auth_password[256];
 
 static char smtp_mode = 'S';
 
@@ -60,11 +58,136 @@ int SMTP_helo(int sock,const char *host)
   return ok;
 }
 
-int SMTP_ehlo(int sock, const char *host, int *opt)
+static void SMTP_auth_error(int sock, char *msg)
+{
+    SockPrintf(sock, "*\r\n");
+    SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
+    if (outlevel >= O_MONITOR) report(stdout, msg);
+}
+
+static void SMTP_auth(int sock, char *username, char *password, char *buf)
+/* ESMTP Authentication support for fetchmail by Wojciech Polak */
+{      
+       int c;
+       char *p = 0;
+       char b64buf[512];
+       char tmp[512];
+
+       if (!username || !password) return;
+
+       memset(b64buf, 0, sizeof(b64buf));
+       memset(tmp, 0, sizeof(tmp));
+
+       if (strstr(buf, "CRAM-MD5")) {
+               unsigned char digest[16];
+               memset(digest, 0, sizeof(digest));
+
+               if (outlevel >= O_MONITOR)
+                       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';
+
+               if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
+                       SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n"));
+                       return;
+               }
+
+               p = strchr(tmp, ' ');
+               p++;
+               /* (hmh) from64tobits will not NULL-terminate strings! */
+               if (from64tobits(b64buf, p, sizeof(b64buf) - 1) <= 0) {
+                       SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
+                       return;
+               }
+               if (outlevel >= O_DEBUG)
+                       report(stdout, GT_("Challenge decoded: %s\n"), b64buf);
+               hmac_md5(password, strlen(password),
+                        b64buf, strlen(b64buf), digest, sizeof(digest));
+#ifdef HAVE_SNPRINTF
+               snprintf(tmp, sizeof(tmp),
+#else
+               sprintf(tmp,
+#endif /* HAVE_SNPRINTF */
+               "%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],
+               digest[4], digest[5], digest[6], digest[7], digest[8],
+               digest[9], digest[10], digest[11], digest[12], digest[13],
+               digest[14], digest[15]);
+
+               to64frombits(b64buf, tmp, strlen(tmp));
+               SockPrintf(sock, "%s\r\n", b64buf);
+               SMTP_ok(sock);
+       }
+       else if (strstr(buf, "PLAIN")) {
+               int len;
+               if (outlevel >= O_MONITOR)
+                       report(stdout, GT_("ESMTP PLAIN Authentication...\n"));
+#ifdef HAVE_SNPRINTF
+               snprintf(tmp, sizeof(tmp),
+#else
+               sprintf(tmp,
+#endif /* HAVE_SNPRINTF */
+               "^%s^%s", username, password);
+
+               len = strlen(tmp);
+               for (c = len - 1; c >= 0; c--)
+               {
+                       if (tmp[c] == '^')
+                               tmp[c] = '\0';
+               }
+               to64frombits(b64buf, tmp, len);
+               SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf);
+               SMTP_ok(sock);
+       }
+       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';
+
+               if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
+                       SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n"));
+                       return;
+               }
+
+               p = strchr(tmp, ' ');
+               p++;
+               if (from64tobits(b64buf, p, sizeof(b64buf) - 1) <= 0) {
+                       SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
+                       return;
+               }
+               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';
+               p = strchr(tmp, ' ');
+               if (!p) {
+                       SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
+                       return;
+               }
+               p++;
+               memset(b64buf, 0, sizeof(b64buf));
+               if (from64tobits(b64buf, p, sizeof(b64buf) - 1) <= 0) {
+                       SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
+                       return;
+               }
+               to64frombits(b64buf, password, strlen(password));
+               SockPrintf(sock, "%s\r\n", b64buf);
+               SMTP_ok(sock);
+       }
+       return;
+}
+
+int SMTP_ehlo(int sock, const char *host, char *name, char *password, int *opt)
 /* send a "EHLO" message to the SMTP listener, return extension status bits */
 {
   struct opt *hp;
-  char auth_response[256];
+  char auth_response[511];
 
   SockPrintf(sock,"%cHLO %s\r\n", (smtp_mode == 'S') ? 'E' : smtp_mode, host);
   if (outlevel >= O_MONITOR)
@@ -90,10 +213,11 @@ int SMTP_ehlo(int sock, const char *host, int *opt)
              *opt |= hp->value;
              if (strncmp(hp->name, "AUTH ", 5) == 0)
                strncpy(auth_response, smtp_response, sizeof(auth_response));
+               auth_response[sizeof(auth_response)-1] = '\0';
          }
       if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') {
          if (*opt & ESMTP_AUTH)
-               SMTP_auth(sock, auth_response);
+               SMTP_auth(sock, name, password, auth_response);
          return SM_OK;
       }
       else if (smtp_response[3] != '-')
@@ -108,13 +232,13 @@ int SMTP_from(int sock, const char *from, const char *opts)
     int ok;
     char buf[MSGBUFSIZE];
 
-    if (strchr(from, '<'))
+    if (from[0]=='<')
 #ifdef HAVE_SNPRINTF
        snprintf(buf, sizeof(buf),
 #else
        sprintf(buf,
 #endif /* HAVE_SNPRINTF */
-               "MAIL FROM: %s", from);
+               "MAIL FROM:%s", from);
     else
 #ifdef HAVE_SNPRINTF
     snprintf(buf, sizeof(buf),
@@ -203,131 +327,62 @@ int SMTP_eom(int sock)
   return ok;
 }
 
+time_t last_smtp_ok = 0;
+
 int SMTP_ok(int sock)
 /* returns status of SMTP connection */
 {
+    SIGHANDLERTYPE alrmsave;
+
+    /* set an alarm for smtp ok */
+    alrmsave = set_signal_handler(SIGALRM, null_signal_handler);
+    set_timeout(mytimeout);
+
     while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1)
     {
-       int  n = strlen(smtp_response);
+       int n;
 
-       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';
-       if (n < 4)
-           return SM_ERROR;
+       /* 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';
        if (outlevel >= O_MONITOR)
            report(stdout, "%cMTP< %s\n", smtp_mode, smtp_response);
-       if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ')
+       if (n < 4 ||
+           (smtp_response[3] != ' ' && smtp_response[3] != '-'))
+       {
+           if (outlevel >= O_MONITOR)
+               report(stderr, GT_("smtp listener protocol error\n"));
+           return SM_UNRECOVERABLE;
+       }
+
+       last_smtp_ok = time((time_t *) NULL);
+
+       if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') &&
+           smtp_response[3] == ' ')
            return SM_OK;
        else if (smtp_response[3] != '-')
            return SM_ERROR;
-    }
-    return SM_UNRECOVERABLE;
-}
 
-static void SMTP_auth(int sock, char *buf)
-/* ESMTP Authentication support for Fetchmail by Wojciech Polak */
-{
-       int c;
-       char *p = 0;
-       char b64buf[512];
-       char tmp[512];
-
-       memset(b64buf, 0, sizeof(b64buf));
-       memset(tmp, 0, sizeof(tmp));
-
-       if (strstr(buf, "CRAM-MD5")) {
-               unsigned char digest[16];
-               static char ascii_digest[33];
-               memset(digest, 0, 16);
-
-               if (outlevel >= O_MONITOR)
-                       report(stdout, "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));
-
-               if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
-                       SockPrintf(sock, "*\r\n");
-                       SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
-                       if (outlevel >= O_MONITOR)
-                               report(stdout, "Server rejected the AUTH command.\n");
-                       return;
-               }
-
-               p = strchr(tmp, ' ');
-               p++;
-               from64tobits(b64buf, p, sizeof(b64buf));
-               if (outlevel >= O_DEBUG)
-                       report(stdout, "Challenge decoded: %s\n", b64buf);
-               hmac_md5(esmtp_auth_password, strlen(esmtp_auth_password),
-                                b64buf, strlen(b64buf), digest, sizeof(digest));
-               for (c = 0; c < 16; c++)
-                       sprintf(ascii_digest + 2 * c, "%02x", digest[c]);
-#ifdef HAVE_SNPRINTF
-               snprintf(tmp, sizeof(tmp),
-#else
-               sprintf(tmp,
-#endif /* HAVE_SNPRINTF */
-               "%s %s", esmtp_auth_username, ascii_digest);
-
-               to64frombits(b64buf, tmp, strlen(tmp));
-               SockPrintf(sock, "%s\r\n", b64buf);
-               SMTP_ok(sock);
-       }
-       else if (strstr(buf, "PLAIN")) {
-               int len;
-               if (outlevel >= O_MONITOR)
-                       report(stdout, "ESMTP PLAIN Authentication...\n");
-#ifdef HAVE_SNPRINTF
-               snprintf(tmp, sizeof(tmp),
-#else
-               sprintf(tmp,
-#endif /* HAVE_SNPRINTF */
-               "^%s^%s", esmtp_auth_username, esmtp_auth_password);
+       /* set an alarm for smtp ok */
+       set_signal_handler(SIGALRM, null_signal_handler);
+       set_timeout(mytimeout);
 
-               len = strlen(tmp);
-               for (c = len - 1; c >= 0; c--)
-               {
-                       if (tmp[c] == '^')
-                               tmp[c] = '\0';
-               }
-               to64frombits(b64buf, tmp, len);
-               SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf);
-               SMTP_ok(sock);
-       }
-       else if (strstr(buf, "LOGIN")) {
-               if (outlevel >= O_MONITOR)
-                       report(stdout, "ESMTP LOGIN Authentication...\n");
-               SockPrintf(sock, "AUTH LOGIN\r\n");
-               SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
-               strncpy(tmp, smtp_response, sizeof(tmp));
+    }
 
-               if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
-                       SockPrintf(sock, "*\r\n");
-                       SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
-                       if (outlevel >= O_MONITOR)
-                               report(stdout, "Server rejected the AUTH command.\n");
-                       return;
-               }
+    /* restore alarm */
+    set_timeout(0);
+    set_signal_handler(SIGALRM, alrmsave);
 
-               p = strchr(tmp, ' ');
-               p++;
-               from64tobits(b64buf, p, sizeof(b64buf));
-               to64frombits(b64buf, esmtp_auth_username, strlen(esmtp_auth_username));
-               SockPrintf(sock, "%s\r\n", b64buf);
-               SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
-               strncpy(tmp, smtp_response, sizeof(tmp));
-               p = strchr(tmp, ' ');
-               p++;
-               from64tobits(b64buf, p, sizeof(b64buf));
-               to64frombits(b64buf, esmtp_auth_password, strlen(esmtp_auth_password));
-               SockPrintf(sock, "%s\r\n", b64buf);
-               SMTP_ok(sock);
-       }
-       return;
+    if (outlevel >= O_MONITOR)
+       report(stderr, GT_("smtp listener protocol error\n"));
+    return SM_UNRECOVERABLE;
 }
 
 /* smtp.c ends here */