/src/neomutt/imap/auth_oauth.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * IMAP OAUTH authentication method |
4 | | * |
5 | | * @authors |
6 | | * Copyright (C) 1999-2001,2005 Brendan Cully <brendan@kublai.com> |
7 | | * Copyright (C) 2018 Brandon Long <blong@fiction.net> |
8 | | * |
9 | | * @copyright |
10 | | * This program is free software: you can redistribute it and/or modify it under |
11 | | * the terms of the GNU General Public License as published by the Free Software |
12 | | * Foundation, either version 2 of the License, or (at your option) any later |
13 | | * version. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
18 | | * details. |
19 | | * |
20 | | * You should have received a copy of the GNU General Public License along with |
21 | | * this program. If not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | /** |
25 | | * @page imap_auth_oauth OAUTH authentication |
26 | | * |
27 | | * IMAP OAUTH authentication method |
28 | | */ |
29 | | |
30 | | #include "config.h" |
31 | | #include <stdbool.h> |
32 | | #include <stdio.h> |
33 | | #include "private.h" |
34 | | #include "mutt/lib.h" |
35 | | #include "config/lib.h" |
36 | | #include "core/lib.h" |
37 | | #include "conn/lib.h" |
38 | | #include "auth.h" |
39 | | #include "adata.h" |
40 | | #include "mutt_logging.h" |
41 | | |
42 | | /** |
43 | | * imap_auth_oauth_xoauth2 - Authenticate an IMAP connection using OAUTHBEARER or XOAUTH2 |
44 | | * @param adata Imap Account data |
45 | | * @param method Use this named method, or any available method if NULL |
46 | | * @param xoauth2 Use xoauth2 token (if true) or oauthbearer token (if false) |
47 | | * @retval num ImapAuth::ImapAuthRes Result, e.g. IMAP_AUTH_SUCCESS |
48 | | */ |
49 | | static enum ImapAuthRes imap_auth_oauth_xoauth2(struct ImapAccountData *adata, |
50 | | const char *method, bool xoauth2) |
51 | 0 | { |
52 | 0 | char *ibuf = NULL; |
53 | 0 | char *oauthbearer = NULL; |
54 | 0 | const char *authtype = xoauth2 ? "XOAUTH2" : "OAUTHBEARER"; |
55 | 0 | int ilen; |
56 | 0 | int rc; |
57 | | |
58 | | /* For now, we only support SASL_IR also and over TLS */ |
59 | 0 | if ((xoauth2 && !(adata->capabilities & IMAP_CAP_AUTH_XOAUTH2)) || |
60 | 0 | (!xoauth2 && !(adata->capabilities & IMAP_CAP_AUTH_OAUTHBEARER)) || |
61 | 0 | !(adata->capabilities & IMAP_CAP_SASL_IR) || (adata->conn->ssf == 0)) |
62 | 0 | { |
63 | 0 | return IMAP_AUTH_UNAVAIL; |
64 | 0 | } |
65 | | |
66 | | /* If they did not explicitly request or configure oauth then fail quietly */ |
67 | 0 | const char *const c_imap_oauth_refresh_command = cs_subset_string(NeoMutt->sub, "imap_oauth_refresh_command"); |
68 | 0 | if (!method && !c_imap_oauth_refresh_command) |
69 | 0 | return IMAP_AUTH_UNAVAIL; |
70 | | |
71 | | // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL |
72 | 0 | mutt_message(_("Authenticating (%s)..."), authtype); |
73 | | |
74 | | /* We get the access token from the imap_oauth_refresh_command */ |
75 | 0 | oauthbearer = mutt_account_getoauthbearer(&adata->conn->account, xoauth2); |
76 | 0 | if (!oauthbearer) |
77 | 0 | return IMAP_AUTH_FAILURE; |
78 | | |
79 | 0 | ilen = mutt_str_len(oauthbearer) + 30; |
80 | 0 | ibuf = mutt_mem_malloc(ilen); |
81 | 0 | snprintf(ibuf, ilen, "AUTHENTICATE %s %s", authtype, oauthbearer); |
82 | | |
83 | | /* This doesn't really contain a password, but the token is good for |
84 | | * an hour, so suppress it anyways. */ |
85 | 0 | rc = imap_exec(adata, ibuf, IMAP_CMD_PASS); |
86 | |
|
87 | 0 | FREE(&oauthbearer); |
88 | 0 | FREE(&ibuf); |
89 | |
|
90 | 0 | if (rc != IMAP_EXEC_SUCCESS) |
91 | 0 | { |
92 | | /* The error response was in SASL continuation, so continue the SASL |
93 | | * to cause a failure and exit SASL input. See RFC7628 3.2.3 */ |
94 | 0 | mutt_socket_send(adata->conn, "\001"); |
95 | 0 | rc = imap_exec(adata, ibuf, IMAP_CMD_NO_FLAGS); |
96 | 0 | } |
97 | |
|
98 | 0 | if (rc == IMAP_EXEC_SUCCESS) |
99 | 0 | { |
100 | 0 | mutt_clear_error(); |
101 | 0 | return IMAP_AUTH_SUCCESS; |
102 | 0 | } |
103 | | |
104 | | // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL |
105 | 0 | mutt_error(_("%s authentication failed"), authtype); |
106 | 0 | return IMAP_AUTH_FAILURE; |
107 | 0 | } |
108 | | |
109 | | /** |
110 | | * imap_auth_oauth - Authenticate an IMAP connection using OAUTHBEARER - Implements ImapAuth::authenticate() |
111 | | */ |
112 | | enum ImapAuthRes imap_auth_oauth(struct ImapAccountData *adata, const char *method) |
113 | 0 | { |
114 | 0 | return imap_auth_oauth_xoauth2(adata, method, false); |
115 | 0 | } |
116 | | |
117 | | /** |
118 | | * imap_auth_xoauth2 - Authenticate an IMAP connection using XOAUTH2 - Implements ImapAuth::authenticate() |
119 | | */ |
120 | | enum ImapAuthRes imap_auth_xoauth2(struct ImapAccountData *adata, const char *method) |
121 | 0 | { |
122 | 0 | return imap_auth_oauth_xoauth2(adata, method, true); |
123 | 0 | } |