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.
This commit is contained in:
Oswald Buddenhagen 2014-07-12 21:02:25 +02:00
parent aba3524d9b
commit 1217193fbb
3 changed files with 90 additions and 27 deletions

2
NEWS
View File

@ -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. 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. Notice: Tunnels are assumed to be secure and thus default to no SSL.
More flexible configuration of the used authentication mechanism.
[1.1.0] [1.1.0]
Support for hierarchical mailboxes in Patterns. Support for hierarchical mailboxes in Patterns.

View File

@ -48,9 +48,9 @@ typedef struct imap_server_conf {
char *pass; char *pass;
char *pass_cmd; char *pass_cmd;
int max_in_progress; int max_in_progress;
string_list_t *auth_mechs;
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
char ssl_type; char ssl_type;
char require_cram;
#endif #endif
} imap_server_conf_t; } imap_server_conf_t;
@ -100,6 +100,7 @@ typedef struct imap_store {
list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
message_t **msgapp; /* FETCH results */ message_t **msgapp; /* FETCH results */
unsigned caps; /* CAPABILITY results */ unsigned caps; /* CAPABILITY results */
string_list_t *auth_mechs;
parse_list_state_t parse_list_sts; parse_list_state_t parse_list_sts;
/* command queue */ /* command queue */
int nexttag, num_in_progress; int nexttag, num_in_progress;
@ -173,7 +174,6 @@ struct imap_cmd_refcounted {
enum CAPABILITY { enum CAPABILITY {
NOLOGIN = 0, NOLOGIN = 0,
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
CRAM,
STARTTLS, STARTTLS,
#endif #endif
UIDPLUS, UIDPLUS,
@ -185,7 +185,6 @@ enum CAPABILITY {
static const char *cap_list[] = { static const char *cap_list[] = {
"LOGINDISABLED", "LOGINDISABLED",
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
"AUTH=CRAM-MD5",
"STARTTLS", "STARTTLS",
#endif #endif
"UIDPLUS", "UIDPLUS",
@ -983,12 +982,21 @@ parse_capability( imap_store_t *ctx, char *cmd )
char *arg; char *arg;
unsigned i; unsigned i;
free_string_list( ctx->auth_mechs );
ctx->auth_mechs = 0;
ctx->caps = 0x80000000; ctx->caps = 0x80000000;
while ((arg = next_arg( &cmd ))) 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++) for (i = 0; i < as(cap_list); i++)
if (!strcmp( cap_list[i], arg )) if (!strcmp( cap_list[i], arg ))
ctx->caps |= 1 << i; ctx->caps |= 1 << i;
} }
}
if (!CAP(NOLOGIN))
add_string_list( &ctx->auth_mechs, "LOGIN" );
}
static int static int
parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s ) parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s )
@ -1354,6 +1362,7 @@ imap_cancel_store( store_t *gctx )
free_list( ctx->ns_personal ); free_list( ctx->ns_personal );
free_list( ctx->ns_other ); free_list( ctx->ns_other );
free_list( ctx->ns_shared ); free_list( ctx->ns_shared );
free_string_list( ctx->auth_mechs );
free( ctx->delimiter ); free( ctx->delimiter );
imap_deref( ctx ); 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_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
imap_server_conf_t *srvc = cfg->server; imap_server_conf_t *srvc = cfg->server;
string_list_t *mech, *cmech;
char *arg; char *arg;
#ifdef HAVE_LIBSSL
int auth_cram = 0;
#endif
int auth_login = 0;
info ("Logging in...\n"); info ("Logging in...\n");
if (!srvc->user) { if (!srvc->user) {
@ -1697,24 +1711,38 @@ imap_open_store_authenticate2( imap_store_t *ctx )
*/ */
srvc->pass = nfstrdup( arg ); 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 #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) ); 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; cmd->param.cont = do_cram_auth;
imap_exec( ctx, cmd, imap_open_store_authenticate2_p2, "AUTHENTICATE CRAM-MD5" ); imap_exec( ctx, cmd, imap_open_store_authenticate2_p2, "AUTHENTICATE CRAM-MD5" );
return; return;
} }
if (srvc->require_cram) {
error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" );
goto bail;
}
#endif #endif
if (CAP(NOLOGIN)) { if (auth_login) {
error( "Skipping account %s, server forbids LOGIN\n", srvc->name ); info( "Logging in...\n" );
goto bail;
}
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
if (!ctx->conn.ssl) if (!ctx->conn.ssl)
#endif #endif
@ -1722,6 +1750,8 @@ imap_open_store_authenticate2( imap_store_t *ctx )
imap_exec( ctx, 0, imap_open_store_authenticate2_p2, imap_exec( ctx, 0, imap_open_store_authenticate2_p2,
"LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass ); "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass );
return; return;
}
error( "IMAP error: server supports no acceptable authentication mechanism\n" );
bail: bail:
imap_open_store_bail( ctx ); imap_open_store_bail( ctx );
@ -2240,6 +2270,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
/* Legacy SSL options */ /* Legacy SSL options */
int require_ssl = -1, use_imaps = -1; int require_ssl = -1, use_imaps = -1;
int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1; int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1;
int require_cram = -1;
#endif #endif
if (!strcasecmp( "IMAPAccount", cfg->cmd )) { if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
@ -2356,8 +2387,14 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
use_tlsv11 = parse_bool( cfg ); use_tlsv11 = parse_bool( cfg );
else if (!strcasecmp( "UseTLSv1.2", cfg->cmd )) else if (!strcasecmp( "UseTLSv1.2", cfg->cmd ))
use_tlsv12 = parse_bool( cfg ); use_tlsv12 = parse_bool( cfg );
else if (!strcasecmp( "RequireCRAM", cfg->cmd )) else if (!strcasecmp( "AuthMech", cfg->cmd ) ||
server->require_cram = parse_bool( cfg ); !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 #endif
else if (!strcasecmp( "Tunnel", cfg->cmd )) else if (!strcasecmp( "Tunnel", cfg->cmd ))
server->sconf.tunnel = nfstrdup( cfg->val ); 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; server->ssl_type = server->sconf.tunnel ? SSL_None : SSL_STARTTLS;
} }
#endif #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) if (!server->sconf.port)
server->sconf.port = server->sconf.port =
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL

View File

@ -274,9 +274,16 @@ socket. This allows you to run an IMAP session over an SSH tunnel, for
example. example.
.. ..
.TP .TP
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR \fBAuthMechs\fR \fItype\fR ...
If set to \fIyes\fR, \fBmbsync\fR will abort the connection if no CRAM-MD5 The list of acceptable authentication mechanisms.
authentication is possible. (Default: \fIno\fR) 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 .TP
\fBSSLType\fR {\fINone\fR|\fISTARTTLS\fR|\fIIMAPS\fR} \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) mdconvert(1), isync(1), mutt(1), maildir(5)
.P .P
Up to date information on \fBmbsync\fR can be found at http://isync.sf.net/ 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 .SH AUTHORS
Originally written by Michael R. Elkins, Originally written by Michael R. Elkins,