NeoMutt  2022-04-29-249-gaae397
Teaching an old dog new tricks
DOXYGEN
auth.h File Reference

IMAP authenticator multiplexor. More...

#include "config.h"
#include <stdbool.h>
+ Include dependency graph for auth.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  ImapAuthRes { IMAP_AUTH_SUCCESS = 0 , IMAP_AUTH_FAILURE , IMAP_AUTH_UNAVAIL }
 Results of IMAP Authentication. More...
 

Functions

bool imap_auth_is_valid (const char *authenticator)
 Check if string is a valid imap authentication method. More...
 
enum ImapAuthRes imap_auth_plain (struct ImapAccountData *adata, const char *method)
 SASL PLAIN support - Implements ImapAuth::authenticate() More...
 
enum ImapAuthRes imap_auth_anon (struct ImapAccountData *adata, const char *method)
 Authenticate anonymously - Implements ImapAuth::authenticate() More...
 
enum ImapAuthRes imap_auth_cram_md5 (struct ImapAccountData *adata, const char *method)
 Authenticate using CRAM-MD5 - Implements ImapAuth::authenticate() More...
 
enum ImapAuthRes imap_auth_login (struct ImapAccountData *adata, const char *method)
 Plain LOGIN support - Implements ImapAuth::authenticate() More...
 
enum ImapAuthRes imap_auth_gss (struct ImapAccountData *adata, const char *method)
 GSS Authentication support - Implements ImapAuth::authenticate() More...
 
enum ImapAuthRes imap_auth_oauth (struct ImapAccountData *adata, const char *method)
 Authenticate an IMAP connection using OAUTHBEARER - Implements ImapAuth::authenticate() More...
 
enum ImapAuthRes imap_auth_xoauth2 (struct ImapAccountData *adata, const char *method)
 Authenticate an IMAP connection using XOAUTH2 - Implements ImapAuth::authenticate() More...
 

Detailed Description

IMAP authenticator multiplexor.

Authors
  • Brendan Cully

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, see http://www.gnu.org/licenses/.

Definition in file auth.h.

Enumeration Type Documentation

◆ ImapAuthRes

Results of IMAP Authentication.

Enumerator
IMAP_AUTH_SUCCESS 

Authentication successful.

IMAP_AUTH_FAILURE 

Authentication failed.

IMAP_AUTH_UNAVAIL 

Authentication method not permitted.

Definition at line 37 of file auth.h.

38{
42};
@ IMAP_AUTH_FAILURE
Authentication failed.
Definition: auth.h:40
@ IMAP_AUTH_SUCCESS
Authentication successful.
Definition: auth.h:39
@ IMAP_AUTH_UNAVAIL
Authentication method not permitted.
Definition: auth.h:41

Function Documentation

◆ imap_auth_is_valid()

bool imap_auth_is_valid ( const char *  authenticator)

Check if string is a valid imap authentication method.

Parameters
authenticatorAuthenticator string to check
Return values
trueArgument is a valid auth method

Validate whether an input string is an accepted imap authentication method as defined by ImapAuthenticators.

Definition at line 90 of file auth.c.

91{
92 for (size_t i = 0; i < mutt_array_size(ImapAuthenticators); i++)
93 {
94 const struct ImapAuth *auth = &ImapAuthenticators[i];
95 if (auth->method && mutt_istr_equal(auth->method, authenticator))
96 return true;
97 }
98
99 return false;
100}
static const struct ImapAuth ImapAuthenticators[]
Accepted authentication methods.
Definition: auth.c:59
#define mutt_array_size(x)
Definition: memory.h:36
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
IMAP authentication multiplexor.
Definition: auth.c:43
const char * method
Name of authentication method supported, NULL means variable.
Definition: auth.c:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_auth_plain()

enum ImapAuthRes imap_auth_plain ( struct ImapAccountData adata,
const char *  method 
)

SASL PLAIN support - Implements ImapAuth::authenticate()

Definition at line 41 of file auth_plain.c.

42{
43 int rc = IMAP_RES_CONTINUE;
45 static const char auth_plain_cmd[] = "AUTHENTICATE PLAIN";
46 char buf[256] = { 0 };
47
48 if (mutt_account_getuser(&adata->conn->account) < 0)
49 return IMAP_AUTH_FAILURE;
50 if (mutt_account_getpass(&adata->conn->account) < 0)
51 return IMAP_AUTH_FAILURE;
52
53 mutt_message(_("Logging in..."));
54
55 /* Prepare full AUTHENTICATE PLAIN message */
56 mutt_sasl_plain_msg(buf, sizeof(buf), auth_plain_cmd, adata->conn->account.user,
57 adata->conn->account.user, adata->conn->account.pass);
58
59 if (adata->capabilities & IMAP_CAP_SASL_IR)
60 {
61 imap_cmd_start(adata, buf);
62 }
63 else
64 {
65 /* Split the message so we send AUTHENTICATE PLAIN first, and the
66 * credentials after the first command continuation request */
67 buf[sizeof(auth_plain_cmd) - 1] = '\0';
68 imap_cmd_start(adata, buf);
69 while (rc == IMAP_RES_CONTINUE)
70 {
71 rc = imap_cmd_step(adata);
72 }
73 if (rc == IMAP_RES_RESPOND)
74 {
75 mutt_str_cat(buf + sizeof(auth_plain_cmd),
76 sizeof(buf) - sizeof(auth_plain_cmd), "\r\n");
77 mutt_socket_send(adata->conn, buf + sizeof(auth_plain_cmd));
79 }
80 }
81
82 while (rc == IMAP_RES_CONTINUE)
83 {
84 rc = imap_cmd_step(adata);
85 }
86
87 if (rc == IMAP_RES_BAD)
88 {
90 }
91 else if (rc == IMAP_RES_NO)
92 {
93 mutt_error(_("Login failed"));
95 }
96
98 return res;
99}
ImapAuthRes
Results of IMAP Authentication.
Definition: auth.h:38
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:130
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:50
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
int imap_cmd_start(struct ImapAccountData *adata, const char *cmdstr)
Given an IMAP command, send it to the server.
Definition: command.c:1062
int imap_cmd_step(struct ImapAccountData *adata)
Reads server responses from an IMAP command.
Definition: command.c:1076
#define IMAP_RES_RESPOND
+
Definition: private.h:58
#define IMAP_RES_NO
<tag> NO ...
Definition: private.h:54
#define IMAP_CAP_SASL_IR
SASL initial response draft.
Definition: private.h:136
#define IMAP_RES_CONTINUE
* ...
Definition: private.h:57
#define IMAP_RES_BAD
<tag> BAD ...
Definition: private.h:55
#define _(a)
Definition: message.h:28
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:265
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
size_t mutt_sasl_plain_msg(char *buf, size_t buflen, const char *cmd, const char *authz, const char *user, const char *pass)
Construct a base64 encoded SASL PLAIN message.
Definition: sasl_plain.c:55
#define mutt_socket_send(conn, buf)
Definition: socket.h:59
char user[128]
Username.
Definition: connaccount.h:56
char pass[256]
Password.
Definition: connaccount.h:57
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
ImapCapFlags capabilities
Capability flags.
Definition: adata.h:55
struct Connection * conn
Connection to IMAP server.
Definition: adata.h:41
+ Here is the call graph for this function:

◆ imap_auth_anon()

enum ImapAuthRes imap_auth_anon ( struct ImapAccountData adata,
const char *  method 
)

Authenticate anonymously - Implements ImapAuth::authenticate()

This is basically a stripped-down version of the cram-md5 method.

Definition at line 41 of file auth_anon.c.

42{
43 int rc;
44
46 return IMAP_AUTH_UNAVAIL;
47
48 if (mutt_account_getuser(&adata->conn->account) < 0)
49 return IMAP_AUTH_FAILURE;
50
51 if (adata->conn->account.user[0] != '\0')
52 return IMAP_AUTH_UNAVAIL;
53
54 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
55 mutt_message(_("Authenticating (%s)..."), "anonymous");
56
57 imap_cmd_start(adata, "AUTHENTICATE ANONYMOUS");
58
59 do
60 {
61 rc = imap_cmd_step(adata);
62 } while (rc == IMAP_RES_CONTINUE);
63
64 if (rc != IMAP_RES_RESPOND)
65 {
66 mutt_debug(LL_DEBUG1, "Invalid response from server\n");
67 goto bail;
68 }
69
70 mutt_socket_send(adata->conn, "ZHVtbXkK\r\n"); /* base64 ("dummy") */
71
72 do
73 {
74 rc = imap_cmd_step(adata);
75 } while (rc == IMAP_RES_CONTINUE);
76
77 if (rc != IMAP_RES_OK)
78 {
79 mutt_debug(LL_DEBUG1, "Error receiving server response\n");
80 goto bail;
81 }
82
83 if (imap_code(adata->buf))
84 return IMAP_AUTH_SUCCESS;
85
86bail:
87 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
88 mutt_error(_("%s authentication failed"), "anonymous");
89 return IMAP_AUTH_FAILURE;
90}
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
bool imap_code(const char *s)
Was the command successful.
Definition: command.c:1199
#define IMAP_RES_OK
<tag> OK ...
Definition: private.h:56
#define IMAP_CAP_AUTH_ANONYMOUS
AUTH=ANONYMOUS.
Definition: private.h:130
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
char * buf
Definition: adata.h:59
+ Here is the call graph for this function:

◆ imap_auth_cram_md5()

enum ImapAuthRes imap_auth_cram_md5 ( struct ImapAccountData adata,
const char *  method 
)

Authenticate using CRAM-MD5 - Implements ImapAuth::authenticate()

Definition at line 94 of file auth_cram.c.

95{
96 char ibuf[2048], obuf[1024];
97 unsigned char hmac_response[MD5_DIGEST_LEN];
98 int len;
99 int rc;
100
101 if (!(adata->capabilities & IMAP_CAP_AUTH_CRAM_MD5))
102 return IMAP_AUTH_UNAVAIL;
103
104 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
105 mutt_message(_("Authenticating (%s)..."), "CRAM-MD5");
106
107 /* get auth info */
108 if (mutt_account_getlogin(&adata->conn->account) < 0)
109 return IMAP_AUTH_FAILURE;
110 if (mutt_account_getpass(&adata->conn->account) < 0)
111 return IMAP_AUTH_FAILURE;
112
113 imap_cmd_start(adata, "AUTHENTICATE CRAM-MD5");
114
115 /* From RFC2195:
116 * The data encoded in the first ready response contains a presumptively
117 * arbitrary string of random digits, a timestamp, and the fully-qualified
118 * primary host name of the server. The syntax of the unencoded form must
119 * correspond to that of an RFC822 'msg-id' [RFC822] as described in [POP3]. */
120 do
121 {
122 rc = imap_cmd_step(adata);
123 } while (rc == IMAP_RES_CONTINUE);
124
125 if (rc != IMAP_RES_RESPOND)
126 {
127 mutt_debug(LL_DEBUG1, "Invalid response from server: %s\n", ibuf);
128 goto bail;
129 }
130
131 len = mutt_b64_decode(adata->buf + 2, obuf, sizeof(obuf));
132 if (len == -1)
133 {
134 mutt_debug(LL_DEBUG1, "Error decoding base64 response\n");
135 goto bail;
136 }
137
138 obuf[len] = '\0';
139 mutt_debug(LL_DEBUG2, "CRAM challenge: %s\n", obuf);
140
141 /* The client makes note of the data and then responds with a string
142 * consisting of the user name, a space, and a 'digest'. The latter is
143 * computed by applying the keyed MD5 algorithm from [KEYED-MD5] where the
144 * key is a shared secret and the digested text is the timestamp (including
145 * angle-brackets).
146 *
147 * Note: The user name shouldn't be quoted. Since the digest can't contain
148 * spaces, there is no ambiguity. Some servers get this wrong, we'll work
149 * around them when the bug report comes in. Until then, we'll remain
150 * blissfully RFC-compliant. */
151 hmac_md5(adata->conn->account.pass, obuf, hmac_response);
152 /* dubious optimisation I saw elsewhere: make the whole string in one call */
153 int off = snprintf(obuf, sizeof(obuf), "%s ", adata->conn->account.user);
154 mutt_md5_toascii(hmac_response, obuf + off);
155 mutt_debug(LL_DEBUG2, "CRAM response: %s\n", obuf);
156
157 /* ibuf must be long enough to store the base64 encoding of obuf,
158 * plus the additional debris */
159 mutt_b64_encode(obuf, strlen(obuf), ibuf, sizeof(ibuf) - 2);
160 mutt_str_cat(ibuf, sizeof(ibuf), "\r\n");
161 mutt_socket_send(adata->conn, ibuf);
162
163 do
164 {
165 rc = imap_cmd_step(adata);
166 } while (rc == IMAP_RES_CONTINUE);
167
168 if (rc != IMAP_RES_OK)
169 {
170 mutt_debug(LL_DEBUG1, "Error receiving server response\n");
171 goto bail;
172 }
173
174 if (imap_code(adata->buf))
175 return IMAP_AUTH_SUCCESS;
176
177bail:
178 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
179 mutt_error(_("%s authentication failed"), "CRAM-MD5");
180 return IMAP_AUTH_FAILURE;
181}
static void hmac_md5(const char *password, char *challenge, unsigned char *response)
Produce CRAM-MD5 challenge response.
Definition: auth_cram.c:47
#define MD5_DIGEST_LEN
Definition: auth_cram.c:39
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:88
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:136
int mutt_account_getlogin(struct ConnAccount *cac)
Retrieve login info into ConnAccount, if necessary.
Definition: connaccount.c:100
#define IMAP_CAP_AUTH_CRAM_MD5
RFC2195: CRAM-MD5 authentication.
Definition: private.h:128
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
void mutt_md5_toascii(const void *digest, char *resbuf)
Convert a binary MD5 digest into ASCII Hexadecimal.
Definition: md5.c:457
+ Here is the call graph for this function:

◆ imap_auth_login()

enum ImapAuthRes imap_auth_login ( struct ImapAccountData adata,
const char *  method 
)

Plain LOGIN support - Implements ImapAuth::authenticate()

Definition at line 44 of file auth_login.c.

45{
46 char q_user[256], q_pass[256];
47 char buf[1024] = { 0 };
48
50 {
51 mutt_message(_("LOGIN disabled on this server"));
52 return IMAP_AUTH_UNAVAIL;
53 }
54
55 if (mutt_account_getuser(&adata->conn->account) < 0)
56 return IMAP_AUTH_FAILURE;
57 if (mutt_account_getpass(&adata->conn->account) < 0)
58 return IMAP_AUTH_FAILURE;
59
60 mutt_message(_("Logging in..."));
61
62 imap_quote_string(q_user, sizeof(q_user), adata->conn->account.user, false);
63 imap_quote_string(q_pass, sizeof(q_pass), adata->conn->account.pass, false);
64
65 /* don't print the password unless we're at the ungodly debugging level
66 * of 5 or higher */
67
68 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
69 if (c_debug_level < IMAP_LOG_PASS)
70 mutt_debug(LL_DEBUG2, "Sending LOGIN command for %s\n", adata->conn->account.user);
71
72 snprintf(buf, sizeof(buf), "LOGIN %s %s", q_user, q_pass);
73 if (imap_exec(adata, buf, IMAP_CMD_PASS) == IMAP_EXEC_SUCCESS)
74 {
76 return IMAP_AUTH_SUCCESS;
77 }
78
79 mutt_error(_("Login failed"));
80 return IMAP_AUTH_FAILURE;
81}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition: command.c:1247
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition: util.c:837
#define IMAP_CMD_PASS
Command contains a password. Suppress logging.
Definition: private.h:74
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition: private.h:84
#define IMAP_LOG_PASS
Definition: private.h:51
#define IMAP_CAP_LOGINDISABLED
RFC2595: LOGINDISABLED.
Definition: private.h:134
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:

◆ imap_auth_gss()

enum ImapAuthRes imap_auth_gss ( struct ImapAccountData adata,
const char *  method 
)

GSS Authentication support - Implements ImapAuth::authenticate()

Definition at line 104 of file auth_gss.c.

105{
106 gss_buffer_desc request_buf, send_token;
107 gss_buffer_t sec_token;
108 gss_name_t target_name;
109 gss_ctx_id_t context;
110 gss_OID mech_name;
111 char server_conf_flags;
112 gss_qop_t quality;
113 int cflags;
114 OM_uint32 maj_stat, min_stat;
115 unsigned long buf_size;
116 int rc, retval = IMAP_AUTH_FAILURE;
117
118 if (!(adata->capabilities & IMAP_CAP_AUTH_GSSAPI))
119 return IMAP_AUTH_UNAVAIL;
120
121 if (mutt_account_getuser(&adata->conn->account) < 0)
122 return IMAP_AUTH_FAILURE;
123
124 struct Buffer *buf1 = mutt_buffer_pool_get();
125 struct Buffer *buf2 = mutt_buffer_pool_get();
126
127 /* get an IMAP service ticket for the server */
128 mutt_buffer_printf(buf1, "imap@%s", adata->conn->account.host);
129 request_buf.value = buf1->data;
130 request_buf.length = mutt_buffer_len(buf1);
131
132 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
133 maj_stat = gss_import_name(&min_stat, &request_buf, gss_nt_service_name, &target_name);
134 if (maj_stat != GSS_S_COMPLETE)
135 {
136 mutt_debug(LL_DEBUG2, "Couldn't get service name for [%s]\n", buf1->data);
137 retval = IMAP_AUTH_UNAVAIL;
138 goto cleanup;
139 }
140 else if (c_debug_level >= 2)
141 {
142 gss_display_name(&min_stat, target_name, &request_buf, &mech_name);
143 mutt_debug(LL_DEBUG2, "Using service name [%s]\n", (char *) request_buf.value);
144 gss_release_buffer(&min_stat, &request_buf);
145 }
146 /* Acquire initial credentials - without a TGT GSSAPI is UNAVAIL */
147 sec_token = GSS_C_NO_BUFFER;
148 context = GSS_C_NO_CONTEXT;
149
150 /* build token */
151 maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context, target_name,
152 GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
153 0, GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL,
154 &send_token, (unsigned int *) &cflags, NULL);
155 if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
156 {
157 print_gss_error(maj_stat, min_stat);
158 mutt_debug(LL_DEBUG1, "Error acquiring credentials - no TGT?\n");
159 gss_release_name(&min_stat, &target_name);
160
161 retval = IMAP_AUTH_UNAVAIL;
162 goto cleanup;
163 }
164
165 /* now begin login */
166 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
167 mutt_message(_("Authenticating (%s)..."), "GSSAPI");
168
169 imap_cmd_start(adata, "AUTHENTICATE GSSAPI");
170
171 /* expect a null continuation response ("+") */
172 do
173 {
174 rc = imap_cmd_step(adata);
175 } while (rc == IMAP_RES_CONTINUE);
176
177 if (rc != IMAP_RES_RESPOND)
178 {
179 mutt_debug(LL_DEBUG2, "Invalid response from server: %s\n", buf1->data);
180 gss_release_name(&min_stat, &target_name);
181 goto bail;
182 }
183
184 /* now start the security context initialisation loop... */
185 mutt_debug(LL_DEBUG2, "Sending credentials\n");
186 mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
187 gss_release_buffer(&min_stat, &send_token);
188 mutt_buffer_addstr(buf1, "\r\n");
190
191 while (maj_stat == GSS_S_CONTINUE_NEEDED)
192 {
193 /* Read server data */
194 do
195 {
196 rc = imap_cmd_step(adata);
197 } while (rc == IMAP_RES_CONTINUE);
198
199 if (rc != IMAP_RES_RESPOND)
200 {
201 mutt_debug(LL_DEBUG1, "#1 Error receiving server response\n");
202 gss_release_name(&min_stat, &target_name);
203 goto bail;
204 }
205
206 if (mutt_b64_buffer_decode(buf2, adata->buf + 2) < 0)
207 {
208 mutt_debug(LL_DEBUG1, "Invalid base64 server response\n");
209 gss_release_name(&min_stat, &target_name);
210 goto err_abort_cmd;
211 }
212 request_buf.value = buf2->data;
213 request_buf.length = mutt_buffer_len(buf2);
214 sec_token = &request_buf;
215
216 /* Write client data */
217 maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context, target_name,
218 GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
219 0, GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL,
220 &send_token, (unsigned int *) &cflags, NULL);
221 if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
222 {
223 print_gss_error(maj_stat, min_stat);
224 mutt_debug(LL_DEBUG1, "Error exchanging credentials\n");
225 gss_release_name(&min_stat, &target_name);
226
227 goto err_abort_cmd;
228 }
229 mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
230 gss_release_buffer(&min_stat, &send_token);
231 mutt_buffer_addstr(buf1, "\r\n");
233 }
234
235 gss_release_name(&min_stat, &target_name);
236
237 /* get security flags and buffer size */
238 do
239 {
240 rc = imap_cmd_step(adata);
241 } while (rc == IMAP_RES_CONTINUE);
242
243 if (rc != IMAP_RES_RESPOND)
244 {
245 mutt_debug(LL_DEBUG1, "#2 Error receiving server response\n");
246 goto bail;
247 }
248 if (mutt_b64_buffer_decode(buf2, adata->buf + 2) < 0)
249 {
250 mutt_debug(LL_DEBUG1, "Invalid base64 server response\n");
251 goto err_abort_cmd;
252 }
253 request_buf.value = buf2->data;
254 request_buf.length = mutt_buffer_len(buf2);
255
256 maj_stat = gss_unwrap(&min_stat, context, &request_buf, &send_token, &cflags, &quality);
257 if (maj_stat != GSS_S_COMPLETE)
258 {
259 print_gss_error(maj_stat, min_stat);
260 mutt_debug(LL_DEBUG2, "Couldn't unwrap security level data\n");
261 gss_release_buffer(&min_stat, &send_token);
262 goto err_abort_cmd;
263 }
264 mutt_debug(LL_DEBUG2, "Credential exchange complete\n");
265
266 /* first octet is security levels supported. We want NONE */
267 server_conf_flags = ((char *) send_token.value)[0];
268 if (!(((char *) send_token.value)[0] & GSS_AUTH_P_NONE))
269 {
270 mutt_debug(LL_DEBUG2, "Server requires integrity or privacy\n");
271 gss_release_buffer(&min_stat, &send_token);
272 goto err_abort_cmd;
273 }
274
275 /* we don't care about buffer size if we don't wrap content. But here it is */
276 ((char *) send_token.value)[0] = '\0';
277 buf_size = ntohl(*((long *) send_token.value));
278 gss_release_buffer(&min_stat, &send_token);
279 mutt_debug(LL_DEBUG2, "Unwrapped security level flags: %c%c%c\n",
280 (server_conf_flags & GSS_AUTH_P_NONE) ? 'N' : '-',
281 (server_conf_flags & GSS_AUTH_P_INTEGRITY) ? 'I' : '-',
282 (server_conf_flags & GSS_AUTH_P_PRIVACY) ? 'P' : '-');
283 mutt_debug(LL_DEBUG2, "Maximum GSS token size is %ld\n", buf_size);
284
285 /* agree to terms (hack!) */
286 buf_size = htonl(buf_size); /* not relevant without integrity/privacy */
287 mutt_buffer_reset(buf1);
289 mutt_buffer_addstr_n(buf1, ((char *) &buf_size) + 1, 3);
290 /* server decides if principal can log in as user */
291 mutt_buffer_addstr(buf1, adata->conn->account.user);
292 request_buf.value = buf1->data;
293 request_buf.length = mutt_buffer_len(buf1);
294 maj_stat = gss_wrap(&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
295 &cflags, &send_token);
296 if (maj_stat != GSS_S_COMPLETE)
297 {
298 mutt_debug(LL_DEBUG2, "Error creating login request\n");
299 goto err_abort_cmd;
300 }
301
302 mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
303 mutt_debug(LL_DEBUG2, "Requesting authorisation as %s\n", adata->conn->account.user);
304 mutt_buffer_addstr(buf1, "\r\n");
306
307 /* Joy of victory or agony of defeat? */
308 do
309 {
310 rc = imap_cmd_step(adata);
311 } while (rc == IMAP_RES_CONTINUE);
312 if (rc == IMAP_RES_RESPOND)
313 {
314 mutt_debug(LL_DEBUG1, "Unexpected server continuation request\n");
315 goto err_abort_cmd;
316 }
317 if (imap_code(adata->buf))
318 {
319 /* flush the security context */
320 mutt_debug(LL_DEBUG2, "Releasing GSS credentials\n");
321 maj_stat = gss_delete_sec_context(&min_stat, &context, &send_token);
322 if (maj_stat != GSS_S_COMPLETE)
323 mutt_debug(LL_DEBUG1, "Error releasing credentials\n");
324
325 /* send_token may contain a notification to the server to flush
326 * credentials. RFC1731 doesn't specify what to do, and since this
327 * support is only for authentication, we'll assume the server knows
328 * enough to flush its own credentials */
329 gss_release_buffer(&min_stat, &send_token);
330
331 retval = IMAP_AUTH_SUCCESS;
332 goto cleanup;
333 }
334 else
335 goto bail;
336
337err_abort_cmd:
338 mutt_socket_send(adata->conn, "*\r\n");
339 do
340 {
341 rc = imap_cmd_step(adata);
342 } while (rc == IMAP_RES_CONTINUE);
343
344bail:
345 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
346 mutt_error(_("%s authentication failed"), "GSSAPI");
347 retval = IMAP_AUTH_FAILURE;
348
349cleanup:
352
353 return retval;
354}
#define GSS_AUTH_P_NONE
Definition: auth_gss.c:55
static void print_gss_error(OM_uint32 err_maj, OM_uint32 err_min)
Print detailed error message to the debug log.
Definition: auth_gss.c:64
#define GSS_AUTH_P_PRIVACY
Definition: auth_gss.c:57
#define GSS_AUTH_P_INTEGRITY
Definition: auth_gss.c:56
size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:199
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:217
size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:105
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define IMAP_CAP_AUTH_GSSAPI
RFC1731: GSSAPI authentication.
Definition: private.h:129
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
char host[128]
Server to login to.
Definition: connaccount.h:54
+ Here is the call graph for this function:

◆ imap_auth_oauth()

enum ImapAuthRes imap_auth_oauth ( struct ImapAccountData adata,
const char *  method 
)

Authenticate an IMAP connection using OAUTHBEARER - Implements ImapAuth::authenticate()

Definition at line 112 of file auth_oauth.c.

113{
114 return imap_auth_oauth_xoauth2(adata, method, false);
115}
enum ImapAuthRes imap_auth_oauth_xoauth2(struct ImapAccountData *adata, const char *method, bool xoauth2)
Authenticate an IMAP connection using OAUTHBEARER or XOAUTH2.
Definition: auth_oauth.c:49
+ Here is the call graph for this function:

◆ imap_auth_xoauth2()

enum ImapAuthRes imap_auth_xoauth2 ( struct ImapAccountData adata,
const char *  method 
)

Authenticate an IMAP connection using XOAUTH2 - Implements ImapAuth::authenticate()

Definition at line 120 of file auth_oauth.c.

121{
122 return imap_auth_oauth_xoauth2(adata, method, true);
123}
+ Here is the call graph for this function: