Coverage Report

Created: 2023-09-25 07:17

/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 rc;
56
57
  /* For now, we only support SASL_IR also and over TLS */
58
0
  if ((xoauth2 && !(adata->capabilities & IMAP_CAP_AUTH_XOAUTH2)) ||
59
0
      (!xoauth2 && !(adata->capabilities & IMAP_CAP_AUTH_OAUTHBEARER)) ||
60
0
      !(adata->capabilities & IMAP_CAP_SASL_IR) || (adata->conn->ssf == 0))
61
0
  {
62
0
    return IMAP_AUTH_UNAVAIL;
63
0
  }
64
65
  /* If they did not explicitly request or configure oauth then fail quietly */
66
0
  const char *const c_imap_oauth_refresh_command = cs_subset_string(NeoMutt->sub, "imap_oauth_refresh_command");
67
0
  if (!method && !c_imap_oauth_refresh_command)
68
0
    return IMAP_AUTH_UNAVAIL;
69
70
  // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
71
0
  mutt_message(_("Authenticating (%s)..."), authtype);
72
73
  /* We get the access token from the imap_oauth_refresh_command */
74
0
  oauthbearer = mutt_account_getoauthbearer(&adata->conn->account, xoauth2);
75
0
  if (!oauthbearer)
76
0
    return IMAP_AUTH_FAILURE;
77
78
0
  mutt_str_asprintf(&ibuf, "AUTHENTICATE %s %s", authtype, oauthbearer);
79
80
  /* This doesn't really contain a password, but the token is good for
81
   * an hour, so suppress it anyways.  */
82
0
  rc = imap_exec(adata, ibuf, IMAP_CMD_PASS);
83
84
0
  FREE(&oauthbearer);
85
0
  FREE(&ibuf);
86
87
0
  if (rc != IMAP_EXEC_SUCCESS)
88
0
  {
89
    /* The error response was in SASL continuation, so continue the SASL
90
     * to cause a failure and exit SASL input.  See RFC7628 3.2.3 */
91
0
    mutt_socket_send(adata->conn, "\001");
92
0
    rc = imap_exec(adata, ibuf, IMAP_CMD_NO_FLAGS);
93
0
  }
94
95
0
  if (rc == IMAP_EXEC_SUCCESS)
96
0
  {
97
0
    mutt_clear_error();
98
0
    return IMAP_AUTH_SUCCESS;
99
0
  }
100
101
  // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
102
0
  mutt_error(_("%s authentication failed"), authtype);
103
0
  return IMAP_AUTH_FAILURE;
104
0
}
105
106
/**
107
 * imap_auth_oauth - Authenticate an IMAP connection using OAUTHBEARER - Implements ImapAuth::authenticate()
108
 */
109
enum ImapAuthRes imap_auth_oauth(struct ImapAccountData *adata, const char *method)
110
0
{
111
0
  return imap_auth_oauth_xoauth2(adata, method, false);
112
0
}
113
114
/**
115
 * imap_auth_xoauth2 - Authenticate an IMAP connection using XOAUTH2 - Implements ImapAuth::authenticate()
116
 */
117
enum ImapAuthRes imap_auth_xoauth2(struct ImapAccountData *adata, const char *method)
118
0
{
119
0
  return imap_auth_oauth_xoauth2(adata, method, true);
120
0
}