Hi guys,
unfortunatly mutt doesn't work well together with M$ smtp servers.
To be precise it is the gsasl implementation in mutt.
Other than the implementation with the cyrus sasl lib the gsasl
implementatiion does not send the initial response in the AUTH
command, but only sends an AUTH <mech>.
The smtp server than shall send an empty challenge, i.e. "334 ".
However - gues who does not do that - yes M$. The M$ exchange
server does put an arbitrary string to the 334, e.g:
334 GSSAPI supported
Of course this violates the RFC. But was there ever a standard
that was not broken by MS? I can't remember.
However passing this string to gsasl, of course will fail.
The best would be to ignore the first messag in case the client
must start the handshake, or even better put the IR directly into
the AUTH message, but unfortunatly gsasl doesn't support a way
to find out, wether the mech is client first or server first.
At least I havn't found any.
Thus I now created a hack, checking the server answer, and if
it is not a valid base64 encoding, the message is thrown away
and an empty string is passed to gsasl.
Yes - This is extremly ugly - I don't like that hack, but it
works.
Here is the patch, maybe someone can push it.
---snip---
diff --git a/smtp.c b/smtp.c
index 8837c7da..b49297c3 100644
--- a/smtp.c
+++ b/smtp.c
@@ -743,6 +743,22 @@ fail:
#endif /* USE_SASL_CYRUS */
#ifdef USE_SASL_GNU
+static int mutt_response_isbase64(BUFFER *response)
+{
+ const char *data;
+ data = response ? mutt_b2s (response) : "";
+ /* ignore leading space */
+ if (*data == ' ') data++;
+ for (; *data; data++) {
+ if ((*data >= 'A' && *data <= 'Z') || (*data >= 'a' && *data <= 'z') ||
+ (*data >= '0' && *data <= '9') || *data == '/' || *data == '+')
+ continue;
+ if (*data == '=' && (!data[1] || (data[1]=='=' && !data[2]))) return 1;
+ return 0;
+ }
+ return 1;
+}
+
static int smtp_auth_gsasl (CONNECTION *conn, const char *method)
{
Gsasl_session *gsasl_session = NULL;
@@ -779,6 +795,9 @@ static int smtp_auth_gsasl (CONNECTION *conn, const char
*method)
/* Work around broken SMTP servers. See Debian #1010658.
* The msmtp source also forces IR for PLAIN because the author
* encountered difficulties with a server requiring it.
+ * FRK: Really it was the same problem as below with an empty challenge
+ * that is not empty - never the less, leave this hack in here,
+ * still better than the hack below.
*/
if (!mutt_strcmp (chosen_mech, "PLAIN"))
{
@@ -808,8 +827,29 @@ static int smtp_auth_gsasl (CONNECTION *conn, const char
*method)
if (smtp_rc != smtp_ready)
break;
- gsasl_rc = gsasl_step64 (gsasl_session, mutt_b2s (smtp_response_buf),
- &gsasl_step_output);
+ /* FRK: some broken smtp servers (i.e. M$ exchange) instead of sending an
+ * empty challenge, they do send an arbitrary string (e.g. 334 GSSAPI
+ * supported). if we pass this to gsassl it will fail.
+ * The best solution would be to ignore the first message from the server
+ * in case the mech requires a client first step. Unfortunately gsasl
+ * does not have a way to find out wether a mech is client first or server
+ * first.
+ * As a hack, check wether the response buffer is valid base64 encoding,
+ * otherwise throw it away. This is extremely ugly, but for now I don't see
+ * a better way. Cross all fingers and hope, that no smtp server does send
a
+ * string, that looks like base64, but really isn't, then the algo still
+ * will fail.
+ */
+ if (!mutt_response_isbase64 (smtp_response_buf))
+ {
+ /* treat as empty challenge and throw away */
+ gsasl_rc = gsasl_step64 (gsasl_session, "", &gsasl_step_output);
+ }
+ else
+ {
+ gsasl_rc = gsasl_step64 (gsasl_session, mutt_b2s (smtp_response_buf),
+ &gsasl_step_output);
+ }
if (gsasl_rc == GSASL_NEEDS_MORE || gsasl_rc == GSASL_OK)
{
mutt_buffer_strcpy (output_buf, gsasl_step_output);
---snap----
Thx.
--
Don't worry be happy ...
Ciao Frank Reker