Coverage Report

Created: 2023-06-07 06:15

/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
}