Projects STRLCPY neomutt Commits faafb1c8
🤬
  • Add GNU SASL support for authentication

    add support for the GNU SASL library, using configure option --gsasl
    
    Add multiline response support for SMTP authentication (which is
    probably not actually needed).  Also add arbitrary line length for the
    SASL server responses (the RFCs note that for SASL, the protocol line
    lengths don't apply).
    
    Upstream-commit: https://gitlab.com/muttmua/mutt/commit/68caf9140c8217ecf6c848460c4b4d27996b2922
  • Loading...
  • Richard Russon committed 2 years ago
    faafb1c8
    1 parent 9c456f52
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■
    .github/workflows/build-and-test.yml
    skipped 21 lines
    22 22   - name: default
    23 23   options:
    24 24   - name: disabled
    25  - options: --disable-idn --disable-nls --disable-pgp --disable-smime --ssl
     25 + options: --disable-idn --disable-nls --disable-pgp --disable-smime --ssl --gsasl
    26 26   - name: everything
    27 27   options: --autocrypt --bdb --disable-idn --fmemopen --gdbm --gnutls --gpgme --gss --idn2 --kyotocabinet --lmdb --lua --lz4 --mixmaster --notmuch --pcre2 --qdbm --rocksdb --sasl --tdb --tokyocabinet --with-lock=fcntl --zlib --zstd
    28 28   
    skipped 39 lines
  • ■ ■ ■ ■
    .github/workflows/centos.yml
    skipped 18 lines
    19 19   - name: Default
    20 20   options:
    21 21   - name: Minimal
    22  - options: --disable-idn --disable-nls --disable-pgp --disable-smime --ssl --with-lock=flock
     22 + options: --disable-idn --disable-nls --disable-pgp --disable-smime --ssl --gsasl --with-lock=flock
    23 23   - name: Everything
    24 24   options: --bdb --full-doc --gnutls --gpgme --gss --lz4 --pcre2 --sasl --tdb --tokyocabinet --with-lock=fcntl --zlib
    25 25   options8: --autocrypt --disable-idn --gdbm --idn2 --lua --notmuch --zstd
    skipped 50 lines
  • ■ ■ ■ ■
    .github/workflows/fedora.yml
    skipped 19 lines
    20 20   - name: Default
    21 21   options:
    22 22   - name: Minimal
    23  - options: --disable-idn --disable-nls --disable-pgp --disable-smime --ssl --with-lock=flock
     23 + options: --disable-idn --disable-nls --disable-pgp --disable-smime --ssl --gsasl --with-lock=flock
    24 24   - name: Everything
    25 25   options: --autocrypt --bdb --disable-idn --full-doc --gdbm --gnutls --gpgme --gss --idn2 --lmdb --lua --lz4 --notmuch --pcre2 --qdbm --sasl --tdb --tokyocabinet --with-lock=fcntl --zlib --zstd
    26 26   
    skipped 37 lines
  • ■ ■ ■ ■ ■
    Makefile.autosetup
    skipped 283 lines
    284 284  LIBCONNOBJS= conn/accountcmd.o conn/config.o conn/connaccount.o \
    285 285   conn/getdomain.o conn/raw.o conn/sasl_plain.o conn/socket.o \
    286 286   conn/tunnel.o
    287  -@if HAVE_SASL
     287 +@if USE_SASL_GNU
     288 +LIBCONNOBJS+= conn/gsasl.o
     289 +@endif
     290 +@if USE_SASL_CYRUS
    288 291  LIBCONNOBJS+= conn/sasl.o
    289 292  @endif
    290 293  @if USE_SSL
    skipped 188 lines
    479 482  @if USE_GSS
    480 483  LIBIMAPOBJS+= imap/auth_gss.o
    481 484  @endif
    482  -@if HAVE_SASL
     485 +@if USE_SASL_CYRUS
    483 486  LIBIMAPOBJS+= imap/auth_sasl.o
    484  -@else
     487 +@endif
     488 +@if USE_SASL_GNU
     489 +LIBIMAPOBJS+= imap/auth_gsasl.o
     490 +@endif
     491 +@if !HAVE_SASL
    485 492  LIBIMAPOBJS+= imap/auth_anon.o imap/auth_cram.o
    486 493  @endif
    487 494  CLEANFILES+= $(LIBIMAP) $(LIBIMAPOBJS)
    skipped 461 lines
  • ■ ■ ■ ■ ■ ■
    auto.def
    skipped 56 lines
    57 57   gss=0 => "Use GSSAPI authentication for IMAP"
    58 58   with-gss:path => "Location of GSSAPI library"
    59 59   # SASL (IMAP and POP auth)
     60 + gsasl=0 => "Use the GNU SASL network security library"
     61 + with-gsasl:path => "Location of the GNU SASL network security library"
    60 62   sasl=0 => "Use the SASL network security library"
    61 63   with-sasl:path => "Location of the SASL network security library"
    62 64   # AutoCrypt
    skipped 91 lines
    154 156   foreach opt {
    155 157   asan autocrypt bdb coverage debug-backtrace debug-color debug-email
    156 158   debug-graphviz debug-notify debug-parse-test debug-queue debug-window doc
    157  - everything fmemopen full-doc fuzzing gdbm gnutls gpgme gss homespool idn
     159 + everything fmemopen full-doc fuzzing gdbm gnutls gpgme gsasl gss homespool idn
    158 160   idn2 include-path-in-cflags inotify kyotocabinet lmdb locales-fix lua lz4
    159 161   mixmaster nls notmuch pcre2 pgp pkgconf qdbm rocksdb sasl smime sqlite ssl
    160 162   testing tdb tokyocabinet zlib zstd
    skipped 5 lines
    166 168   # relative --enable-opt to true. This allows "--with-opt=/usr" to be used as
    167 169   # a shortcut for "--opt --with-opt=/usr".
    168 170   foreach opt {
    169  - bdb gdbm gnutls gpgme gss homespool idn idn2 kyotocabinet lmdb lua lz4
     171 + bdb gdbm gnutls gpgme gsasl gss homespool idn idn2 kyotocabinet lmdb lua lz4
    170 172   mixmaster nls notmuch pcre2 qdbm rocksdb sasl sqlite ssl tdb tokyocabinet
    171 173   zlib zstd
    172 174   } {
    skipped 412 lines
    585 587  if {[get-define want-smime]} {
    586 588   define-feature SMIME
    587 589   define CRYPT_BACKEND_CLASSIC_SMIME
     590 +}
     591 + 
     592 +###############################################################################
     593 +# GNU SASL
     594 +if {[get-define want-gsasl] && [get-define want-sasl]} {
     595 + user-error "Cannot specify both --gsasl and --sasl"
     596 +}
     597 +if {[get-define want-gsasl]} {
     598 + if {[get-define want-pkgconf]} {
     599 + pkgconf true libgsasl
     600 + define USE_SASL_GNU
     601 + define-feature SASL
     602 + } else {
     603 + if {[check-inc-and-lib gsasl [opt-val with-gsasl $prefix] \
     604 + gsasl.h gsasl_init gsasl]} {
     605 + define USE_SASL_GNU
     606 + } else {
     607 + user-error "Unable to find GNU SASL"
     608 + }
     609 + }
    588 610  }
    589 611   
    590 612  ###############################################################################
    skipped 808 lines
  • ■ ■ ■ ■ ■ ■
    conn/gsasl.c
     1 +/**
     2 + * @file
     3 + * GNU SASL authentication support
     4 + *
     5 + * @authors
     6 + * Copyright (C) 2022 Richard Russon <[email protected]>
     7 + *
     8 + * @copyright
     9 + * This program is free software: you can redistribute it and/or modify it under
     10 + * the terms of the GNU General Public License as published by the Free Software
     11 + * Foundation, either version 2 of the License, or (at your option) any later
     12 + * version.
     13 + *
     14 + * This program is distributed in the hope that it will be useful, but WITHOUT
     15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
     17 + * details.
     18 + *
     19 + * You should have received a copy of the GNU General Public License along with
     20 + * this program. If not, see <http://www.gnu.org/licenses/>.
     21 + */
     22 + 
     23 +/**
     24 + * @page conn_gsasl GNU SASL authentication support
     25 + *
     26 + * GNU SASL authentication support
     27 + */
     28 + 
     29 +#include "config.h"
     30 +#include <gsasl.h>
     31 +#include <stdbool.h>
     32 +#include <string.h>
     33 +#include "mutt/lib.h"
     34 +#include "connaccount.h"
     35 +#include "connection.h"
     36 +#include "gsasl2.h"
     37 +#include "mutt_account.h"
     38 + 
     39 +static Gsasl *mutt_gsasl_ctx = NULL;
     40 + 
     41 +/**
     42 + * mutt_gsasl_callback - Callback to retrieve authname or user from ConnAccount
     43 + * @param ctx GNU SASL context
     44 + * @param sctx GNU SASL session
     45 + * @param prop Property to get, e.g. GSASL_PASSWORD
     46 + * @retval num GNU SASL error code, e.g. GSASL_OK
     47 + */
     48 +static int mutt_gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
     49 +{
     50 + int rc = GSASL_NO_CALLBACK;
     51 + 
     52 + struct Connection *conn = gsasl_session_hook_get(sctx);
     53 + if (!conn)
     54 + {
     55 + mutt_debug(LL_DEBUG1, "missing session hook data!\n");
     56 + return rc;
     57 + }
     58 + 
     59 + switch (prop)
     60 + {
     61 + case GSASL_PASSWORD:
     62 + if (mutt_account_getpass(&conn->account))
     63 + return rc;
     64 + gsasl_property_set(sctx, GSASL_PASSWORD, conn->account.pass);
     65 + rc = GSASL_OK;
     66 + break;
     67 + 
     68 + case GSASL_AUTHID:
     69 + /* whom the provided password belongs to: login */
     70 + if (mutt_account_getlogin(&conn->account))
     71 + return rc;
     72 + gsasl_property_set(sctx, GSASL_AUTHID, conn->account.login);
     73 + rc = GSASL_OK;
     74 + break;
     75 + 
     76 + case GSASL_AUTHZID:
     77 + /* name of the user whose mail/resources you intend to access: user */
     78 + if (mutt_account_getuser(&conn->account))
     79 + return rc;
     80 + gsasl_property_set(sctx, GSASL_AUTHZID, conn->account.user);
     81 + rc = GSASL_OK;
     82 + break;
     83 + 
     84 + case GSASL_ANONYMOUS_TOKEN:
     85 + gsasl_property_set(sctx, GSASL_ANONYMOUS_TOKEN, "dummy");
     86 + rc = GSASL_OK;
     87 + break;
     88 + 
     89 + case GSASL_SERVICE:
     90 + {
     91 + const char *service = NULL;
     92 + switch (conn->account.type)
     93 + {
     94 + case MUTT_ACCT_TYPE_IMAP:
     95 + service = "imap";
     96 + break;
     97 + case MUTT_ACCT_TYPE_POP:
     98 + service = "pop";
     99 + break;
     100 + case MUTT_ACCT_TYPE_SMTP:
     101 + service = "smtp";
     102 + break;
     103 + default:
     104 + return rc;
     105 + }
     106 + gsasl_property_set(sctx, GSASL_SERVICE, service);
     107 + rc = GSASL_OK;
     108 + break;
     109 + }
     110 + 
     111 + case GSASL_HOSTNAME:
     112 + gsasl_property_set(sctx, GSASL_HOSTNAME, conn->account.host);
     113 + rc = GSASL_OK;
     114 + break;
     115 + 
     116 + default:
     117 + break;
     118 + }
     119 + 
     120 + return rc;
     121 +}
     122 + 
     123 +/**
     124 + * mutt_gsasl_init - Initialise GNU SASL library
     125 + * @retval true Success
     126 + */
     127 +static bool mutt_gsasl_init(void)
     128 +{
     129 + if (mutt_gsasl_ctx)
     130 + return true;
     131 + 
     132 + int rc = gsasl_init(&mutt_gsasl_ctx);
     133 + if (rc != GSASL_OK)
     134 + {
     135 + mutt_gsasl_ctx = NULL;
     136 + mutt_debug(LL_DEBUG1, "libgsasl initialisation failed (%d): %s.\n", rc,
     137 + gsasl_strerror(rc));
     138 + return false;
     139 + }
     140 + 
     141 + gsasl_callback_set(mutt_gsasl_ctx, mutt_gsasl_callback);
     142 + return true;
     143 +}
     144 + 
     145 +/**
     146 + * mutt_gsasl_done - Shutdown GNU SASL library
     147 + */
     148 +void mutt_gsasl_done(void)
     149 +{
     150 + if (!mutt_gsasl_ctx)
     151 + return;
     152 + 
     153 + gsasl_done(mutt_gsasl_ctx);
     154 + mutt_gsasl_ctx = NULL;
     155 +}
     156 + 
     157 +/**
     158 + * mutt_gsasl_get_mech - Pick a connection mechanism
     159 + * @param requested_mech Requested mechanism
     160 + * @param server_mechlist Server's list of mechanisms
     161 + * @retval ptr Selected mechanism string
     162 + */
     163 +const char *mutt_gsasl_get_mech(const char *requested_mech, const char *server_mechlist)
     164 +{
     165 + if (!mutt_gsasl_init())
     166 + return NULL;
     167 + 
     168 + /* libgsasl does not do case-independent string comparisons,
     169 + * and stores its methods internally in uppercase. */
     170 + char *uc_server_mechlist = mutt_str_dup(server_mechlist);
     171 + if (uc_server_mechlist)
     172 + mutt_str_upper(uc_server_mechlist);
     173 + 
     174 + char *uc_requested_mech = mutt_str_dup(requested_mech);
     175 + if (uc_requested_mech)
     176 + mutt_str_upper(uc_requested_mech);
     177 + 
     178 + const char *sel_mech = NULL;
     179 + if (uc_requested_mech)
     180 + sel_mech = gsasl_client_suggest_mechanism(mutt_gsasl_ctx, uc_requested_mech);
     181 + else
     182 + sel_mech = gsasl_client_suggest_mechanism(mutt_gsasl_ctx, uc_server_mechlist);
     183 + 
     184 + FREE(&uc_requested_mech);
     185 + FREE(&uc_server_mechlist);
     186 + 
     187 + return sel_mech;
     188 +}
     189 + 
     190 +/**
     191 + * mutt_gsasl_client_new - Create a new GNU SASL client
     192 + * @param conn Connection to a server
     193 + * @param mech Mechanisms to use
     194 + * @param sctx GNU SASL Session
     195 + * @retval 0 Success
     196 + * @retval -1 Error
     197 + */
     198 +int mutt_gsasl_client_new(struct Connection *conn, const char *mech, Gsasl_session **sctx)
     199 +{
     200 + if (!mutt_gsasl_init())
     201 + return -1;
     202 + 
     203 + int rc = gsasl_client_start(mutt_gsasl_ctx, mech, sctx);
     204 + if (rc != GSASL_OK)
     205 + {
     206 + *sctx = NULL;
     207 + mutt_debug(LL_DEBUG1, "gsasl_client_start failed (%d): %s.\n", rc, gsasl_strerror(rc));
     208 + return -1;
     209 + }
     210 + 
     211 + gsasl_session_hook_set(*sctx, conn);
     212 + return 0;
     213 +}
     214 + 
     215 +/**
     216 + * mutt_gsasl_client_finish - Free a GNU SASL client
     217 + * @param sctx GNU SASL Session
     218 + */
     219 +void mutt_gsasl_client_finish(Gsasl_session **sctx)
     220 +{
     221 + gsasl_finish(*sctx);
     222 + *sctx = NULL;
     223 +}
     224 + 
  • ■ ■ ■ ■ ■ ■
    conn/gsasl2.h
     1 +/**
     2 + * @file
     3 + * GNU SASL authentication support
     4 + *
     5 + * @authors
     6 + * Copyright (C) 2022 Richard Russon <[email protected]>
     7 + *
     8 + * @copyright
     9 + * This program is free software: you can redistribute it and/or modify it under
     10 + * the terms of the GNU General Public License as published by the Free Software
     11 + * Foundation, either version 2 of the License, or (at your option) any later
     12 + * version.
     13 + *
     14 + * This program is distributed in the hope that it will be useful, but WITHOUT
     15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
     17 + * details.
     18 + *
     19 + * You should have received a copy of the GNU General Public License along with
     20 + * this program. If not, see <http://www.gnu.org/licenses/>.
     21 + */
     22 + 
     23 +#ifndef MUTT_CONN_GSASL_H
     24 +#define MUTT_CONN_GSASL_H
     25 + 
     26 +#include <gsasl.h>
     27 + 
     28 +struct Connection;
     29 + 
     30 +void mutt_gsasl_client_finish(Gsasl_session **sctx);
     31 +int mutt_gsasl_client_new (struct Connection *conn, const char *mech, Gsasl_session **sctx);
     32 +void mutt_gsasl_done (void);
     33 +const char *mutt_gsasl_get_mech (const char *requested_mech, const char *server_mechlist);
     34 + 
     35 +#endif /* MUTT_CONN_GSASL_H */
     36 + 
  • ■ ■ ■ ■ ■ ■
    conn/lib.h
    skipped 32 lines
    33 33   * | conn/dlg_verifycert.c | @subpage conn_dlg_verifycert |
    34 34   * | conn/getdomain.c | @subpage conn_getdomain |
    35 35   * | conn/gnutls.c | @subpage conn_gnutls |
     36 + * | conn/gsasl.c | @subpage conn_gsasl |
    36 37   * | conn/openssl.c | @subpage conn_openssl |
    37 38   * | conn/raw.c | @subpage conn_raw |
    38 39   * | conn/sasl.c | @subpage conn_sasl |
    skipped 12 lines
    51 52  #include "connection.h"
    52 53  #include "sasl_plain.h"
    53 54  #include "socket.h"
     55 +#ifdef USE_SASL_GNU
     56 +#include "gsasl2.h"
     57 +#endif
    54 58  #ifdef USE_SASL_CYRUS
    55 59  #include "sasl.h"
    56 60  #endif
    skipped 15 lines
  • ■ ■ ■ ■ ■ ■
    conn/sasl.h
    skipped 19 lines
    20 20   * this program. If not, see <http://www.gnu.org/licenses/>.
    21 21   */
    22 22   
    23  -/* common SASL helper routines */
    24  - 
    25 23  #ifndef MUTT_CONN_SASL_H
    26 24  #define MUTT_CONN_SASL_H
    27 25   
    skipped 14 lines
  • ■ ■ ■ ■ ■
    imap/auth.c
    skipped 60 lines
    61 61   { imap_auth_oauth, "oauthbearer" },
    62 62   { imap_auth_xoauth2, "xoauth2" },
    63 63   { imap_auth_plain, "plain" },
    64  -#ifdef USE_SASL_CYRUS
     64 +#if defined(USE_SASL_CYRUS)
    65 65   { imap_auth_sasl, NULL },
     66 +#elif defined(USE_SASL_GNU)
     67 + { imap_auth_gsasl, NULL },
    66 68  #else
    67 69   { imap_auth_anon, "anonymous" },
    68 70  #endif
    skipped 85 lines
  • ■ ■ ■ ■ ■ ■
    imap/auth.h
    skipped 55 lines
    56 56  #ifdef USE_SASL_CYRUS
    57 57  enum ImapAuthRes imap_auth_sasl(struct ImapAccountData *adata, const char *method);
    58 58  #endif
     59 +#ifdef USE_SASL_GNU
     60 +enum ImapAuthRes imap_auth_gsasl(struct ImapAccountData *adata, const char *method);
     61 +#endif
    59 62  enum ImapAuthRes imap_auth_oauth(struct ImapAccountData *adata, const char *method);
    60 63  enum ImapAuthRes imap_auth_xoauth2(struct ImapAccountData *adata, const char *method);
    61 64   
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    imap/auth_gsasl.c
     1 +/**
     2 + * @file
     3 + * IMAP GNU SASL authentication method
     4 + *
     5 + * @authors
     6 + * Copyright (C) 2022 Richard Russon <[email protected]>
     7 + *
     8 + * @copyright
     9 + * This program is free software: you can redistribute it and/or modify it under
     10 + * the terms of the GNU General Public License as published by the Free Software
     11 + * Foundation, either version 2 of the License, or (at your option) any later
     12 + * version.
     13 + *
     14 + * This program is distributed in the hope that it will be useful, but WITHOUT
     15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
     17 + * details.
     18 + *
     19 + * You should have received a copy of the GNU General Public License along with
     20 + * this program. If not, see <http://www.gnu.org/licenses/>.
     21 + */
     22 + 
     23 +/**
     24 + * @page imap_auth_gsasl GNU SASL authentication
     25 + *
     26 + * IMAP GNU SASL authentication method
     27 + */
     28 + 
     29 +#include "config.h"
     30 +#include <stddef.h>
     31 +#include <gsasl.h>
     32 +#include "private.h"
     33 +#include "mutt/lib.h"
     34 +#include "conn/lib.h"
     35 +#include "adata.h"
     36 +#include "auth.h"
     37 + 
     38 +/**
     39 + * imap_auth_gsasl - GNU SASL authenticator - Implements ImapAuth::authenticate()
     40 + */
     41 +enum ImapAuthRes imap_auth_gsasl(struct ImapAccountData *adata, const char *method)
     42 +{
     43 + Gsasl_session *gsasl_session = NULL;
     44 + struct Buffer *output_buf = NULL;
     45 + char *imap_step_output = NULL;
     46 + int rc = IMAP_AUTH_FAILURE;
     47 + int gsasl_rc = GSASL_OK;
     48 + int imap_step_rc = IMAP_RES_CONTINUE;
     49 + 
     50 + const char *chosen_mech = mutt_gsasl_get_mech(method, adata->capstr);
     51 + if (!chosen_mech)
     52 + {
     53 + mutt_debug(LL_DEBUG2, "mutt_gsasl_get_mech() returned no usable mech\n");
     54 + return IMAP_AUTH_UNAVAIL;
     55 + }
     56 + 
     57 + mutt_debug(LL_DEBUG2, "using mech %s\n", chosen_mech);
     58 + 
     59 + if (mutt_gsasl_client_new(adata->conn, chosen_mech, &gsasl_session) < 0)
     60 + {
     61 + mutt_debug(LL_DEBUG1, "Error allocating GSASL connection.\n");
     62 + return IMAP_AUTH_UNAVAIL;
     63 + }
     64 + 
     65 + mutt_message(_("Authenticating (%s)..."), chosen_mech);
     66 + 
     67 + output_buf = mutt_buffer_pool_get();
     68 + mutt_buffer_printf(output_buf, "AUTHENTICATE %s", chosen_mech);
     69 + if (adata->capabilities & IMAP_CAP_SASL_IR)
     70 + {
     71 + char *gsasl_step_output = NULL;
     72 + gsasl_rc = gsasl_step64(gsasl_session, "", &gsasl_step_output);
     73 + if ((gsasl_rc != GSASL_NEEDS_MORE) && (gsasl_rc != GSASL_OK))
     74 + {
     75 + mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
     76 + gsasl_strerror(gsasl_rc));
     77 + rc = IMAP_AUTH_UNAVAIL;
     78 + goto bail;
     79 + }
     80 + 
     81 + mutt_buffer_addch(output_buf, ' ');
     82 + mutt_buffer_addstr(output_buf, gsasl_step_output);
     83 + gsasl_free(gsasl_step_output);
     84 + }
     85 + imap_cmd_start(adata, mutt_buffer_string(output_buf));
     86 + 
     87 + do
     88 + {
     89 + do
     90 + {
     91 + imap_step_rc = imap_cmd_step(adata);
     92 + } while (imap_step_rc == IMAP_RES_CONTINUE);
     93 + 
     94 + if ((imap_step_rc == IMAP_RES_BAD) || (imap_step_rc == IMAP_RES_NO))
     95 + goto bail;
     96 + 
     97 + if (imap_step_rc != IMAP_RES_RESPOND)
     98 + break;
     99 + 
     100 + imap_step_output = imap_next_word(adata->buf);
     101 + 
     102 + char *gsasl_step_output = NULL;
     103 + gsasl_rc = gsasl_step64(gsasl_session, imap_step_output, &gsasl_step_output);
     104 + if ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK))
     105 + {
     106 + mutt_buffer_strcpy(output_buf, gsasl_step_output);
     107 + gsasl_free(gsasl_step_output);
     108 + }
     109 + else
     110 + {
     111 + // sasl error occured, send an abort string
     112 + mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
     113 + gsasl_strerror(gsasl_rc));
     114 + mutt_buffer_strcpy(output_buf, "*");
     115 + }
     116 + 
     117 + mutt_buffer_addstr(output_buf, "\r\n");
     118 + mutt_socket_send(adata->conn, mutt_buffer_string(output_buf));
     119 + } while ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK));
     120 + 
     121 + if (imap_step_rc != IMAP_RES_OK)
     122 + {
     123 + do
     124 + imap_step_rc = imap_cmd_step(adata);
     125 + while (imap_step_rc == IMAP_RES_CONTINUE);
     126 + }
     127 + 
     128 + if (imap_step_rc == IMAP_RES_RESPOND)
     129 + {
     130 + mutt_socket_send(adata->conn, "*\r\n");
     131 + goto bail;
     132 + }
     133 + 
     134 + if ((gsasl_rc != GSASL_OK) || (imap_step_rc != IMAP_RES_OK))
     135 + goto bail;
     136 + 
     137 + if (imap_code(adata->buf))
     138 + rc = IMAP_AUTH_SUCCESS;
     139 + 
     140 +bail:
     141 + mutt_buffer_pool_release(&output_buf);
     142 + mutt_gsasl_client_finish(&gsasl_session);
     143 + 
     144 + if (rc == IMAP_AUTH_FAILURE)
     145 + {
     146 + mutt_debug(LL_DEBUG2, "%s failed\n", chosen_mech);
     147 + mutt_error(_("SASL authentication failed"));
     148 + }
     149 + 
     150 + return rc;
     151 +}
     152 + 
  • ■ ■ ■ ■
    imap/auth_sasl.c
    skipped 39 lines
    40 40  #include "auth.h"
    41 41   
    42 42  /**
    43  - * imap_auth_sasl - Default authenticator if available - Implements ImapAuth::authenticate()
     43 + * imap_auth_sasl - SASL authenticator - Implements ImapAuth::authenticate()
    44 44   */
    45 45  enum ImapAuthRes imap_auth_sasl(struct ImapAccountData *adata, const char *method)
    46 46  {
    skipped 212 lines
  • ■ ■ ■ ■ ■
    imap/config.c
    skipped 31 lines
    32 32  #include <stdbool.h>
    33 33  #include <stdint.h>
    34 34  #include "mutt/lib.h"
    35  -#include "conn/lib.h"
    36 35  #include "auth.h"
     36 +#ifdef USE_SASL_CYRUS
     37 +#include "conn/lib.h"
     38 +#endif
    37 39   
    38 40  /**
    39 41   * imap_auth_validator - Validate the "imap_authenticators" config variable - Implements ConfigDef::validator() - @ingroup cfg_def_validator
    skipped 118 lines
  • ■ ■ ■ ■ ■ ■
    main.c
    skipped 1382 lines
    1383 1383  #ifdef USE_SASL_CYRUS
    1384 1384   mutt_sasl_done();
    1385 1385  #endif
     1386 +#ifdef USE_SASL_GNU
     1387 + mutt_gsasl_done();
     1388 +#endif
    1386 1389  #ifdef USE_AUTOCRYPT
    1387 1390   mutt_autocrypt_cleanup();
    1388 1391  #endif
    skipped 42 lines
  • ■ ■ ■ ■ ■ ■
    pop/auth.c
    skipped 41 lines
    42 42  #include <sasl/sasl.h>
    43 43  #include <sasl/saslutil.h>
    44 44  #endif
     45 +#ifdef USE_SASL_GNU
     46 +#include <gsasl.h>
     47 +#endif
     48 + 
     49 +#ifdef USE_SASL_GNU
     50 +/**
     51 + * pop_auth_gsasl - POP GNU SASL authenticator - Implements PopAuth::authenticate()
     52 + */
     53 +static enum PopAuthRes pop_auth_gsasl(struct PopAccountData *adata, const char *method)
     54 +{
     55 + Gsasl_session *gsasl_session = NULL;
     56 + struct Buffer *output_buf = NULL;
     57 + struct Buffer *input_buf = NULL;
     58 + int rc = POP_A_FAILURE;
     59 + int gsasl_rc = GSASL_OK;
     60 + 
     61 + const char *chosen_mech = mutt_gsasl_get_mech(method,
     62 + mutt_buffer_string(&adata->auth_list));
     63 + if (!chosen_mech)
     64 + {
     65 + mutt_debug(LL_DEBUG2, "returned no usable mech\n");
     66 + return POP_A_UNAVAIL;
     67 + }
     68 + 
     69 + mutt_debug(LL_DEBUG2, "using mech %s\n", chosen_mech);
     70 + 
     71 + if (mutt_gsasl_client_new(adata->conn, chosen_mech, &gsasl_session) < 0)
     72 + {
     73 + mutt_debug(LL_DEBUG1, "Error allocating GSASL connection.\n");
     74 + return POP_A_UNAVAIL;
     75 + }
     76 + 
     77 + mutt_message(_("Authenticating (%s)..."), chosen_mech);
     78 + 
     79 + output_buf = mutt_buffer_pool_get();
     80 + input_buf = mutt_buffer_pool_get();
     81 + mutt_buffer_printf(output_buf, "AUTH %s\r\n", chosen_mech);
     82 + 
     83 + do
     84 + {
     85 + if (mutt_socket_send(adata->conn, mutt_buffer_string(output_buf)) < 0)
     86 + {
     87 + adata->status = POP_DISCONNECTED;
     88 + rc = POP_A_SOCKET;
     89 + goto fail;
     90 + }
     91 + 
     92 + if (mutt_socket_buffer_readln(input_buf, adata->conn) < 0)
     93 + {
     94 + adata->status = POP_DISCONNECTED;
     95 + rc = POP_A_SOCKET;
     96 + goto fail;
     97 + }
     98 + 
     99 + if (!mutt_strn_equal(mutt_buffer_string(input_buf), "+ ", 2))
     100 + break;
     101 + 
     102 + const char *pop_auth_data = mutt_buffer_string(input_buf) + 2;
     103 + char *gsasl_step_output = NULL;
     104 + gsasl_rc = gsasl_step64(gsasl_session, pop_auth_data, &gsasl_step_output);
     105 + if ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK))
     106 + {
     107 + mutt_buffer_strcpy(output_buf, gsasl_step_output);
     108 + mutt_buffer_addstr(output_buf, "\r\n");
     109 + gsasl_free(gsasl_step_output);
     110 + }
     111 + else
     112 + {
     113 + mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
     114 + gsasl_strerror(gsasl_rc));
     115 + }
     116 + } while ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK));
     117 + 
     118 + if (mutt_strn_equal(mutt_buffer_string(input_buf), "+ ", 2))
     119 + {
     120 + mutt_socket_send(adata->conn, "*\r\n");
     121 + goto fail;
     122 + }
     123 + 
     124 + if (mutt_strn_equal(mutt_buffer_string(input_buf), "+OK", 3) && (gsasl_rc == GSASL_OK))
     125 + rc = POP_A_SUCCESS;
     126 + 
     127 +fail:
     128 + mutt_buffer_pool_release(&input_buf);
     129 + mutt_buffer_pool_release(&output_buf);
     130 + mutt_gsasl_client_finish(&gsasl_session);
     131 + 
     132 + if (rc == POP_A_FAILURE)
     133 + {
     134 + mutt_debug(LL_DEBUG2, "%s failed\n", chosen_mech);
     135 + mutt_error(_("SASL authentication failed."));
     136 + }
     137 + 
     138 + return rc;
     139 +}
     140 +#endif
    45 141   
    46 142  #ifdef USE_SASL_CYRUS
    47 143  /**
    skipped 337 lines
    385 481   { pop_auth_oauth, "oauthbearer" },
    386 482  #ifdef USE_SASL_CYRUS
    387 483   { pop_auth_sasl, NULL },
     484 +#endif
     485 +#ifdef USE_SASL_GNU
     486 + { pop_auth_gsasl, NULL },
    388 487  #endif
    389 488   { pop_auth_apop, "apop" },
    390 489   { pop_auth_user, "user" },
    skipped 136 lines
  • ■ ■ ■ ■ ■
    pop/config.c
    skipped 32 lines
    33 33  #include <stdint.h>
    34 34  #include "private.h"
    35 35  #include "mutt/lib.h"
    36  -#include "conn/lib.h"
    37 36   
    38 37  /**
    39 38   * pop_auth_validator - Validate the "pop_authenticators" config variable - Implements ConfigDef::validator() - @ingroup cfg_def_validator
    skipped 71 lines
  • ■ ■ ■ ■ ■
    send/config.c
    skipped 32 lines
    33 33  #include <stdint.h>
    34 34  #include <string.h>
    35 35  #include "mutt/lib.h"
    36  -#include "conn/lib.h"
    37 36  #include "lib.h"
     37 +#ifdef USE_SASL_CYRUS
     38 +#include "conn/lib.h"
     39 +#endif
    38 40   
    39 41  /**
    40 42   * wrapheaders_validator - Validate the "wrap_headers" config variable - Implements ConfigDef::validator() - @ingroup cfg_def_validator
    skipped 334 lines
  • ■ ■ ■ ■ ■ ■
    send/smtp.c
    skipped 49 lines
    50 50  #include "mutt_account.h"
    51 51  #include "mutt_globals.h"
    52 52  #include "mutt_socket.h"
     53 +#ifdef USE_SASL_GNU
     54 +#include <gsasl.h>
     55 +#include "options.h"
     56 +#endif
    53 57  #ifdef USE_SASL_CYRUS
    54 58  #include <sasl/sasl.h>
    55 59  #include <sasl/saslutil.h>
    skipped 363 lines
    419 423   return smtp_get_resp(adata);
    420 424  }
    421 425   
     426 +#ifdef USE_SASL_GNU
     427 +/**
     428 + * smtp_code - Extract an SMTP return code from a string
     429 + * @param[in] str String to parse
     430 + * @param[in] len Length of string
     431 + * @param[out] n SMTP return code result
     432 + * @retval true Success
     433 + *
     434 + * Note: the 'len' parameter is actually the number of bytes, as
     435 + * returned by mutt_socket_readln(). If all callers are converted to
     436 + * mutt_socket_buffer_readln() we can pass in the actual len, or
     437 + * perhaps the buffer itself.
     438 + */
     439 +static int smtp_code(const char *str, size_t len, int *n)
     440 +{
     441 + char code[4];
     442 + 
     443 + if (len < 4)
     444 + return false;
     445 + code[0] = str[0];
     446 + code[1] = str[1];
     447 + code[2] = str[2];
     448 + code[3] = 0;
     449 + 
     450 + const char *end = mutt_str_atoi(code, n);
     451 + if (!end || (*end != '\0'))
     452 + return false;
     453 + return true;
     454 +}
     455 + 
     456 +/**
     457 + * smtp_get_auth_response - Get the SMTP authorisation response
     458 + * @param[in] conn Connection to a server
     459 + * @param[in] input_buf Temp buffer for strings returned by the server
     460 + * @param[out] smtp_rc SMTP return code result
     461 + * @param[out] response_buf Text after the SMTP response code
     462 + * @retval 0 Success
     463 + * @retval -1 Error
     464 + *
     465 + * Did the SMTP authorisation succeed?
     466 + */
     467 +static int smtp_get_auth_response(struct Connection *conn, struct Buffer *input_buf,
     468 + int *smtp_rc, struct Buffer *response_buf)
     469 +{
     470 + mutt_buffer_reset(response_buf);
     471 + do
     472 + {
     473 + if (mutt_socket_buffer_readln(input_buf, conn) < 0)
     474 + return -1;
     475 + if (!smtp_code(mutt_buffer_string(input_buf),
     476 + mutt_buffer_len(input_buf) + 1 /* number of bytes */, smtp_rc))
     477 + {
     478 + return -1;
     479 + }
     480 + 
     481 + if (*smtp_rc != SMTP_READY)
     482 + break;
     483 + 
     484 + const char *smtp_response = mutt_buffer_string(input_buf) + 3;
     485 + if (*smtp_response)
     486 + {
     487 + smtp_response++;
     488 + mutt_buffer_addstr(response_buf, smtp_response);
     489 + }
     490 + } while (mutt_buffer_string(input_buf)[3] == '-');
     491 + 
     492 + return 0;
     493 +}
     494 + 
     495 +/**
     496 + * smtp_auth_gsasl - Authenticate using SASL
     497 + * @param adata SMTP Account data
     498 + * @param mechlist List of mechanisms to use
     499 + * @retval 0 Success
     500 + * @retval <0 Error, e.g. #SMTP_AUTH_FAIL
     501 + */
     502 +static int smtp_auth_gsasl(struct SmtpAccountData *adata, const char *mechlist)
     503 +{
     504 + Gsasl_session *gsasl_session = NULL;
     505 + struct Buffer *input_buf = NULL, *output_buf = NULL, *smtp_response_buf = NULL;
     506 + int rc = SMTP_AUTH_FAIL, gsasl_rc = GSASL_OK, smtp_rc;
     507 + 
     508 + const char *chosen_mech = mutt_gsasl_get_mech(mechlist, adata->auth_mechs);
     509 + if (!chosen_mech)
     510 + {
     511 + mutt_debug(LL_DEBUG2, "returned no usable mech\n");
     512 + return SMTP_AUTH_UNAVAIL;
     513 + }
     514 + 
     515 + mutt_debug(LL_DEBUG2, "using mech %s\n", chosen_mech);
     516 + 
     517 + if (mutt_gsasl_client_new(adata->conn, chosen_mech, &gsasl_session) < 0)
     518 + {
     519 + mutt_debug(LL_DEBUG1, "Error allocating GSASL connection.\n");
     520 + return SMTP_AUTH_UNAVAIL;
     521 + }
     522 + 
     523 + if (!OptNoCurses)
     524 + mutt_message(_("Authenticating (%s)..."), chosen_mech);
     525 + 
     526 + input_buf = mutt_buffer_pool_get();
     527 + output_buf = mutt_buffer_pool_get();
     528 + smtp_response_buf = mutt_buffer_pool_get();
     529 + 
     530 + mutt_buffer_printf(output_buf, "AUTH %s", chosen_mech);
     531 + 
     532 + /* Work around broken SMTP servers. See Debian #1010658.
     533 + * The msmtp source also forces IR for PLAIN because the author
     534 + * encountered difficulties with a server requiring it. */
     535 + if (mutt_str_equal(chosen_mech, "PLAIN"))
     536 + {
     537 + char *gsasl_step_output = NULL;
     538 + gsasl_rc = gsasl_step64(gsasl_session, "", &gsasl_step_output);
     539 + if (gsasl_rc != GSASL_NEEDS_MORE && gsasl_rc != GSASL_OK)
     540 + {
     541 + mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
     542 + gsasl_strerror(gsasl_rc));
     543 + goto fail;
     544 + }
     545 + 
     546 + mutt_buffer_addch(output_buf, ' ');
     547 + mutt_buffer_addstr(output_buf, gsasl_step_output);
     548 + gsasl_free(gsasl_step_output);
     549 + }
     550 + 
     551 + mutt_buffer_addstr(output_buf, "\r\n");
     552 + 
     553 + do
     554 + {
     555 + if (mutt_socket_send(adata->conn, mutt_buffer_string(output_buf)) < 0)
     556 + goto fail;
     557 + 
     558 + if (smtp_get_auth_response(adata->conn, input_buf, &smtp_rc, smtp_response_buf) < 0)
     559 + goto fail;
     560 + 
     561 + if (smtp_rc != SMTP_READY)
     562 + break;
     563 + 
     564 + char *gsasl_step_output = NULL;
     565 + gsasl_rc = gsasl_step64(gsasl_session, mutt_buffer_string(smtp_response_buf),
     566 + &gsasl_step_output);
     567 + if ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK))
     568 + {
     569 + mutt_buffer_strcpy(output_buf, gsasl_step_output);
     570 + mutt_buffer_addstr(output_buf, "\r\n");
     571 + gsasl_free(gsasl_step_output);
     572 + }
     573 + else
     574 + {
     575 + mutt_debug(LL_DEBUG1, "gsasl_step64() failed (%d): %s\n", gsasl_rc,
     576 + gsasl_strerror(gsasl_rc));
     577 + }
     578 + } while ((gsasl_rc == GSASL_NEEDS_MORE) || (gsasl_rc == GSASL_OK));
     579 + 
     580 + if (smtp_rc == SMTP_READY)
     581 + {
     582 + mutt_socket_send(adata->conn, "*\r\n");
     583 + goto fail;
     584 + }
     585 + 
     586 + if (smtp_success(smtp_rc) && (gsasl_rc == GSASL_OK))
     587 + rc = SMTP_AUTH_SUCCESS;
     588 + 
     589 +fail:
     590 + mutt_buffer_pool_release(&input_buf);
     591 + mutt_buffer_pool_release(&output_buf);
     592 + mutt_buffer_pool_release(&smtp_response_buf);
     593 + mutt_gsasl_client_finish(&gsasl_session);
     594 + 
     595 + if (rc == SMTP_AUTH_FAIL)
     596 + mutt_debug(LL_DEBUG2, "%s failed\n", chosen_mech);
     597 + 
     598 + return rc;
     599 +}
     600 +#endif
     601 + 
    422 602  #ifdef USE_SASL_CYRUS
    423 603  /**
    424 604   * smtp_auth_sasl - Authenticate using SASL
    skipped 299 lines
    724 904  #ifdef USE_SASL_CYRUS
    725 905   { smtp_auth_sasl, NULL },
    726 906  #endif
     907 +#ifdef USE_SASL_GNU
     908 + { smtp_auth_gsasl, NULL },
     909 +#endif
    727 910   // clang-format on
    728 911  };
    729 912   
    skipped 55 lines
    785 968   /* Fall back to default: any authenticator */
    786 969   mutt_debug(LL_DEBUG2, "Falling back to smtp_auth_sasl, if using sasl.\n");
    787 970   
    788  -#ifdef USE_SASL_CYRUS
     971 +#if defined(USE_SASL_CYRUS)
    789 972   r = smtp_auth_sasl(adata, adata->auth_mechs);
     973 +#elif defined(USE_SASL_GNU)
     974 + r = smtp_auth_gsasl(adata, adata->auth_mechs);
    790 975  #else
    791 976   mutt_error(_("SMTP authentication requires SASL"));
    792 977   r = SMTP_AUTH_UNAVAIL;
    skipped 209 lines
  • ■ ■ ■ ■ ■
    version.c
    skipped 197 lines
    198 198  #else
    199 199   { "gpgme", 0 },
    200 200  #endif
     201 +#ifdef USE_SASL_GNU
     202 + { "gsasl", 1 },
     203 +#else
     204 + { "gsasl", 0 },
     205 +#endif
    201 206  #ifdef USE_GSS
    202 207   { "gss", 1 },
    203 208  #else
    skipped 380 lines
Please wait...
Page is in error, reload to recover