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)
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 */
{
#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.
*/
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
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)
{
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 */
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)
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 */
};