Version 2 patch. Including timsieved.
Also in the patch is some code for Serverinfo switch in timsieved to not 
disclose name and/or version info in "IMPLEMENTATION" if Serverinfo is Off or 
Min.

Regards,
Carlos Velasco

-------- Original Message --------
Subject: Patch: forcing SSL before auth
From: Carlos Velasco <carlos.vela...@nimastelecom.com>
To: cyrus-devel@lists.andrew.cmu.edu
Date: 9/8/2015 12:18:36
> Hi,
>
> Right now, "allowplaintext" option disallow using a plain authentication if 
> session is not protected by TLS.
> However, this setting still allows a client to make MD5 or SHA1 auth without 
> session being protected by TLS. This can lead to not data confidentiality 
> when using not plain auth.
> There are several admins now requesting to force TLS for all sessions, and 
> although this can be done using "allowplaintext" and removing all mechs but 
> Plain, it would be right to be able to provide another layer of security and 
> use TLS+SHA1 or so...
>
> Attached is a patch with a new imapd.conf option:
> forcetlsauth: 0 | 1. Default 0
> If enabled all authentications require a TLS session negotiated before.
>
> Patch also "hides" AUTH and other authentication commands that are not 
> allowed before TLS, in Capabilites commands.
> Patched in imapd, pop3d, nntpd, httpd.
>
> This patch does not break cyradm functionality at all, however I attach 
> another patch for the cyradm perl part to allow "--cafile" option (got tired 
> of certificate validation warnings) and also fixed a minor bug when 
> requesting capabilities to server without the callback.
>
> Please, consider committing this to mainstream.
>
> Regards,
> Carlos Velasco
>

diff -ur a/imap/httpd.c b/imap/httpd.c
--- a/imap/httpd.c	2015-07-06 02:40:07.000000000 +0200
+++ b/imap/httpd.c	2015-08-09 14:46:11.855933782 +0200
@@ -602,7 +602,10 @@
 	    }
 	}
     }
-    httpd_tls_required = !avail_auth_schemes;
+    if (config_getswitch(IMAPOPT_FORCETLSAUTH))
+	httpd_tls_required = 1;
+    else
+	httpd_tls_required = !avail_auth_schemes;
 
     proc_register("httpd", httpd_clienthost, NULL, NULL, NULL);
 
diff -ur a/imap/imapd.c b/imap/imapd.c
--- a/imap/imapd.c	2015-07-06 02:40:07.000000000 +0200
+++ b/imap/imapd.c	2015-08-09 14:46:11.881933801 +0200
@@ -2398,9 +2398,11 @@
     }
 
     /* possibly disallow login */
-    if (!imapd_starttls_done && (extprops_ssf < 2) &&
-	!config_getswitch(IMAPOPT_ALLOWPLAINTEXT) &&
-	!is_userid_anonymous(canon_user)) {
+    if ((!imapd_starttls_done && (extprops_ssf < 2) &&
+         !config_getswitch(IMAPOPT_ALLOWPLAINTEXT) &&
+	 !is_userid_anonymous(canon_user)) || 
+        (!imapd_starttls_done &&
+	 config_getswitch(IMAPOPT_FORCETLSAUTH))) {
 	eatline(imapd_in, ' ');
 	prot_printf(imapd_out, "%s NO Login only available under a layer\r\n",
 		    tag);
@@ -2548,6 +2550,14 @@
     int r;
     int failedloginpause;
 
+    if (!imapd_starttls_done &&
+        config_getswitch(IMAPOPT_FORCETLSAUTH)) {
+        eatline(imapd_in, ' ');
+        prot_printf(imapd_out, "%s NO Auth only available under a layer\r\n",
+                    tag);
+        return;
+    }
+
     r = saslserver(imapd_saslconn, authtype, resp, "", "+ ", "",
 		   imapd_in, imapd_out, &sasl_result, NULL);
 
@@ -3039,6 +3049,7 @@
 
     /* add the SASL mechs */
     if ((!imapd_authstate || saslprops.ssf) &&
+        (imapd_starttls_done || !config_getswitch(IMAPOPT_FORCETLSAUTH)) &&
 	sasl_listmech(imapd_saslconn, NULL, 
 		      "AUTH=", " AUTH=",
 		      !imapd_authstate ? " SASL-IR" : "", &sasllist,
diff -ur a/imap/nntpd.c b/imap/nntpd.c
--- a/imap/nntpd.c	2015-07-06 02:40:07.000000000 +0200
+++ b/imap/nntpd.c	2015-08-09 14:46:11.883933803 +0200
@@ -1813,20 +1813,22 @@
     if (tls_enabled() && !nntp_starttls_done && !nntp_authstate)
 	prot_printf(nntp_out, "STARTTLS\r\n");
 
-    /* check for SASL mechs */
-    sasl_listmech(nntp_saslconn, NULL, "SASL ", " ", "\r\n",
-		  &mechlist, NULL, &mechcount);
-
-    /* add the AUTHINFO variants */
-    if (!nntp_authstate) {
-	prot_printf(nntp_out, "AUTHINFO%s%s\r\n",
+    if (nntp_starttls_done || !config_getswitch(IMAPOPT_FORCETLSAUTH)) {
+        /* check for SASL mechs */
+        sasl_listmech(nntp_saslconn, NULL, "SASL ", " ", "\r\n",
+		&mechlist, NULL, &mechcount);
+
+        /* add the AUTHINFO variants */
+        if (!nntp_authstate) {
+		prot_printf(nntp_out, "AUTHINFO%s%s\r\n",
 		    (nntp_starttls_done || (extprops_ssf > 1) ||
 		     config_getswitch(IMAPOPT_ALLOWPLAINTEXT)) ?
 		    " USER" : "", mechcount ? " SASL" : "");
-    }
+        }
 
-    /* add the SASL mechs */
-    if (mechcount) prot_printf(nntp_out, "%s", mechlist);
+        /* add the SASL mechs */
+        if (mechcount) prot_printf(nntp_out, "%s", mechlist);
+    }
 
     /* add the reader capabilities/extensions */
     if ((nntp_capa & MODE_READ) && (nntp_authstate || allowanonymous)) {
@@ -1974,9 +1976,10 @@
 	return;
     }
 
-    /* possibly disallow USER */
-    if (!(nntp_starttls_done || (extprops_ssf > 1) ||
-	  config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
+    /* possibly disallow AUTHINFO USER */
+    if ((!(nntp_starttls_done || (extprops_ssf > 1) ||
+	  config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) ||
+        (!nntp_starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH))) {
 	prot_printf(nntp_out,
 		    "483 AUTHINFO USER command only available under a layer\r\n");
 	return;
@@ -2085,6 +2088,13 @@
     int failedloginpause;
     struct proc_limits limits;
 
+    /* possibly disallow AUTHINFO SASL */
+    if (!nntp_starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH)) {
+        prot_printf(nntp_out,
+                    "483 AUTHINFO SASL command only available under a layer\r\n");
+        return;
+    }
+
     /* Conceal initial response in telemetry log */
     if (nntp_logfd != -1 && resp) {
 	r = ftruncate(nntp_logfd,
diff -ur a/imap/pop3d.c b/imap/pop3d.c
--- a/imap/pop3d.c	2015-07-06 02:40:07.000000000 +0200
+++ b/imap/pop3d.c	2015-08-09 14:46:11.884933804 +0200
@@ -1349,6 +1349,13 @@
     const void *canon_user;
     int failedloginpause;
 
+    /* possibly disallow APOP */
+    if (!popd_starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH)) {
+        prot_printf(popd_out,
+                    "-ERR [AUTH] APOP command only available under a layer\r\n");
+        return;
+    }
+
     assert(response != NULL);
 
     if (popd_userid) {
@@ -1418,7 +1425,8 @@
 
     /* possibly disallow USER */
     if (!(kflag || popd_starttls_done || (extprops_ssf > 1) ||
-	  config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
+	  config_getswitch(IMAPOPT_ALLOWPLAINTEXT)) ||
+         (!popd_starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH))) {
 	prot_printf(popd_out,
 		    "-ERR [AUTH] USER command only available under a layer\r\n");
 	return;
@@ -1570,6 +1578,7 @@
 
     /* SASL special case: print SASL, then a list of supported capabilities */
     if ((!popd_authstate || saslprops.ssf) &&
+         (popd_starttls_done || !config_getswitch(IMAPOPT_FORCETLSAUTH)) &&
 	sasl_listmech(popd_saslconn,
 		      NULL, /* should be id string */
 		      "SASL ", " ", "\r\n",
@@ -1594,9 +1603,10 @@
     prot_printf(popd_out, "RESP-CODES\r\n");
     prot_printf(popd_out, "AUTH-RESP-CODE\r\n");
 
-    if (!popd_authstate &&
-	(kflag || popd_starttls_done || (extprops_ssf > 1)
-	 || config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) {
+    if ((!popd_authstate &&
+	 (kflag || popd_starttls_done || (extprops_ssf > 1)
+	  || config_getswitch(IMAPOPT_ALLOWPLAINTEXT))) &&
+        (popd_starttls_done || !config_getswitch(IMAPOPT_FORCETLSAUTH))) {
 	prot_printf(popd_out, "USER\r\n");
     }
 
@@ -1619,6 +1629,13 @@
     const char *canon_user;
     int failedloginpause;
 
+    /* possibly disallow AUTH */
+    if (!popd_starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH)) {
+        prot_printf(popd_out,
+                    "-ERR [AUTH] AUTH command only available under a layer\r\n");
+        return;
+    }
+
     /* if client didn't specify an argument we give them the list
      *
      * XXX This method of mechanism discovery is an undocumented feature
diff -ur a/lib/imapopts.c b/lib/imapopts.c
--- a/lib/imapopts.c	2015-07-06 03:24:21.000000000 +0200
+++ b/lib/imapopts.c	2015-08-09 14:46:11.885933805 +0200
@@ -64,6 +64,10 @@
     (union config_value)((long) 0),
     (union config_value)((long) 0),
     { { NULL, IMAP_ENUM_ZERO } } },
+  { IMAPOPT_FORCETLSAUTH, "forcetlsauth", 0, OPT_SWITCH,
+    (union config_value)((long) 0),
+    (union config_value)((long) 0),
+    { { NULL, IMAP_ENUM_ZERO } } },
   { IMAPOPT_ALLOWUSERMOVES, "allowusermoves", 0, OPT_SWITCH,
     (union config_value)((long) 0),
     (union config_value)((long) 0),
diff -ur a/lib/imapopts.h b/lib/imapopts.h
--- a/lib/imapopts.h	2015-07-06 03:24:21.000000000 +0200
+++ b/lib/imapopts.h	2015-08-09 14:46:11.885933805 +0200
@@ -26,6 +26,7 @@
   IMAPOPT_ALLOWAPOP,
   IMAPOPT_ALLOWNEWNEWS,
   IMAPOPT_ALLOWPLAINTEXT,
+  IMAPOPT_FORCETLSAUTH,
   IMAPOPT_ALLOWUSERMOVES,
   IMAPOPT_ALTNAMESPACE,
   IMAPOPT_ANNOTATION_DB,
diff -ur a/timsieved/actions.c b/timsieved/actions.c
--- a/timsieved/actions.c	2015-07-06 02:40:07.000000000 +0200
+++ b/timsieved/actions.c	2015-08-09 15:40:44.286364806 +0200
@@ -177,12 +177,23 @@
     int mechcount;
 
     /* implementation */
-    prot_printf(conn,
+    if (config_serverinfo == IMAP_ENUM_SERVERINFO_ON) {
+	prot_printf(conn,
 		"\"IMPLEMENTATION\" \"Cyrus timsieved%s %s\"\r\n",
 		config_mupdate_server ? " (Murder)" : "", cyrus_version());
+    } else if (config_serverinfo == IMAP_ENUM_SERVERINFO_MIN) {
+	prot_printf(conn,
+	        "\"IMPLEMENTATION\" \"Cyrus timsieved%s\"\r\n",
+		config_mupdate_server ? " (Murder)" : "");
+    } else {
+    /* IMAP_ENUM_SERVERINFO_OFF */
+	prot_printf(conn,
+		"\"IMPLEMENTATION\" \"ManageSieve\"\r\n");
+    }
     
     /* SASL */
     if ((!authenticated || sasl_ssf) &&
+	(starttls_done || !config_getswitch(IMAPOPT_FORCETLSAUTH)) &&
 	sasl_listmech(saslconn, NULL, 
 		    "\"SASL\" \"", " ", "\"\r\n",
 		    &sasllist,
diff -ur a/timsieved/parser.c b/timsieved/parser.c
--- a/timsieved/parser.c	2015-07-06 02:40:07.000000000 +0200
+++ b/timsieved/parser.c	2015-08-09 15:47:55.153764300 +0200
@@ -187,6 +187,10 @@
       break;
 
   case AUTHENTICATE:
+    if (!starttls_done && config_getswitch(IMAPOPT_FORCETLSAUTH)) {
+      error_msg = "AUTHENTICATE only available under a layer";
+      goto error;
+    }
     if (timlex(NULL, NULL, sieved_in)!=SPACE)
     {
       error_msg = "SPACE must occur after AUTHENTICATE";

Reply via email to