summaryrefslogtreecommitdiffstats
path: root/imap/auth_oauth.c
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2020-06-11 16:11:36 -0700
committerKevin McCarthy <kevin@8t8.us>2020-06-13 14:44:17 -0700
commitc7a872d1eeea39df148396869c1cbbc0fa26552f (patch)
tree0fa80c6f4e6e0a7f8693ee087f18b3870a16b718 /imap/auth_oauth.c
parent5b844328bb7d7fb0357328bed002e7672f9b9e2a (diff)
Add basic XOAUTH2 support.
This still relies on an external script to obtain the resource access token. Since XOAUTH2 should be slowly going away, use the same refresh_commands as with OAUTHBEARER. Unlike OAUTHBEARER, XOAUTH2 must be explicitly added to the $imap/smtp/pop_authenticators list. To keep the shared functions simpler, convert them to use buffers. RFC 7628 indicates that upon authentication failure the clients should be sending an BASE 64 encoded '^a' ("AQ=="), to terminate the SASL session, so change all the handlers to do that and read the following response. The RFC doesn't comment about a line terminator being required, but I assume it is, so add that too.
Diffstat (limited to 'imap/auth_oauth.c')
-rw-r--r--imap/auth_oauth.c102
1 files changed, 66 insertions, 36 deletions
diff --git a/imap/auth_oauth.c b/imap/auth_oauth.c
index a301e166..b7f01e4f 100644
--- a/imap/auth_oauth.c
+++ b/imap/auth_oauth.c
@@ -28,58 +28,88 @@
#include "auth.h"
/* imap_auth_oauth: AUTH=OAUTHBEARER support. See RFC 7628 */
-imap_auth_res_t imap_auth_oauth (IMAP_DATA* idata, const char* method)
+static imap_auth_res_t imap_auth_oauth (IMAP_DATA* idata, int xoauth2)
{
- char* ibuf = NULL;
- char* oauthbearer = NULL;
- int ilen;
- int rc;
+ int rc = IMAP_AUTH_FAILURE, steprc;
+ BUFFER *bearertoken = NULL, *authline = NULL;
+ const char *authtype;
- /* For now, we only support SASL_IR also and over TLS */
- if (!mutt_bit_isset (idata->capabilities, AUTH_OAUTHBEARER) ||
- !mutt_bit_isset (idata->capabilities, SASL_IR) ||
- !idata->conn->ssf)
- return IMAP_AUTH_UNAVAIL;
+ authtype = xoauth2 ? "XOAUTH2" : "OAUTHBEARER";
- /* If they did not explicitly request or configure oauth then fail quietly */
- if (!(method || ImapOauthRefreshCmd))
- return IMAP_AUTH_UNAVAIL;
+ mutt_message (_("Authenticating (%s)..."), authtype);
- mutt_message _("Authenticating (OAUTHBEARER)...");
+ bearertoken = mutt_buffer_pool_get ();
+ authline = mutt_buffer_pool_get ();
/* We get the access token from the imap_oauth_refresh_command */
- oauthbearer = mutt_account_getoauthbearer (&idata->conn->account);
- if (oauthbearer == NULL)
- return IMAP_AUTH_FAILURE;
+ if (mutt_account_getoauthbearer (&idata->conn->account, bearertoken, xoauth2))
+ goto cleanup;
- ilen = strlen (oauthbearer) + 30;
- ibuf = safe_malloc (ilen);
- snprintf (ibuf, ilen, "AUTHENTICATE OAUTHBEARER %s", oauthbearer);
+ mutt_buffer_printf (authline, "AUTHENTICATE %s %s",
+ authtype, mutt_b2s (bearertoken));
/* This doesn't really contain a password, but the token is good for
* an hour, so suppress it anyways.
*/
- rc = imap_exec (idata, ibuf, IMAP_CMD_FAIL_OK | IMAP_CMD_PASS);
-
- FREE (&oauthbearer);
- FREE (&ibuf);
-
- if (rc)
+ if (imap_exec (idata, mutt_b2s (authline), IMAP_CMD_FAIL_OK | IMAP_CMD_PASS))
{
/* The error response was in SASL continuation, so continue the SASL
* to cause a failure and exit SASL input. See RFC 7628 3.2.3
+ * "AQ==" is Base64 encoded ^A (0x01) .
*/
- mutt_socket_write (idata->conn, "\001");
- rc = imap_exec (idata, ibuf, IMAP_CMD_FAIL_OK);
- }
+ mutt_socket_write (idata->conn, "AQ==\r\n");
+ do
+ steprc = imap_cmd_step (idata);
+ while (steprc == IMAP_CMD_CONTINUE);
- if (!rc)
- {
- mutt_clear_error();
- return IMAP_AUTH_SUCCESS;
+ /* L10N:
+ %s is the authentication type, for example OAUTHBEARER
+ */
+ mutt_error (_("%s authentication failed."), authtype);
+ mutt_sleep (2);
+ goto cleanup;
}
- mutt_error _("OAUTHBEARER authentication failed.");
- mutt_sleep (2);
- return IMAP_AUTH_FAILURE;
+ mutt_clear_error();
+ rc = IMAP_AUTH_SUCCESS;
+
+cleanup:
+ mutt_buffer_pool_release (&bearertoken);
+ mutt_buffer_pool_release (&authline);
+ return rc;
+}
+
+/* AUTH=OAUTHBEARER support. See RFC 7628 */
+imap_auth_res_t imap_auth_oauthbearer (IMAP_DATA* idata, const char* method)
+{
+ /* For now, we only support SASL_IR also and over TLS */
+ if (!mutt_bit_isset (idata->capabilities, SASL_IR) ||
+ !idata->conn->ssf)
+ return IMAP_AUTH_UNAVAIL;
+
+ if (!mutt_bit_isset (idata->capabilities, AUTH_OAUTHBEARER))
+ return IMAP_AUTH_UNAVAIL;
+
+ if (!ImapOauthRefreshCmd)
+ return IMAP_AUTH_UNAVAIL;
+
+ return imap_auth_oauth (idata, 0);
+}
+
+/* AUTH=XOAUTH2 support. */
+imap_auth_res_t imap_auth_xoauth2 (IMAP_DATA* idata, const char* method)
+{
+ /* For now, we only support SASL_IR also and over TLS */
+ if (!mutt_bit_isset (idata->capabilities, SASL_IR) ||
+ !idata->conn->ssf)
+ return IMAP_AUTH_UNAVAIL;
+
+ if (!mutt_bit_isset (idata->capabilities, AUTH_XOAUTH2))
+ return IMAP_AUTH_UNAVAIL;
+
+ /* If they did not explicitly request XOAUTH2 then fail quietly */
+ if (!(method && ImapOauthRefreshCmd))
+ return IMAP_AUTH_UNAVAIL;
+
+ return imap_auth_oauth (idata, 1);
}