NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
auth.c File Reference

POP authentication. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "adata.h"
+ Include dependency graph for auth.c:

Go to the source code of this file.

Functions

void pop_apop_timestamp (struct PopAccountData *adata, char *buf)
 Get the server timestamp for APOP authentication.
 
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()
 
bool pop_auth_is_valid (const char *authenticator)
 Check if string is a valid pop authentication method.
 
int pop_authenticate (struct PopAccountData *adata)
 Authenticate with a POP server.
 

Variables

static const struct PopAuth PopAuthenticators []
 Accepted authentication methods.
 

Detailed Description

POP authentication.

Authors
  • Vsevolod Volkov
  • Richard Russon

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.c.

Function Documentation

◆ pop_apop_timestamp()

void pop_apop_timestamp ( struct PopAccountData adata,
char *  buf 
)

Get the server timestamp for APOP authentication.

Parameters
adataPOP Account data
bufTimestamp string

Definition at line 299 of file auth.c.

300{
301 char *p1 = NULL, *p2 = NULL;
302
303 FREE(&adata->timestamp);
304
305 if ((p1 = strchr(buf, '<')) && (p2 = strchr(p1, '>')))
306 {
307 p2[1] = '\0';
308 adata->timestamp = mutt_str_dup(p1);
309 }
310}
#define FREE(x)
Definition: memory.h:45
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
char * timestamp
Definition: adata.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pop_auth_apop()

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

APOP authenticator - Implements PopAuth::authenticate()

Definition at line 315 of file auth.c.

316{
317 struct Md5Ctx md5ctx = { 0 };
318 unsigned char digest[16];
319 char hash[33] = { 0 };
320 char buf[1024] = { 0 };
321
322 if (mutt_account_getpass(&adata->conn->account) || !adata->conn->account.pass[0])
323 return POP_A_FAILURE;
324
325 if (!adata->timestamp)
326 return POP_A_UNAVAIL;
327
328 if (!mutt_addr_valid_msgid(adata->timestamp))
329 {
330 mutt_error(_("POP timestamp is invalid"));
331 return POP_A_UNAVAIL;
332 }
333
334 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
335 mutt_message(_("Authenticating (%s)..."), "APOP");
336
337 /* Compute the authentication hash to send to the server */
338 mutt_md5_init_ctx(&md5ctx);
339 mutt_md5_process(adata->timestamp, &md5ctx);
340 mutt_md5_process(adata->conn->account.pass, &md5ctx);
341 mutt_md5_finish_ctx(&md5ctx, digest);
342 mutt_md5_toascii(digest, hash);
343
344 /* Send APOP command to server */
345 snprintf(buf, sizeof(buf), "APOP %s %s\r\n", adata->conn->account.user, hash);
346
347 switch (pop_query(adata, buf, sizeof(buf)))
348 {
349 case 0:
350 return POP_A_SUCCESS;
351 case -1:
352 return POP_A_SOCKET;
353 }
354
355 // L10N: %s is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
356 mutt_error(_("%s authentication failed"), "APOP");
357
358 return POP_A_FAILURE;
359}
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition: address.c:789
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:129
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
void mutt_md5_process(const char *str, struct Md5Ctx *md5ctx)
Process a NULL-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
@ POP_A_UNAVAIL
No valid authentication method.
Definition: private.h:62
@ POP_A_SUCCESS
Authenticated successfully.
Definition: private.h:59
@ POP_A_FAILURE
Authentication failed.
Definition: private.h:61
@ POP_A_SOCKET
Connection lost.
Definition: private.h:60
#define pop_query(adata, buf, buflen)
Definition: private.h:109
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
Cursor for the MD5 hashing.
Definition: md5.h:37
struct Connection * conn
Connection to POP server.
Definition: adata.h:38
+ Here is the call graph for this function:

◆ pop_auth_user()

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

USER authenticator - Implements PopAuth::authenticate()

Definition at line 364 of file auth.c.

365{
366 if (!adata->cmd_user)
367 return POP_A_UNAVAIL;
368
369 if (mutt_account_getpass(&adata->conn->account) || !adata->conn->account.pass[0])
370 return POP_A_FAILURE;
371
372 mutt_message(_("Logging in..."));
373
374 char buf[1024] = { 0 };
375 snprintf(buf, sizeof(buf), "USER %s\r\n", adata->conn->account.user);
376 int rc = pop_query(adata, buf, sizeof(buf));
377
378 if (adata->cmd_user == 2)
379 {
380 if (rc == 0)
381 {
382 adata->cmd_user = 1;
383
384 mutt_debug(LL_DEBUG1, "set USER capability\n");
385 }
386
387 if (rc == -2)
388 {
389 adata->cmd_user = 0;
390
391 mutt_debug(LL_DEBUG1, "unset USER capability\n");
392 snprintf(adata->err_msg, sizeof(adata->err_msg), "%s",
393 _("Command USER is not supported by server"));
394 }
395 }
396
397 if (rc == 0)
398 {
399 snprintf(buf, sizeof(buf), "PASS %s\r\n", adata->conn->account.pass);
400 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
401 rc = pop_query_d(adata, buf, sizeof(buf),
402 /* don't print the password unless we're at the ungodly debugging level */
403 (c_debug_level < MUTT_SOCK_LOG_FULL) ? "PASS *\r\n" : NULL);
404 }
405
406 switch (rc)
407 {
408 case 0:
409 return POP_A_SUCCESS;
410 case -1:
411 return POP_A_SOCKET;
412 }
413
414 mutt_error("%s %s", _("Login failed"), adata->err_msg);
415
416 return POP_A_FAILURE;
417}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
int pop_query_d(struct PopAccountData *adata, char *buf, size_t buflen, char *msg)
Send data from buffer and receive answer to the same buffer.
Definition: lib.c:465
#define MUTT_SOCK_LOG_FULL
Definition: socket.h:56
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
char err_msg[POP_CMD_RESPONSE]
Definition: adata.h:56
unsigned int cmd_user
optional command USER
Definition: adata.h:44
+ Here is the call graph for this function:

◆ pop_auth_oauth()

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

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

Definition at line 422 of file auth.c.

423{
424 /* If they did not explicitly request or configure oauth then fail quietly */
425 const char *const c_pop_oauth_refresh_command = cs_subset_string(NeoMutt->sub, "pop_oauth_refresh_command");
426 if (!method && !c_pop_oauth_refresh_command)
427 return POP_A_UNAVAIL;
428
429 // L10N: (%s) is the method name, e.g. Anonymous, CRAM-MD5, GSSAPI, SASL
430 mutt_message(_("Authenticating (%s)..."), "OAUTHBEARER");
431
432 char *oauthbearer = mutt_account_getoauthbearer(&adata->conn->account, false);
433 if (!oauthbearer)
434 return POP_A_FAILURE;
435
436 char *auth_cmd = NULL;
437 mutt_str_asprintf(&auth_cmd, "AUTH OAUTHBEARER %s\r\n", oauthbearer);
438 FREE(&oauthbearer);
439
440 int rc = pop_query_d(adata, auth_cmd, strlen(auth_cmd),
441#ifdef DEBUG
442 /* don't print the bearer token unless we're at the ungodly debugging level */
443 (cs_subset_number(NeoMutt->sub, "debug_level") < MUTT_SOCK_LOG_FULL) ?
444 "AUTH OAUTHBEARER *\r\n" :
445#endif
446 NULL);
447 FREE(&auth_cmd);
448
449 switch (rc)
450 {
451 case 0:
452 return POP_A_SUCCESS;
453 case -1:
454 return POP_A_SOCKET;
455 }
456
457 /* The error response was a SASL continuation, so "continue" it.
458 * See RFC7628 3.2.3 */
459 mutt_socket_send(adata->conn, "\001");
460
461 char *err = adata->err_msg;
462 char decoded_err[1024] = { 0 };
463 int len = mutt_b64_decode(adata->err_msg, decoded_err, sizeof(decoded_err) - 1);
464 if (len >= 0)
465 {
466 decoded_err[len] = '\0';
467 err = decoded_err;
468 }
469 mutt_error("%s %s", _("Authentication failed"), err);
470
471 return POP_A_FAILURE;
472}
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:136
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
char * mutt_account_getoauthbearer(struct ConnAccount *cac, bool xoauth2)
Get an OAUTHBEARER/XOAUTH2 token.
Definition: connaccount.c:194
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1022
#define mutt_socket_send(conn, buf)
Definition: socket.h:59
+ Here is the call graph for this function:

◆ pop_auth_is_valid()

bool pop_auth_is_valid ( const char *  authenticator)

Check if string is a valid pop authentication method.

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

Validate whether an input string is an accepted pop authentication method as defined by PopAuthenticators.

Definition at line 500 of file auth.c.

501{
502 for (size_t i = 0; i < mutt_array_size(PopAuthenticators); i++)
503 {
504 const struct PopAuth *auth = &PopAuthenticators[i];
505 if (auth->method && mutt_istr_equal(auth->method, authenticator))
506 return true;
507 }
508
509 return false;
510}
#define mutt_array_size(x)
Definition: memory.h:38
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
static const struct PopAuth PopAuthenticators[]
Accepted authentication methods.
Definition: auth.c:477
POP authentication multiplexor.
Definition: private.h:78
const char * method
Name of authentication method supported, NULL means variable.
Definition: private.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pop_authenticate()

int pop_authenticate ( struct PopAccountData adata)

Authenticate with a POP server.

Parameters
adataPOP Account data
Return values
numResult, e.g. POP_A_SUCCESS
0Successful
-1Connection lost
-2Login failed
-3Authentication cancelled

Definition at line 521 of file auth.c.

522{
523 struct ConnAccount *cac = &adata->conn->account;
524 const struct PopAuth *authenticator = NULL;
525 int attempts = 0;
526 int rc = POP_A_UNAVAIL;
527
528 if ((mutt_account_getuser(cac) < 0) || (cac->user[0] == '\0'))
529 {
530 return -3;
531 }
532
533 const struct Slist *c_pop_authenticators = cs_subset_slist(NeoMutt->sub, "pop_authenticators");
534 const bool c_pop_auth_try_all = cs_subset_bool(NeoMutt->sub, "pop_auth_try_all");
535 if (c_pop_authenticators && (c_pop_authenticators->count > 0))
536 {
537 /* Try user-specified list of authentication methods */
538 struct ListNode *np = NULL;
539 STAILQ_FOREACH(np, &c_pop_authenticators->head, entries)
540 {
541 mutt_debug(LL_DEBUG2, "Trying method %s\n", np->data);
542 authenticator = PopAuthenticators;
543
544 while (authenticator->authenticate)
545 {
546 if (!authenticator->method || mutt_istr_equal(authenticator->method, np->data))
547 {
548 rc = authenticator->authenticate(adata, np->data);
549 if (rc == POP_A_SOCKET)
550 {
551 switch (pop_connect(adata))
552 {
553 case 0:
554 {
555 rc = authenticator->authenticate(adata, np->data);
556 break;
557 }
558 case -2:
559 rc = POP_A_FAILURE;
560 }
561 }
562
563 if (rc != POP_A_UNAVAIL)
564 attempts++;
565 if ((rc == POP_A_SUCCESS) || (rc == POP_A_SOCKET) ||
566 ((rc == POP_A_FAILURE) && !c_pop_auth_try_all))
567 {
568 break;
569 }
570 }
571 authenticator++;
572 }
573 }
574 }
575 else
576 {
577 /* Fall back to default: any authenticator */
578 mutt_debug(LL_DEBUG2, "Using any available method\n");
579 authenticator = PopAuthenticators;
580
581 while (authenticator->authenticate)
582 {
583 rc = authenticator->authenticate(adata, NULL);
584 if (rc == POP_A_SOCKET)
585 {
586 switch (pop_connect(adata))
587 {
588 case 0:
589 {
590 rc = authenticator->authenticate(adata, NULL);
591 break;
592 }
593 case -2:
594 rc = POP_A_FAILURE;
595 }
596 }
597
598 if (rc != POP_A_UNAVAIL)
599 attempts++;
600 if ((rc == POP_A_SUCCESS) || (rc == POP_A_SOCKET) ||
601 ((rc == POP_A_FAILURE) && !c_pop_auth_try_all))
602 {
603 break;
604 }
605
606 authenticator++;
607 }
608 }
609
610 switch (rc)
611 {
612 case POP_A_SUCCESS:
613 return 0;
614 case POP_A_SOCKET:
615 return -1;
616 case POP_A_UNAVAIL:
617 if (attempts == 0)
618 mutt_error(_("No authenticators available"));
619 }
620
621 return -2;
622}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:243
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:50
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
int pop_connect(struct PopAccountData *adata)
Open connection.
Definition: lib.c:281
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
Login details for a remote server.
Definition: connaccount.h:53
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
enum PopAuthRes(* authenticate)(struct PopAccountData *adata, const char *method)
Authenticate a POP connection.
Definition: private.h:85
String list.
Definition: slist.h:47
struct ListHead head
List containing values.
Definition: slist.h:48
size_t count
Number of values in list.
Definition: slist.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ PopAuthenticators

const struct PopAuth PopAuthenticators[]
static
Initial value:
= {
{ pop_auth_oauth, "oauthbearer" },
{ pop_auth_apop, "apop" },
{ pop_auth_user, "user" },
{ NULL, NULL },
}
static enum PopAuthRes pop_auth_user(struct PopAccountData *adata, const char *method)
USER authenticator - Implements PopAuth::authenticate()
Definition: auth.c:364
static enum PopAuthRes pop_auth_apop(struct PopAccountData *adata, const char *method)
APOP authenticator - Implements PopAuth::authenticate()
Definition: auth.c:315
static enum PopAuthRes pop_auth_oauth(struct PopAccountData *adata, const char *method)
Authenticate a POP connection using OAUTHBEARER - Implements PopAuth::authenticate()
Definition: auth.c:422

Accepted authentication methods.

Definition at line 477 of file auth.c.