]> Pileus Git - ~andy/fetchmail/blobdiff - pop3.c
Support A_SSH authentication.
[~andy/fetchmail] / pop3.c
diff --git a/pop3.c b/pop3.c
index 7082d94f882145616ae4955ae33e63b64db461d6..02e38c3f3a8b7221406a6a4ead00a668d6bff206 100644 (file)
--- a/pop3.c
+++ b/pop3.c
@@ -39,6 +39,21 @@ char *sdps_envto;
 static char lastok[POPBUFSIZE+1];
 #endif /* OPIE_ENABLE */
 
+/* these variables are shared between the CAPA probe and the authenticator */
+#if defined(GSSAPI)
+    flag has_gssapi = FALSE;
+#endif /* defined(GSSAPI) */
+#if defined(KERBEROS_V4) || defined(KERBEROS_V5)
+    flag has_kerberos = FALSE;
+#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
+    flag has_cram = FALSE;
+#ifdef OPIE_ENABLE
+    flag has_otp = FALSE;
+#endif /* OPIE_ENABLE */
+#ifdef SSL_ENABLE
+    flag has_ssl = FALSE;
+#endif /* SSL_ENABLE */
+
 #define DOTLINE(s)     (s[0] == '.' && (s[1]=='\r'||s[1]=='\n'||s[1]=='\0'))
 
 static int pop3_ok (int sock, char *argbuf)
@@ -124,6 +139,46 @@ static int pop3_ok (int sock, char *argbuf)
     return(ok);
 }
 
+
+
+static int capa_probe(sock)
+/* probe the capabilities of the remote server */
+{
+    int        ok;
+
+    ok = gen_transact(sock, "CAPA");
+    if (ok == PS_SUCCESS)
+    {
+       char buffer[64];
+
+       /* determine what authentication methods we have available */
+       while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0)
+       {
+           if (DOTLINE(buffer))
+               break;
+#ifdef SSL_ENABLE
+           if (strstr(buffer, "STLS"))
+               has_ssl = TRUE;
+#endif /* SSL_ENABLE */
+#if defined(GSSAPI)
+           if (strstr(buffer, "GSSAPI"))
+               has_gssapi = TRUE;
+#endif /* defined(GSSAPI) */
+#if defined(KERBEROS_V4)
+           if (strstr(buffer, "KERBEROS_V4"))
+               has_kerberos = TRUE;
+#endif /* defined(KERBEROS_V4)  */
+#ifdef OPIE_ENABLE
+           if (strstr(buffer, "X-OTP"))
+               has_otp = TRUE;
+#endif /* OPIE_ENABLE */
+           if (strstr(buffer, "CRAM-MD5"))
+               has_cram = TRUE;
+       }
+    }
+    return(ok);
+}
+
 static int pop3_getauth(int sock, struct query *ctl, char *greeting)
 /* apply for connection authorization */
 {
@@ -133,21 +188,14 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
 #if OPIE_ENABLE
     char *challenge;
 #endif /* OPIE_ENABLE */
-#if defined(GSSAPI)
-    flag has_gssapi = FALSE;
-#endif /* defined(GSSAPI) */
-#if defined(KERBEROS_V4) || defined(KERBEROS_V5)
-    flag has_kerberos = FALSE;
-#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
-    flag has_cram = FALSE;
-#ifdef OPIE_ENABLE
-    flag has_otp = FALSE;
-#endif /* OPIE_ENABLE */
 #ifdef SSL_ENABLE
-    flag has_ssl = FALSE;
     flag did_stls = FALSE;
 #endif /* SSL_ENABLE */
 
+    if (ctl->server.authenticate == A_SSH) {
+        return PS_SUCCESS;
+    }
+
 #ifdef SDPS_ENABLE
     /*
      * This needs to catch both demon.co.uk and demon.net.
@@ -201,50 +249,21 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
         */
        if (ctl->server.authenticate == A_ANY)
        {
-           ok = gen_transact(sock, "CAPA");
-           if (ok == PS_SUCCESS)
-           {
-               char buffer[64];
-
-               /* determine what authentication methods we have available */
-               while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0)
+           if (capa_probe(sock) != PS_SUCCESS)
+           /* we are in STAGE_GETAUTH! */
+               if (ok == PS_AUTHFAIL ||
+                   /* Some servers directly close the socket. However, if we
+                    * have already authenticated before, then a previous CAPA
+                    * must have succeeded. In that case, treat this as a
+                    * genuine socket error and do not change the auth method.
+                    */
+                   (ok == PS_SOCKET && !ctl->wehaveauthed))
                {
-                   if (DOTLINE(buffer))
-                       break;
-#ifdef SSL_ENABLE
-                   if (strstr(buffer, "STLS"))
-                       has_ssl = TRUE;
-#endif /* SSL_ENABLE */
-#if defined(GSSAPI)
-                   if (strstr(buffer, "GSSAPI"))
-                       has_gssapi = TRUE;
-#endif /* defined(GSSAPI) */
-#if defined(KERBEROS_V4)
-                   if (strstr(buffer, "KERBEROS_V4"))
-                       has_kerberos = TRUE;
-#endif /* defined(KERBEROS_V4)  */
-#ifdef OPIE_ENABLE
-                   if (strstr(buffer, "X-OTP"))
-                       has_otp = TRUE;
-#endif /* OPIE_ENABLE */
-                   if (strstr(buffer, "CRAM-MD5"))
-                       has_cram = TRUE;
+                   ctl->server.authenticate = A_PASSWORD;
+                   /* repoll immediately */
+                   ok = PS_REPOLL;
+                   break;
                }
-           }
-           /* we are in STAGE_GETAUTH! */
-           else if (ok == PS_AUTHFAIL ||
-               /* Some servers directly close the socket. However, if we
-                * have already authenticated before, then a previous CAPA
-                * must have succeeded. In that case, treat this as a
-                * genuine socket error and do not change the auth method.
-                */
-               (ok == PS_SOCKET && !ctl->wehaveauthed))
-           {
-               ctl->server.authenticate = A_PASSWORD;
-               /* repoll immediately */
-               ok = PS_REPOLL;
-               break;
-           }
        }
 
 #ifdef SSL_ENABLE
@@ -255,12 +274,13 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
            char *realhost;
 
           realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
-           gen_transact(sock, "STLS");
+           ok = gen_transact(sock, "STLS");
 
            /* We use "tls1" instead of ctl->sslproto, as we want STLS,
             * not other SSL protocols
             */
-          if (SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
+          if (ok == PS_SUCCESS &&
+              SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
           {
               if (!ctl->sslproto && !ctl->wehaveauthed)
               {
@@ -273,6 +293,18 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
                return(PS_AUTHFAIL);
            }
           did_stls = TRUE;
+
+          /*
+           * RFC 2595 says this:
+           *
+           * "Once TLS has been started, the client MUST discard cached
+           * information about server capabilities and SHOULD re-issue the
+           * CAPABILITY command.  This is necessary to protect against
+           * man-in-the-middle attacks which alter the capabilities list prior
+           * to STARTTLS.  The server MAY advertise different capabilities
+           * after STARTTLS."
+           */
+          capa_probe(sock);
        }
 #endif /* SSL_ENABLE */
 
@@ -792,11 +824,40 @@ static int pop3_fetch(int sock, struct query *ctl, int number, int *lenp)
     return(PS_SUCCESS);
 }
 
+static void mark_uid_seen(struct query *ctl, int number)
+/* Tell the UID code we've seen this. */
+{
+    if (ctl->newsaved)
+    {
+       struct idlist   *sdp;
+
+       for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
+           if (sdp->val.status.num == number)
+           {
+               sdp->val.status.mark = UID_SEEN;
+               save_str(&ctl->oldsaved, sdp->id,UID_SEEN);
+           }
+    }
+}
+
 static int pop3_delete(int sock, struct query *ctl, int number)
 /* delete a given message */
 {
+    int ok;
+    mark_uid_seen(ctl, number);
     /* actually, mark for deletion -- doesn't happen until QUIT time */
-    return(gen_transact(sock, "DELE %d", number));
+    ok = gen_transact(sock, "DELE %d", number);
+    if (ok != PS_SUCCESS)
+       return(ok);
+    delete_str(&ctl->newsaved, number);
+    return(PS_SUCCESS);
+}
+
+static int pop3_mark_seen(int sock, struct query *ctl, int number)
+/* mark a given message as seen */
+{
+    mark_uid_seen(ctl, number);
+    return(PS_SUCCESS);
 }
 
 static int pop3_logout(int sock, struct query *ctl)
@@ -856,6 +917,7 @@ const static struct method pop3 =
     NULL,              /* no way to fetch body alone */
     NULL,              /* no message trailer */
     pop3_delete,       /* how to delete a message */
+    pop3_mark_seen,    /* how to mark a message as seen */
     pop3_logout,       /* log out, we're done */
     FALSE,             /* no, we can't re-poll */
 };