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 <[email protected]>
To: [email protected]
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";