+ /*
+ * CAPA command may return a list including available
+ * authentication mechanisms. if it doesn't, no harm done, we
+ * just fall back to a plain login. Note that this code
+ * latches the server's authentication type, so that in daemon mode
+ * the CAPA check only needs to be done once at start of run.
+ *
+ * If CAPA fails, then force the authentication method to PASSORD
+ * and repoll immediately.
+ *
+ * These authentication methods are blessed by RFC1734,
+ * describing the POP3 AUTHentication command.
+ */
+ if ((ctl->server.authenticate == A_ANY) ||
+ (ctl->server.authenticate == A_GSSAPI) ||
+ (ctl->server.authenticate == A_KERBEROS_V4) ||
+ (ctl->server.authenticate == A_OTP) ||
+ (ctl->server.authenticate == A_CRAM_MD5))
+ {
+ if ((ok = 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))
+ {
+ ctl->server.authenticate = A_PASSWORD;
+ /* repoll immediately */
+ ok = PS_REPOLL;
+ break;
+ }
+ }
+
+#ifdef SSL_ENABLE
+ if (has_ssl
+ && !ctl->use_ssl
+ && (!ctl->sslproto || !strcmp(ctl->sslproto,"tls1")))
+ {
+ char *realhost;
+
+ realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
+ ok = gen_transact(sock, "STLS");
+
+ /* We use "tls1" instead of ctl->sslproto, as we want STLS,
+ * 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) == -1)
+ {
+ if (!ctl->sslproto && !ctl->wehaveauthed)
+ {
+ ctl->sslproto = xstrdup("");
+ /* repoll immediately */
+ return(PS_REPOLL);
+ }
+ report(stderr,
+ GT_("SSL connection failed.\n"));
+ return PS_SOCKET;
+ }
+ 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 */
+
+ /*
+ * OK, we have an authentication type now.
+ */
+#if defined(KERBEROS_V4)
+ /*
+ * Servers doing KPOP have to go through a dummy login sequence
+ * rather than doing SASL.
+ */
+ if (has_kerberos &&
+ ctl->server.service && (strcmp(ctl->server.service, KPOP_PORT)!=0)
+ && (ctl->server.authenticate == A_KERBEROS_V4
+ || ctl->server.authenticate == A_KERBEROS_V5
+ || ctl->server.authenticate == A_ANY))
+ {
+ ok = do_rfc1731(sock, "AUTH", ctl->server.truename);
+ if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
+ break;
+ }
+#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
+
+#if defined(GSSAPI)
+ if (has_gssapi &&
+ (ctl->server.authenticate == A_GSSAPI ||
+ ctl->server.authenticate == A_ANY))
+ {
+ ok = do_gssauth(sock,"AUTH","pop",ctl->server.truename,ctl->remotename);
+ if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
+ break;
+ }
+#endif /* defined(GSSAPI) */
+
+#ifdef OPIE_ENABLE
+ if (has_otp &&
+ (ctl->server.authenticate == A_OTP ||
+ ctl->server.authenticate == A_ANY))
+ {
+ ok = do_otp(sock, "AUTH", ctl);
+ if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
+ break;
+ }
+#endif /* OPIE_ENABLE */
+
+ if (ctl->server.authenticate == A_CRAM_MD5 ||
+ (has_cram && ctl->server.authenticate == A_ANY))
+ {
+ ok = do_cram_md5(sock, "AUTH", ctl, NULL);
+ if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)
+ break;
+ }
+
+ /* ordinary validation, no one-time password or RPA */
+ if ((ok = gen_transact(sock, "USER %s", ctl->remotename)))
+ break;
+
+#ifdef OPIE_ENABLE