NeoMutt  2022-04-29-247-gc6aae8
Teaching an old dog new tricks
DOXYGEN
connaccount.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <assert.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include <sys/types.h>
35#include "mutt/lib.h"
36#include "gui/lib.h"
37#include "mutt.h"
38#include "connaccount.h"
39#include "enter/lib.h"
40#include "accountcmd.h"
41#include "mutt_globals.h"
42#include "options.h"
43
51{
52 if (cac->flags & MUTT_ACCT_USER)
53 return 0;
54 if (!cac->get_field)
55 return -1;
56
57 const char *user = cac->get_field(MUTT_CA_USER, cac->gf_data);
58 if (user)
59 {
60 mutt_str_copy(cac->user, user, sizeof(cac->user));
61 }
63 {
64 /* The external command might interact with the screen */
65 if (!OptNoCurses)
67 return 0;
68 }
69 else if (OptNoCurses)
70 {
71 return -1;
72 }
73 else
74 {
75 /* prompt (defaults to unix username), copy into cac->user */
76 char prompt[256] = { 0 };
77 /* L10N: Example: Username at myhost.com */
78 snprintf(prompt, sizeof(prompt), _("Username at %s: "), cac->host);
79 mutt_str_copy(cac->user, Username, sizeof(cac->user));
80
81 struct Buffer *buf = mutt_buffer_pool_get();
82 const int rc = mutt_buffer_get_field(prompt, buf, MUTT_COMP_UNBUFFERED,
83 false, NULL, NULL, NULL);
84 mutt_str_copy(cac->user, mutt_buffer_string(buf), sizeof(cac->user));
86 if (rc != 0)
87 return -1;
88 }
89
90 cac->flags |= MUTT_ACCT_USER;
91 return 0;
92}
93
101{
102 if (cac->flags & MUTT_ACCT_LOGIN)
103 return 0;
104 if (!cac->get_field)
105 return -1;
106
107 const char *login = cac->get_field(MUTT_CA_LOGIN, cac->gf_data);
108 if (!login && (mutt_account_getuser(cac) == 0))
109 {
110 login = cac->user;
111 }
112
113 if (!login)
114 {
115 mutt_debug(LL_DEBUG1, "Couldn't get user info\n");
116 return -1;
117 }
118
119 mutt_str_copy(cac->login, login, sizeof(cac->login));
120 cac->flags |= MUTT_ACCT_LOGIN;
121 return 0;
122}
123
131{
132 if (cac->flags & MUTT_ACCT_PASS)
133 return 0;
134 if (!cac->get_field)
135 return -1;
136
137 const char *pass = cac->get_field(MUTT_CA_PASS, cac->gf_data);
138 if (pass)
139 {
140 mutt_str_copy(cac->pass, pass, sizeof(cac->pass));
141 }
143 {
144 /* The external command might interact with the screen */
145 if (!OptNoCurses)
147 return 0;
148 }
149 else if (OptNoCurses)
150 {
151 return -1;
152 }
153 else
154 {
155 char prompt[256] = { 0 };
156 snprintf(prompt, sizeof(prompt), _("Password for %s@%s: "),
157 (cac->flags & MUTT_ACCT_LOGIN) ? cac->login : cac->user, cac->host);
158 cac->pass[0] = '\0';
159
160 struct Buffer *buf = mutt_buffer_pool_get();
161 const int rc = mutt_buffer_get_field(prompt, buf, MUTT_COMP_PASS | MUTT_COMP_UNBUFFERED,
162 false, NULL, NULL, NULL);
163 mutt_str_copy(cac->pass, mutt_buffer_string(buf), sizeof(cac->pass));
165 if (rc != 0)
166 return -1;
167 }
168
169 cac->flags |= MUTT_ACCT_PASS;
170 return 0;
171}
172
178{
179 cac->flags &= ~MUTT_ACCT_PASS;
180 memset(cac->pass, 0, sizeof(cac->pass));
181}
182
195char *mutt_account_getoauthbearer(struct ConnAccount *cac, bool xoauth2)
196{
197 if (!cac || !cac->get_field)
198 return NULL;
199
200 /* The oauthbearer token includes the login */
201 if (mutt_account_getlogin(cac))
202 return NULL;
203
204 const char *cmd = cac->get_field(MUTT_CA_OAUTH_CMD, cac->gf_data);
205 if (!cmd)
206 {
207 /* L10N: You will see this error message if (1) you have "oauthbearer" in
208 one of your $*_authenticators and (2) you do not have the corresponding
209 $*_oauth_refresh_command defined. So the message does not mean "None of
210 your $*_oauth_refresh_command's are defined." */
211 mutt_error(_("No OAUTH refresh command defined"));
212 return NULL;
213 }
214
215 FILE *fp = NULL;
216 pid_t pid = filter_create(cmd, NULL, &fp, NULL);
217 if (pid < 0)
218 {
219 mutt_perror(_("Unable to run refresh command"));
220 return NULL;
221 }
222
223 size_t token_size = 0;
224 char *token = mutt_file_read_line(NULL, &token_size, fp, NULL, MUTT_RL_NO_FLAGS);
225 mutt_file_fclose(&fp);
226 filter_wait(pid);
227
228 /* The refresh cmd in some cases will invoke gpg to decrypt a token */
229 if (!OptNoCurses)
231
232 if (!token || (*token == '\0'))
233 {
234 mutt_error(_("Command returned empty string"));
235 FREE(&token);
236 return NULL;
237 }
238
239 if ((!xoauth2 && (token_size > 512)) || (xoauth2 && (token_size > 4096)))
240 {
241 mutt_error(_("OAUTH token is too big: %ld"), token_size);
242 FREE(&token);
243 return NULL;
244 }
245
246 /* 4500 is chosen to allow for both a token that is 4096-long plus a
247 * username that can be up to 320-long. */
248 char oauthbearer[4500] = { 0 };
249 int oalen = 0;
250 if (xoauth2)
251 {
252 oalen = snprintf(oauthbearer, sizeof(oauthbearer),
253 "user=%s\001auth=Bearer %s\001\001", cac->login, token);
254 }
255 else
256 {
257 oalen = snprintf(oauthbearer, sizeof(oauthbearer),
258 "n,a=%s,\001host=%s\001port=%d\001auth=Bearer %s\001\001",
259 cac->login, cac->host, cac->port, token);
260 }
261 FREE(&token);
262
263 size_t encoded_len = oalen * 4 / 3 + 10;
264 assert(encoded_len < 6010); // Assure LGTM that we won't overflow
265
266 char *encoded_token = mutt_mem_malloc(encoded_len);
267 mutt_b64_encode(oauthbearer, oalen, encoded_token, encoded_len);
268
269 return encoded_token;
270}
MuttAccountFlags mutt_account_call_external_cmd(struct ConnAccount *cac)
Retrieve account credentials via an external command.
Definition: accountcmd.c:163
Connection Credentials External Command.
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
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
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
void mutt_account_unsetpass(struct ConnAccount *cac)
Unset ConnAccount's password.
Definition: connaccount.c:177
char * mutt_account_getoauthbearer(struct ConnAccount *cac, bool xoauth2)
Get an OAUTHBEARER/XOAUTH2 token.
Definition: connaccount.c:195
int mutt_account_getlogin(struct ConnAccount *cac)
Retrieve login info into ConnAccount, if necessary.
Definition: connaccount.c:100
Connection Credentials.
@ MUTT_CA_OAUTH_CMD
OAuth refresh command.
Definition: connaccount.h:38
@ MUTT_CA_USER
User name.
Definition: connaccount.h:36
@ MUTT_CA_LOGIN
Login name.
Definition: connaccount.h:35
@ MUTT_CA_PASS
Password.
Definition: connaccount.h:37
#define MUTT_ACCT_NO_FLAGS
No flags are set.
Definition: connaccount.h:42
#define MUTT_ACCT_PASS
Password field has been set.
Definition: connaccount.h:46
#define MUTT_ACCT_USER
User field has been set.
Definition: connaccount.h:44
#define MUTT_ACCT_LOGIN
Login field has been set.
Definition: connaccount.h:45
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:162
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:720
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
Many unsorted constants and some structs.
#define MUTT_COMP_PASS
Password mode (no echo)
Definition: mutt.h:63
#define MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition: mutt.h:64
Hundreds of global variables to back the user variables.
char * Username
User's login name.
Definition: mutt_globals.h:52
Handling of global boolean variables.
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:53
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
Login details for a remote server.
Definition: connaccount.h:53
char login[128]
Login name.
Definition: connaccount.h:55
char user[128]
Username.
Definition: connaccount.h:56
char pass[256]
Password.
Definition: connaccount.h:57
char host[128]
Server to login to.
Definition: connaccount.h:54
const char *(* get_field)(enum ConnAccountField field, void *gf_data)
Function to get some login credentials.
Definition: connaccount.h:68
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:60
void * gf_data
Private data to pass to get_field()
Definition: connaccount.h:70
unsigned short port
Port to connect to.
Definition: connaccount.h:58