NeoMutt  2025-12-11-1039-g550ac6
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
POP Authentication API

Authenticate a POP connection. More...

Functions

static enum PopAuthRes pop_auth_apop (struct PopAccountData *adata, const char *method)
 APOP authenticator - Implements PopAuth::authenticate() -.
static enum PopAuthRes pop_auth_user (struct PopAccountData *adata, const char *method)
 USER authenticator - Implements PopAuth::authenticate() -.
static enum PopAuthRes pop_auth_oauth (struct PopAccountData *adata, const char *method)
 Authenticate a POP connection using OAUTHBEARER - Implements PopAuth::authenticate() -.

Detailed Description

Authenticate a POP connection.

Parameters
adataPOP Account data
methodName of this authentication method (UNUSED)
Return values
enumPopAuthRes, e.g. POP_A_SUCCESS

Function Documentation

◆ pop_auth_apop()

enum PopAuthRes pop_auth_apop ( struct PopAccountData * adata,
const char * method )
static

APOP authenticator - Implements PopAuth::authenticate() -.

Definition at line 343 of file auth.c.

344{
345 struct Md5Ctx md5ctx = { 0 };
346 unsigned char digest[16] = { 0 };
347 char hash[33] = { 0 };
348 char buf[1024] = { 0 };
349
350 if (mutt_account_getpass(&adata->conn->account) || !adata->conn->account.pass[0])
351 return POP_A_FAILURE;
352
353 if (!adata->timestamp)
354 return POP_A_UNAVAIL;
355
356 if (!mutt_addr_valid_msgid(adata->timestamp))
357 {
358 mutt_error(_("POP timestamp is invalid"));
359 return POP_A_UNAVAIL;
360 }
361
362 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
363 mutt_message(_("Authenticating (%s)..."), "APOP");
364
365 /* Compute the authentication hash to send to the server */
366 mutt_md5_init_ctx(&md5ctx);
367 mutt_md5_process(adata->timestamp, &md5ctx);
368 mutt_md5_process(adata->conn->account.pass, &md5ctx);
369 mutt_md5_finish_ctx(&md5ctx, digest);
370 mutt_md5_toascii(digest, hash);
371
372 /* Send APOP command to server */
373 snprintf(buf, sizeof(buf), "APOP %s %s\r\n", adata->conn->account.user, hash);
374
375 switch (pop_query(adata, buf, sizeof(buf), NULL))
376 {
377 case 0:
378 return POP_A_SUCCESS;
379 case -1:
380 return POP_A_SOCKET;
381 default:
382 break;
383 }
384
385 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
386 mutt_error(_("%s authentication failed"), "APOP");
387
388 return POP_A_FAILURE;
389}
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition address.c:803
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
void mutt_md5_process(const char *str, struct Md5Ctx *md5ctx)
Process a NUL-terminated string.
Definition md5.c:355
void mutt_md5_init_ctx(struct Md5Ctx *md5ctx)
Initialise the MD5 computation.
Definition md5.c:261
void * mutt_md5_finish_ctx(struct Md5Ctx *md5ctx, void *resbuf)
Process the remaining bytes in the buffer.
Definition md5.c:285
void mutt_md5_toascii(const void *digest, char *resbuf)
Convert a binary MD5 digest into ASCII Hexadecimal.
Definition md5.c:456
#define _(a)
Definition message.h:28
int pop_query(struct PopAccountData *adata, char *buf, size_t buflen, char *msg)
Send data from buffer and receive answer to the same buffer.
Definition lib.c:467
@ POP_A_UNAVAIL
No valid authentication method.
Definition private.h:60
@ POP_A_SUCCESS
Authenticated successfully.
Definition private.h:57
@ POP_A_FAILURE
Authentication failed.
Definition private.h:59
@ POP_A_SOCKET
Connection lost.
Definition private.h:58
char user[128]
Username.
Definition connaccount.h:62
char pass[256]
Password.
Definition connaccount.h:63
struct ConnAccount account
Account details: username, password, etc.
Definition connection.h:49
Cursor for the MD5 hashing.
Definition md5.h:37
struct Connection * conn
Connection to POP server.
Definition adata.h:38
char * timestamp
APOP timestamp.
Definition adata.h:55
Here is the call graph for this function:

◆ pop_auth_user()

enum PopAuthRes pop_auth_user ( struct PopAccountData * adata,
const char * method )
static

USER authenticator - Implements PopAuth::authenticate() -.

Definition at line 394 of file auth.c.

395{
396 if (!adata->cmd_user)
397 return POP_A_UNAVAIL;
398
399 if (mutt_account_getpass(&adata->conn->account) || !adata->conn->account.pass[0])
400 return POP_A_FAILURE;
401
402 mutt_message(_("Logging in..."));
403
404 char buf[1024] = { 0 };
405 snprintf(buf, sizeof(buf), "USER %s\r\n", adata->conn->account.user);
406 int rc = pop_query(adata, buf, sizeof(buf), NULL);
407
408 if (adata->cmd_user == 2)
409 {
410 if (rc == 0)
411 {
412 adata->cmd_user = 1;
413
414 mutt_debug(LL_DEBUG1, "set USER capability\n");
415 }
416
417 if (rc == -2)
418 {
419 adata->cmd_user = 0;
420
421 mutt_debug(LL_DEBUG1, "unset USER capability\n");
422 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
423 _("Command USER is not supported by server"));
424 }
425 }
426
427 if (rc == 0)
428 {
429 snprintf(buf, sizeof(buf), "PASS %s\r\n", adata->conn->account.pass);
430 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
431 rc = pop_query(adata, buf, sizeof(buf),
432 /* don't print the password unless we're at the ungodly debugging level */
433 (c_debug_level < MUTT_SOCK_LOG_FULL) ? "PASS *\r\n" : NULL);
434 }
435
436 switch (rc)
437 {
438 case 0:
439 return POP_A_SUCCESS;
440 case -1:
441 return POP_A_SOCKET;
442 default:
443 break;
444 }
445
446 mutt_error("%s %s", _("Login failed"), adata->err_msg);
447
448 return POP_A_FAILURE;
449}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define MUTT_SOCK_LOG_FULL
Log everything including full protocol.
Definition socket.h:53
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
char err_msg[POP_CMD_RESPONSE]
Last error message.
Definition adata.h:57
unsigned int cmd_user
optional command USER
Definition adata.h:44
Here is the call graph for this function:

◆ pop_auth_oauth()

enum PopAuthRes pop_auth_oauth ( struct PopAccountData * adata,
const char * method )
static

Authenticate a POP connection using OAUTHBEARER - Implements PopAuth::authenticate() -.

Definition at line 454 of file auth.c.

455{
456 /* If they did not explicitly request or configure oauth then fail quietly */
457 const char *const c_pop_oauth_refresh_command = cs_subset_string(NeoMutt->sub, "pop_oauth_refresh_command");
458 if (!method && !c_pop_oauth_refresh_command)
459 return POP_A_UNAVAIL;
460
461 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
462 mutt_message(_("Authenticating (%s)..."), "OAUTHBEARER");
463
464 char *oauthbearer = mutt_account_getoauthbearer(&adata->conn->account, false);
465 if (!oauthbearer)
466 return POP_A_FAILURE;
467
468 char *auth_cmd = NULL;
469 mutt_str_asprintf(&auth_cmd, "AUTH OAUTHBEARER %s\r\n", oauthbearer);
470 FREE(&oauthbearer);
471
472 int rc = pop_query(adata, auth_cmd, strlen(auth_cmd),
473#ifdef DEBUG
474 /* don't print the bearer token unless we're at the ungodly debugging level */
475 (cs_subset_number(NeoMutt->sub, "debug_level") < MUTT_SOCK_LOG_FULL) ?
476 "AUTH OAUTHBEARER *\r\n" :
477#endif
478 NULL);
479 FREE(&auth_cmd);
480
481 switch (rc)
482 {
483 case 0:
484 return POP_A_SUCCESS;
485 case -1:
486 return POP_A_SOCKET;
487 default:
488 break;
489 }
490
491 /* The error response was a SASL continuation, so "continue" it.
492 * See RFC7628 3.2.3 */
493 mutt_socket_send(adata->conn, "\001");
494
495 char *err = adata->err_msg;
496 char decoded_err[1024] = { 0 };
497 int len = mutt_b64_decode(adata->err_msg, decoded_err, sizeof(decoded_err) - 1);
498 if (len >= 0)
499 {
500 decoded_err[len] = '\0';
501 err = decoded_err;
502 }
503 mutt_error("%s %s", _("Authentication failed"), err);
504
505 return POP_A_FAILURE;
506}
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert NUL-terminated base64 string to raw bytes.
Definition base64.c:180
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
char * mutt_account_getoauthbearer(struct ConnAccount *cac, bool xoauth2)
Get an OAUTHBEARER/XOAUTH2 token.
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:809
#define mutt_socket_send(conn, buf)
Definition socket.h:56
Here is the call graph for this function: