From 1217193fbbbf6dca7c31eab3d418e20dc8c43fd7 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 12 Jul 2014 21:02:25 +0200 Subject: [PATCH] rework authentication mechanism configuration RequireCRAM (another fairly stupid "use if available" option) is now deprecated. instead, the AuthMech option can be used to give a precise list of acceptable authentication mechanisms (which is currently "a bit" short). in particular, this allows *not* using CRAM-MD5 even if it's available. --- NEWS | 2 + src/drv_imap.c | 99 ++++++++++++++++++++++++++++++++++++++------------ src/mbsync.1 | 16 ++++++-- 3 files changed, 90 insertions(+), 27 deletions(-) diff --git a/NEWS b/NEWS index a4ff5ec..7bcc75b 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ The SSL/TLS configuration has been re-designed. SSL is now explicitly enabled or disabled - "use SSL if available" is gone. Notice: Tunnels are assumed to be secure and thus default to no SSL. +More flexible configuration of the used authentication mechanism. + [1.1.0] Support for hierarchical mailboxes in Patterns. diff --git a/src/drv_imap.c b/src/drv_imap.c index e5e0621..9a1a0d0 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -48,9 +48,9 @@ typedef struct imap_server_conf { char *pass; char *pass_cmd; int max_in_progress; + string_list_t *auth_mechs; #ifdef HAVE_LIBSSL char ssl_type; - char require_cram; #endif } imap_server_conf_t; @@ -100,6 +100,7 @@ typedef struct imap_store { list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ message_t **msgapp; /* FETCH results */ unsigned caps; /* CAPABILITY results */ + string_list_t *auth_mechs; parse_list_state_t parse_list_sts; /* command queue */ int nexttag, num_in_progress; @@ -173,7 +174,6 @@ struct imap_cmd_refcounted { enum CAPABILITY { NOLOGIN = 0, #ifdef HAVE_LIBSSL - CRAM, STARTTLS, #endif UIDPLUS, @@ -185,7 +185,6 @@ enum CAPABILITY { static const char *cap_list[] = { "LOGINDISABLED", #ifdef HAVE_LIBSSL - "AUTH=CRAM-MD5", "STARTTLS", #endif "UIDPLUS", @@ -983,11 +982,20 @@ parse_capability( imap_store_t *ctx, char *cmd ) char *arg; unsigned i; + free_string_list( ctx->auth_mechs ); + ctx->auth_mechs = 0; ctx->caps = 0x80000000; - while ((arg = next_arg( &cmd ))) - for (i = 0; i < as(cap_list); i++) - if (!strcmp( cap_list[i], arg )) - ctx->caps |= 1 << i; + while ((arg = next_arg( &cmd ))) { + if (!memcmp( "AUTH=", arg, 5 )) { + add_string_list( &ctx->auth_mechs, arg + 5 ); + } else { + for (i = 0; i < as(cap_list); i++) + if (!strcmp( cap_list[i], arg )) + ctx->caps |= 1 << i; + } + } + if (!CAP(NOLOGIN)) + add_string_list( &ctx->auth_mechs, "LOGIN" ); } static int @@ -1354,6 +1362,7 @@ imap_cancel_store( store_t *gctx ) free_list( ctx->ns_personal ); free_list( ctx->ns_other ); free_list( ctx->ns_shared ); + free_string_list( ctx->auth_mechs ); free( ctx->delimiter ); imap_deref( ctx ); } @@ -1644,7 +1653,12 @@ imap_open_store_authenticate2( imap_store_t *ctx ) { imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; imap_server_conf_t *srvc = cfg->server; + string_list_t *mech, *cmech; char *arg; +#ifdef HAVE_LIBSSL + int auth_cram = 0; +#endif + int auth_login = 0; info ("Logging in...\n"); if (!srvc->user) { @@ -1697,31 +1711,47 @@ imap_open_store_authenticate2( imap_store_t *ctx ) */ srvc->pass = nfstrdup( arg ); } + for (mech = srvc->auth_mechs; mech; mech = mech->next) { + int any = !strcmp( mech->string, "*" ); + for (cmech = ctx->auth_mechs; cmech; cmech = cmech->next) { + if (any || !strcasecmp( mech->string, cmech->string )) { + if (!strcasecmp( cmech->string, "LOGIN" )) { #ifdef HAVE_LIBSSL - if (CAP(CRAM)) { + if (ctx->conn.ssl || !any) +#endif + auth_login = 1; +#ifdef HAVE_LIBSSL + } else if (!strcasecmp( cmech->string, "CRAM-MD5" )) { + auth_cram = 1; +#endif + } else { + error( "IMAP error: authentication mechanism %s is not supported\n", cmech->string ); + goto bail; + } + } + } + } +#ifdef HAVE_LIBSSL + if (auth_cram) { struct imap_cmd *cmd = new_imap_cmd( sizeof(*cmd) ); - info( "Authenticating with CRAM-MD5\n" ); + info( "Authenticating with CRAM-MD5...\n" ); cmd->param.cont = do_cram_auth; imap_exec( ctx, cmd, imap_open_store_authenticate2_p2, "AUTHENTICATE CRAM-MD5" ); return; } - if (srvc->require_cram) { - error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" ); - goto bail; - } #endif - if (CAP(NOLOGIN)) { - error( "Skipping account %s, server forbids LOGIN\n", srvc->name ); - goto bail; - } + if (auth_login) { + info( "Logging in...\n" ); #ifdef HAVE_LIBSSL - if (!ctx->conn.ssl) + if (!ctx->conn.ssl) #endif - warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); - imap_exec( ctx, 0, imap_open_store_authenticate2_p2, - "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass ); - return; + warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); + imap_exec( ctx, 0, imap_open_store_authenticate2_p2, + "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass ); + return; + } + error( "IMAP error: server supports no acceptable authentication mechanism\n" ); bail: imap_open_store_bail( ctx ); @@ -2240,6 +2270,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) /* Legacy SSL options */ int require_ssl = -1, use_imaps = -1; int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1; + int require_cram = -1; #endif if (!strcasecmp( "IMAPAccount", cfg->cmd )) { @@ -2356,8 +2387,14 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) use_tlsv11 = parse_bool( cfg ); else if (!strcasecmp( "UseTLSv1.2", cfg->cmd )) use_tlsv12 = parse_bool( cfg ); - else if (!strcasecmp( "RequireCRAM", cfg->cmd )) - server->require_cram = parse_bool( cfg ); + else if (!strcasecmp( "AuthMech", cfg->cmd ) || + !strcasecmp( "AuthMechs", cfg->cmd )) { + arg = cfg->val; + do + add_string_list( &server->auth_mechs, arg ); + while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 ))); + } else if (!strcasecmp( "RequireCRAM", cfg->cmd )) + require_cram = parse_bool( cfg ); #endif else if (!strcasecmp( "Tunnel", cfg->cmd )) server->sconf.tunnel = nfstrdup( cfg->val ); @@ -2438,6 +2475,20 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) server->ssl_type = server->sconf.tunnel ? SSL_None : SSL_STARTTLS; } #endif +#ifdef HAVE_LIBSSL + if (require_cram >= 0) { + if (server->auth_mechs) { + error( "%s '%s': The deprecated RequireCRAM option is mutually exlusive with AuthMech.\n", type, name ); + cfg->err = 1; + return 1; + } + warn( "Notice: %s '%s': RequireCRAM is deprecated. Use AuthMech instead.\n", type, name ); + if (require_cram) + add_string_list(&server->auth_mechs, "CRAM-MD5"); + } +#endif + if (!server->auth_mechs) + add_string_list( &server->auth_mechs, "*" ); if (!server->sconf.port) server->sconf.port = #ifdef HAVE_LIBSSL diff --git a/src/mbsync.1 b/src/mbsync.1 index 599061e..478fabf 100644 --- a/src/mbsync.1 +++ b/src/mbsync.1 @@ -274,9 +274,16 @@ socket. This allows you to run an IMAP session over an SSH tunnel, for example. .. .TP -\fBRequireCRAM\fR \fIyes\fR|\fIno\fR -If set to \fIyes\fR, \fBmbsync\fR will abort the connection if no CRAM-MD5 -authentication is possible. (Default: \fIno\fR) +\fBAuthMechs\fR \fItype\fR ... +The list of acceptable authentication mechanisms. +In addition to the mechanisms listed in the SASL registry (link below), +the legacy IMAP \fBLOGIN\fR mechanism is known. +The wildcard \fB*\fR represents all mechanisms that are deemed secure +enough for the current \fBSSLType\fR setting. +The actually used mechanism is the most secure choice from the intersection +of this list, the list supplied by the server, and the mechanisms actually +supported by \fBmbsync\fR (currently only \fBCRAM-MD5\fR and \fBLOGIN\fR). +(Default: \fB*\fR) .. .TP \fBSSLType\fR {\fINone\fR|\fISTARTTLS\fR|\fIIMAPS\fR} @@ -594,6 +601,9 @@ Directory containing synchronization state files mdconvert(1), isync(1), mutt(1), maildir(5) .P Up to date information on \fBmbsync\fR can be found at http://isync.sf.net/ +.P +SASL mechanisms are listed at +http://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml .. .SH AUTHORS Originally written by Michael R. Elkins,