summaryrefslogtreecommitdiffstats
path: root/imap
diff options
context:
space:
mode:
Diffstat (limited to 'imap')
-rw-r--r--imap/Makefile.am7
-rw-r--r--imap/auth.c1
-rw-r--r--imap/auth.h1
-rw-r--r--imap/auth_oauth.c104
-rw-r--r--imap/command.c1
-rw-r--r--imap/imap_private.h1
6 files changed, 112 insertions, 3 deletions
diff --git a/imap/Makefile.am b/imap/Makefile.am
index 527b044f..199f6d6b 100644
--- a/imap/Makefile.am
+++ b/imap/Makefile.am
@@ -13,12 +13,13 @@ else
AUTHENTICATORS = auth_anon.c auth_cram.c
endif
-EXTRA_DIST = README TODO auth_anon.c auth_cram.c auth_gss.c auth_sasl.c
+EXTRA_DIST = README TODO auth_anon.c auth_cram.c auth_gss.c auth_oauth.c \
+ auth_sasl.c
AM_CPPFLAGS = -I$(top_srcdir) -I../intl
noinst_LIBRARIES = libimap.a
noinst_HEADERS = auth.h imap_private.h message.h
-libimap_a_SOURCES = auth.c auth_login.c browse.c command.c imap.c imap.h \
- message.c utf7.c util.c $(AUTHENTICATORS) $(GSSSOURCES)
+libimap_a_SOURCES = auth.c auth_login.c auth_oauth.c browse.c command.c \
+ imap.c imap.h message.c utf7.c util.c $(AUTHENTICATORS) $(GSSSOURCES)
diff --git a/imap/auth.c b/imap/auth.c
index 047531a5..1b26077a 100644
--- a/imap/auth.c
+++ b/imap/auth.c
@@ -42,6 +42,7 @@ static const imap_auth_t imap_authenticators[] = {
{ imap_auth_cram_md5, "cram-md5" },
#endif
{ imap_auth_login, "login" },
+ { imap_auth_oauth, "oauthbearer" },
{ NULL, NULL }
};
diff --git a/imap/auth.h b/imap/auth.h
index 63107947..82ef2f4c 100644
--- a/imap/auth.h
+++ b/imap/auth.h
@@ -51,5 +51,6 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA* idata, const char* method);
#ifdef USE_SASL
imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method);
#endif
+imap_auth_res_t imap_auth_oauth (IMAP_DATA* idata, const char* method);
#endif /* _IMAP_AUTH_H */
diff --git a/imap/auth_oauth.c b/imap/auth_oauth.c
new file mode 100644
index 00000000..0bb5d2c2
--- /dev/null
+++ b/imap/auth_oauth.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 1999-2001,2005 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 2018 Brandon Long <blong@fiction.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* IMAP login/authentication code */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "mutt.h"
+#include "imap_private.h"
+#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)
+{
+ char* ibuf = NULL;
+ char* oauth_buf = NULL;
+ int len, ilen, oalen;
+ int rc;
+
+ /* 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;
+
+ mutt_message _("Authenticating (OAUTHBEARER)...");
+
+ /* get auth info */
+ if (mutt_account_getlogin (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+
+ /* We get the access token from the "imap_pass" field */
+ if (mutt_account_getpass (&idata->conn->account))
+ return IMAP_AUTH_FAILURE;
+
+ /* Determine the length of the keyed message digest, add 50 for
+ * overhead.
+ */
+ oalen = strlen (idata->conn->account.user) +
+ strlen (idata->conn->account.host) +
+ strlen (idata->conn->account.pass) + 50;
+ oauth_buf = safe_malloc (oalen);
+
+ snprintf (oauth_buf, oalen,
+ "n,a=%s,\001host=%s\001port=%d\001auth=Bearer %s\001\001",
+ idata->conn->account.user, idata->conn->account.host,
+ idata->conn->account.port, idata->conn->account.pass);
+
+ /* ibuf must be long enough to store the base64 encoding of
+ * oauth_buf, plus the additional debris.
+ */
+
+ ilen = strlen (oauth_buf) * 2 + 30;
+ ibuf = safe_malloc (ilen);
+ ibuf[0] = '\0';
+
+ safe_strcat (ibuf, ilen, "AUTHENTICATE OAUTHBEARER ");
+ len = strlen(ibuf);
+
+ mutt_to_base64 ((unsigned char*) (ibuf + len),
+ (unsigned char*) oauth_buf, strlen (oauth_buf),
+ ilen - len);
+
+ /* 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 (&oauth_buf);
+ FREE (&ibuf);
+
+ if (!rc)
+ {
+ mutt_clear_error();
+ return IMAP_AUTH_SUCCESS;
+ }
+
+ /* The error response was in SASL continuation, so "continue" the SASL
+ * to cause a failure and exit SASL input.
+ */
+ mutt_socket_write (idata->conn, "an noop\r\n");
+
+ mutt_error _("OAUTHBEARER authentication failed.");
+ mutt_sleep (2);
+ return IMAP_AUTH_FAILURE;
+}
diff --git a/imap/command.c b/imap/command.c
index c8825981..0d8fcc8b 100644
--- a/imap/command.c
+++ b/imap/command.c
@@ -64,6 +64,7 @@ static const char * const Capabilities[] = {
"AUTH=CRAM-MD5",
"AUTH=GSSAPI",
"AUTH=ANONYMOUS",
+ "AUTH=OAUTHBEARER",
"STARTTLS",
"LOGINDISABLED",
"IDLE",
diff --git a/imap/imap_private.h b/imap/imap_private.h
index 312fbfe4..d4337cbf 100644
--- a/imap/imap_private.h
+++ b/imap/imap_private.h
@@ -112,6 +112,7 @@ enum
ACRAM_MD5, /* RFC 2195: CRAM-MD5 authentication */
AGSSAPI, /* RFC 1731: GSSAPI authentication */
AUTH_ANON, /* AUTH=ANONYMOUS */
+ AUTH_OAUTHBEARER, /* RFC 7628: AUTH=OAUTHBEARER */
STARTTLS, /* RFC 2595: STARTTLS */
LOGINDISABLED, /* LOGINDISABLED */
IDLE, /* RFC 2177: IDLE */