]> Pileus Git - ~andy/fetchmail/blobdiff - pop3.c
Complain in POP3 if NTLM/MSN auth is requested but not built in.
[~andy/fetchmail] / pop3.c
diff --git a/pop3.c b/pop3.c
index 9025b314008a26b8771cb6754b23bf760cee6995..674894698f217fb3abdb96ad76774ff5709dcff3 100644 (file)
--- a/pop3.c
+++ b/pop3.c
@@ -69,12 +69,13 @@ static tSmbNtlmAuthResponse  response;
  * Much source (ntlm.h, smb*.c smb*.h) was borrowed from Samba.
  */
 
-static int do_pop3_ntlm(int sock, struct query *ctl)
+static int do_pop3_ntlm(int sock, struct query *ctl,
+       int msn_instead /** if true, send AUTH MSN, else send AUTH NTLM */)
 {
     char msgbuf[2048];
     int result,len;
   
-    gen_send(sock, "AUTH MSN");
+    gen_send(sock, msn_instead ? "AUTH MSN" : "AUTH NTLM");
 
     if ((result = gen_recv(sock, msgbuf, sizeof msgbuf)))
        return result;
@@ -318,25 +319,26 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
     if (!(ctl->server.sdps) && MULTIDROP(ctl) && strstr(greeting, "demon."))
         ctl->server.sdps = TRUE;
 #endif /* SDPS_ENABLE */
+
 #ifdef NTLM_ENABLE
-       /* MSN servers require the use of NTLM (MSN) authentication */
-       if (!strcasecmp(ctl->server.pollname, "pop3.email.msn.com") ||
-           ctl->server.authenticate == A_NTLM)
-       {
-           if (!do_pop3_ntlm(sock, ctl))
-           {
-               return(PS_SUCCESS);
-           }
-           else
-           {
-               return(PS_AUTHFAIL);
-           }
-       }
+    /* MSN servers require the use of NTLM (MSN) authentication */
+    if (!strcasecmp(ctl->server.pollname, "pop3.email.msn.com") ||
+           ctl->server.authenticate == A_MSN)
+       return (do_pop3_ntlm(sock, ctl, 1) == 0) ? PS_SUCCESS : PS_AUTHFAIL;
+    if (ctl->server.authenticate == A_NTLM)
+       return (do_pop3_ntlm(sock, ctl, 0) == 0) ? PS_SUCCESS : PS_AUTHFAIL;
+#else
+    if (ctl->server.authenticate == A_NTLM || ctl->server.authenticate == A_MSN)
+    {
+       report(stderr,
+          GT_("Required NTLM capability not compiled into fetchmail\n"));
+    }
 #endif
 
     switch (ctl->server.protocol) {
     case P_POP3:
 #ifdef RPA_ENABLE
+       /* XXX FIXME: AUTH probing (RFC1734) should become global */
        /* CompuServe POP3 Servers as of 990730 want AUTH first for RPA */
        if (strstr(ctl->remotename, "@compuserve.com"))
        {
@@ -422,7 +424,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
               }
               report(stderr,
                       GT_("SSL connection failed.\n"));
-               return(PS_AUTHFAIL);
+               return PS_SOCKET;
            }
           did_stls = TRUE;
 
@@ -449,11 +451,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
         * rather than doing SASL.
         */
        if (has_kerberos &&
-#ifdef INET6_ENABLE
            ctl->server.service && (strcmp(ctl->server.service, KPOP_PORT)!=0)
-#else /* INET6_ENABLE */
-           ctl->server.port != KPOP_PORT
-#endif /* INET6_ENABLE */
            && (ctl->server.authenticate == A_KERBEROS_V4
             || ctl->server.authenticate == A_KERBEROS_V5
             || ctl->server.authenticate == A_ANY))
@@ -523,7 +521,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
        }
 #endif /* OPIE_ENABLE */
 
-       strcpy(shroud, ctl->password);
+       strlcpy(shroud, ctl->password, sizeof(shroud));
        ok = gen_transact(sock, "PASS %s", ctl->password);
        shroud[0] = '\0';
 #ifdef SSL_ENABLE
@@ -561,11 +559,11 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
            *++end = '\0';
 
        /* copy timestamp and password into digestion buffer */
-       xalloca(msg, char *, (end-start+1) + strlen(ctl->password) + 1);
+       msg = xmalloc((end-start+1) + strlen(ctl->password) + 1);
        strcpy(msg,start);
        strcat(msg,ctl->password);
-
        strcpy(ctl->digest, MD5Digest((unsigned char *)msg));
+       free(msg);
 
        ok = gen_transact(sock, "APOP %s %s", ctl->remotename, ctl->digest);
        break;
@@ -611,6 +609,12 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
     return(PS_SUCCESS);
 }
 
+/* cut off C string at first POSIX space */
+static void trim(char *s) {
+    s += strcspn(s, POSIX_space);
+    s[0] = '\0';
+}
+
 static int pop3_gettopid(int sock, int num , char *id, size_t idsize)
 {
     int ok;
@@ -626,35 +630,42 @@ static int pop3_gettopid(int sock, int num , char *id, size_t idsize)
            break;
        if (!got_it && 0 == strncasecmp("Message-Id:", buf, 11)) {
            char *p = buf + 11;
+           got_it = 1;
            p += strspn(p, POSIX_space);
-           p = strtok(p, POSIX_space);
            strlcpy(id, p, idsize);
+           trim(id);
        }
     }
     return 0;
 }
 
-/** Parse destructively the UID response (leading +OK must have been
+/** Parse the UID response (leading +OK must have been
  * stripped off) in buf, store the number in gotnum, and store the ID
  * into the caller-provided buffer "id" of size "idsize".
  * Returns PS_SUCCESS or PS_PROTOCOL for failure. */
-static int parseuid(char *buf, unsigned long *gotnum, char *id, size_t idsize)
+static int parseuid(const char *buf, unsigned long *gotnum, char *id, size_t idsize)
 {
-    char *i, *j;
+    const char *i;
+    char *j;
 
-    i = strtok(buf, POSIX_space);
+    /* skip leading blanks ourselves */
+    i = buf;
+    i += strspn(i, POSIX_space);
     errno = 0;
     *gotnum = strtoul(i, &j, 10);
-    if (*j != '\0' || j == i || errno) {
+    if (j == i || !*j || errno || NULL == strchr(POSIX_space, *j)) {
        report(stderr, GT_("Cannot handle UIDL response from upstream server.\n"));
        return PS_PROTOCOL;
     }
-    i = strtok(NULL, POSIX_space);
-    strlcpy(id, i, idsize);
+    j += strspn(j, POSIX_space);
+    strlcpy(id, j, idsize);
+    trim(id);
     return PS_SUCCESS;
 }
 
-static int pop3_getuidl(int sock, int num , char *id, size_t idsize)
+/** request UIDL for single message \a num and stuff the result into the
+ * buffer \a id which can hold \a idsize bytes */
+static int pop3_getuidl(int sock, int num, char *id /** output */, size_t idsize)
 {
     int ok;
     char buf [POPBUFSIZE+1];
@@ -905,7 +916,7 @@ static int pop3_getrange(int sock,
                unsigned long unum;
 
                *newp = 0;
-               while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
+               while ((ok = gen_recv(sock, buf, sizeof(buf))) == PS_SUCCESS)
                {
                    if (DOTLINE(buf))
                        break;
@@ -951,7 +962,8 @@ static int pop3_getrange(int sock,
                            old = save_str(&ctl->oldsaved, id, UID_UNSEEN);
                            old->val.status.num = unum;
                        }
-                   }
+                   } else
+                       return PS_ERROR;
                }
            }
        }
@@ -1229,13 +1241,8 @@ static int pop3_logout(int sock, struct query *ctl)
 static const struct method pop3 =
 {
     "POP3",            /* Post Office Protocol v3 */
-#ifdef INET6_ENABLE
     "pop3",            /* standard POP3 port */
     "pop3s",           /* ssl POP3 port */
-#else /* INET6_ENABLE */
-    110,               /* standard POP3 port */
-    995,               /* ssl POP3 port */
-#endif /* INET6_ENABLE */
     FALSE,             /* this is not a tagged protocol */
     TRUE,              /* this uses a message delimiter */
     pop3_ok,           /* parse command response */
@@ -1249,6 +1256,7 @@ static const struct method pop3 =
     NULL,              /* no message trailer */
     pop3_delete,       /* how to delete a message */
     pop3_mark_seen,    /* how to mark a message as seen */
+    NULL,              /* no action at end of mailbox */
     pop3_logout,       /* log out, we're done */
     FALSE,             /* no, we can't re-poll */
 };