static int actual_deletions = 0;
/* for "IMAP> IDLE" */
-static int saved_timeout = 0;
+static int saved_timeout = 0, idle_timeout = 0;
+static time_t idle_start_time = 0;
static int imap_ok(int sock, char *argbuf)
/* parse command response */
return(PS_LOCKBUSY);
}
}
+
+ if (stage == STAGE_IDLE)
+ {
+ /* reduce the timeout: servers may not reset their timeout
+ * when they send some information asynchronously */
+ mytimeout = idle_timeout - (time((time_t *) NULL) - idle_start_time);
+ if (mytimeout <= 0)
+ return(PS_IDLETIMEOUT);
+ }
} while
(tag[0] != '\0' && strncmp(buf, tag, strlen(tag)));
{
int ok = 0;
#ifdef SSL_ENABLE
- flag did_stls = FALSE;
- flag using_tls = FALSE;
-#endif /* SSL_ENABLE */
-
+ int got_tls = 0;
+ char *realhost;
+#endif
(void)greeting;
+
/*
* Assumption: expunges are cheap, so we want to do them
* after every message unless user said otherwise.
}
#ifdef SSL_ENABLE
- if ((!ctl->sslproto || !strcasecmp(ctl->sslproto,"tls1"))
- && !ctl->use_ssl
- && strstr(capabilities, "STARTTLS"))
- {
- char *realhost;
-
- realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
- ok = gen_transact(sock, "STARTTLS");
-
- /* We use "tls1" instead of ctl->sslproto, as we want STARTTLS,
- * not other SSL protocols
- */
- if (ok == PS_SUCCESS &&
- SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck,
- ctl->sslcertpath,ctl->sslfingerprint,
- realhost,ctl->server.pollname,&ctl->remotename) == -1)
- {
- if (!ctl->sslproto && !ctl->wehaveauthed)
- {
- ctl->sslproto = xstrdup("");
- /* repoll immediately with TLS disabled */
- return(PS_REPOLL);
- }
- report(stderr,
- GT_("TLS connection failed.\n"));
- return PS_SOCKET;
- } else {
- using_tls = TRUE;
- if (outlevel >= O_VERBOSE && !ctl->sslproto)
- report(stdout, GT_("%s: opportunistic upgrade to TLS.\n"), realhost);
- }
- 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, ctl);
- }
- /* Check if TLS was enforced. */
- if ((ctl->sslproto && !strcasecmp(ctl->sslproto,"tls1")) && !ctl->use_ssl && !using_tls) {
- report(stderr, GT_("TLS connection failed.\n"));
- return PS_SOCKET;
+ realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
+
+ if (maybe_tls(ctl)) {
+ if (strstr(capabilities, "STARTTLS"))
+ {
+ /* Use "tls1" rather than ctl->sslproto because tls1 is the only
+ * protocol that will work with STARTTLS. Don't need to worry
+ * whether TLS is mandatory or opportunistic unless SSLOpen() fails
+ * (see below). */
+ if (gen_transact(sock, "STARTTLS") == PS_SUCCESS
+ && SSLOpen(sock, ctl->sslcert, ctl->sslkey, "tls1", ctl->sslcertck,
+ ctl->sslcertpath, ctl->sslfingerprint, realhost,
+ ctl->server.pollname, &ctl->remotename) != -1)
+ {
+ /*
+ * 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."
+ *
+ * Now that we're confident in our TLS connection we can
+ * guarantee a secure capability re-probe.
+ */
+ got_tls = 1;
+ capa_probe(sock, ctl);
+ if (outlevel >= O_VERBOSE)
+ {
+ report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), realhost);
+ }
+ }
+ }
+
+ if (!got_tls) {
+ if (must_tls(ctl)) {
+ /* Config required TLS but we couldn't guarantee it, so we must
+ * stop. */
+ report(stderr, GT_("%s: upgrade to TLS failed.\n"), realhost);
+ return PS_SOCKET;
+ } else {
+ if (outlevel >= O_VERBOSE) {
+ report(stdout, GT_("%s: opportunistic upgrade to TLS failed, trying to continue\n"), realhost);
+ }
+ /* We don't know whether the connection is in a working state, so
+ * test by issuing a NOOP. */
+ if (gen_transact(sock, "NOOP") != PS_SUCCESS) {
+ /* Not usable. Empty sslproto to force an unencrypted
+ * connection on the next attempt, and repoll. */
+ ctl->sslproto = xstrdup("");
+ return PS_REPOLL;
+ }
+ /* Usable. Proceed with authenticating insecurely. */
+ }
+ }
}
#endif /* SSL_ENABLE */
snprintf(shroud, sizeof (shroud), "\"%s\"", password);
ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password);
+ memset(shroud, 0x55, sizeof(shroud));
shroud[0] = '\0';
+ memset(password, 0x55, strlen(password));
free(password);
free(remotename);
-#ifdef SSL_ENABLE
- /* this is for servers which claim to support TLS, but actually
- * don't! */
- if (did_stls && ok == PS_SOCKET && !ctl->sslproto && !ctl->wehaveauthed)
- {
- ctl->sslproto = xstrdup("");
- /* repoll immediately */
- ok = PS_REPOLL;
- }
-#endif
if (ok)
{
/* SASL cancellation of authentication */
/* special timeout to terminate the IDLE and re-issue it
* at least every 28 minutes:
* (the server may have an inactivity timeout) */
- mytimeout = 1680; /* 28 min */
+ mytimeout = idle_timeout = 1680; /* 28 min */
+ time(&idle_start_time);
stage = STAGE_IDLE;
/* enter IDLE mode */
ok = gen_transact(sock, "IDLE");
* notification out of the blue. This is in compliance
* with RFC 2060 section 5.3. Wait for that with a low
* timeout */
- mytimeout = 28;
+ mytimeout = idle_timeout = 28;
+ time(&idle_start_time);
stage = STAGE_IDLE;
/* We are waiting for notification; no tag needed */
tag[0] = '\0';