Browse Source

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.
Oswald Buddenhagen 11 years ago
parent
commit
1217193fbb
3 changed files with 90 additions and 27 deletions
  1. 2 0
      NEWS
  2. 75 24
      src/drv_imap.c
  3. 13 3
      src/mbsync.1

+ 2 - 0
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.
 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.

+ 75 - 24
src/drv_imap.c

@@ -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,11 +982,20 @@ 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 )))
-		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
 static int
@@ -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,31 +1711,47 @@ 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
+					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
 #ifdef HAVE_LIBSSL
-	if (CAP(CRAM)) {
+	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)) {
-		error( "Skipping account %s, server forbids LOGIN\n", srvc->name );
-		goto bail;
-	}
+	if (auth_login) {
+		info( "Logging in...\n" );
 #ifdef HAVE_LIBSSL
 #ifdef HAVE_LIBSSL
-	if (!ctx->conn.ssl)
+		if (!ctx->conn.ssl)
 #endif
 #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:
   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 ))
-			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
 #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

+ 13 - 3
src/mbsync.1

@@ -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
-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
 .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,