Re: exim4 upload to stable (dovecot stability / and optionally spf quoting)
On 2013-01-06 "Adam D. Barratt" <adam@adam-barratt.org.uk> wrote:
[...]
> In principle the fixes sound okay but a debdiff between stable (well,
> p-u, as that has +squeeze3) and the proposed package would be
> appreciated.
There you go ...
cu andreas
--
`What a good friend you are to him, Dr. Maturin. His other friends are
so grateful to you.'
`I sew his ears on from time to time, sure'
===============================================================================
exim4
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-base
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-1672-] {+1644+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-config
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-1272-] {+1256+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-daemon-heavy
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-1148-] {+1136+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-daemon-heavy-dbg
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-1936-] {+1924+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-daemon-light
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-1040-] {+1028+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-daemon-light-dbg
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-1736-] {+1724+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-dbg
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-688-] {+664+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
exim4-dev
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-244-] {+236+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
===============================================================================
eximon4
==============================================================================
File lists identical (after any substitutions)
Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-304-] {+292+}
Version: [-4.72-6+squeeze3-] {+4.72-6+squeeze4+}
diff -Nru exim4-4.72/debian/changelog exim4-4.72/debian/changelog
--- exim4-4.72/debian/changelog 2012-10-25 19:43:49.000000000 +0200
+++ exim4-4.72/debian/changelog 2013-01-12 11:23:38.000000000 +0100
@@ -1,3 +1,13 @@
+exim4 (4.72-6+squeeze4) stable; urgency=low
+
+ * Cherrypick [86_Dovecot-robustness.diff] from upstream GIT, a
+ robustness fix for the Dovecot authenticator.
+ * Use exim's ${quote:xxx} operator when invoking spfquery to disallow
+ bypassing of SPF validation by using special mailbox names. (Thanks to
+ Lekensteyn for diagnosis and testing.) Closes: #697057
+
+ -- Andreas Metzler <ametzler@debian.org> Sat, 12 Jan 2013 11:22:07 +0100
+
exim4 (4.72-6+squeeze3) stable-security; urgency=high
* Non-maintainer upload by the Security Team.
diff -Nru exim4-4.72/debian/debconf/conf.d/acl/30_exim4-config_check_rcpt exim4-4.72/debian/debconf/conf.d/acl/30_exim4-config_check_rcpt
--- exim4-4.72/debian/debconf/conf.d/acl/30_exim4-config_check_rcpt 2011-01-22 17:01:08.000000000 +0100
+++ exim4-4.72/debian/debconf/conf.d/acl/30_exim4-config_check_rcpt 2013-01-12 11:17:10.000000000 +0100
@@ -254,10 +254,10 @@
log_message = SPF check failed.
!acl = acl_local_deny_exceptions
condition = ${run{/usr/bin/spfquery.mail-spf-perl --ip \
- \"$sender_host_address\" --identity \
+ ${quote:$sender_host_address} --identity \
${if def:sender_address_domain \
- {--scope mfrom --identity \"$sender_address\"}\
- {--scope helo --identity \"$sender_helo_name\"}}}\
+ {--scope mfrom --identity ${quote:$sender_address}}\
+ {--scope helo --identity ${quote:$sender_helo_name}}}}\
{no}{${if eq {$runrc}{1}{yes}{no}}}}
defer
message = Temporary DNS error while checking SPF record. Try again later.
diff -Nru exim4-4.72/debian/patches/86_Dovecot-robustness.diff exim4-4.72/debian/patches/86_Dovecot-robustness.diff
--- exim4-4.72/debian/patches/86_Dovecot-robustness.diff 1970-01-01 01:00:00.000000000 +0100
+++ exim4-4.72/debian/patches/86_Dovecot-robustness.diff 2013-01-12 12:03:59.000000000 +0100
@@ -0,0 +1,308 @@
+From 3f1df0e341c4ddc4add38fa97d9d34972655a6c7 Mon Sep 17 00:00:00 2001
+From: Phil Pennock <pdp@exim.org>
+Date: Mon, 19 Nov 2012 23:44:33 -0500
+Subject: [PATCH] Dovecot: robustness; better msg on missing mech.
+
+If the dovecot protocol response doesn't include the MECH message for
+the SMTP AUTH protocol the client has requested, that's not a protocol
+failure, don't log it as such. Instead, explicitly log that it didn't
+advertise the mechanism we're looking for. This lets administrators fix
+either their Exim or their Dovecot configurations.
+
+Also: make the Dovecot handling more resistant to bad data from the auth
+server; handle too many fields with debug-log message to explain what's
+going on, permit lines of 8192 length per spec and detect if the line is
+too long, so that we can fail auth instead of becoming unsynchronised.
+
+Stop using the CUID from the server as the AUTH id counter. They're
+different, by my reading of the spec.
+
+TESTED: works against Dovecot 2.1.10.
+
+Thanks to Brady Catherman for reporting the problem with diagnosis.
+---
+
+diff --git a/src/auths/dovecot.c b/src/auths/dovecot.c
+index 0824240..032a089 100644
+--- a/src/auths/dovecot.c
++++ b/src/auths/dovecot.c
+@@ -12,12 +12,42 @@ commented them specially, but now they are getting quite extensive, so I have
+ ceased doing that. The biggest change is to use unbuffered I/O on the socket
+ because using C buffered I/O gives problems on some operating systems. PH */
+
++/* Protocol specifications:
++ * Dovecot 1, protocol version 1.1
++ * http://wiki.dovecot.org/Authentication%20Protocol
++ *
++ * Dovecot 2, protocol version 1.1
++ * http://wiki2.dovecot.org/Design/AuthProtocol
++ */
++
+ #include "../exim.h"
+ #include "dovecot.h"
+
+ #define VERSION_MAJOR 1
+ #define VERSION_MINOR 0
+
++/* http://wiki.dovecot.org/Authentication%20Protocol
++"The maximum line length isn't defined,
++ but it's currently expected to fit into 8192 bytes"
++*/
++#define DOVECOT_AUTH_MAXLINELEN 8192
++
++/* This was hard-coded as 8.
++AUTH req C->S sends {"AUTH", id, mechanism, service } + params, 5 defined for
++Dovecot 1; Dovecot 2 (same protocol version) defines 9.
++
++Master->Server sends {"USER", id, userid} + params, 6 defined.
++Server->Client only gives {"OK", id} + params, unspecified, only 1 guaranteed.
++
++We only define here to accept S->C; max seen is 3+<unspecified>, plus the two
++for the command and id, where unspecified might include _at least_ user=...
++
++So: allow for more fields than we ever expect to see, while aware that count
++can go up without changing protocol version.
++The cost is the length of an array of pointers on the stack.
++*/
++#define DOVECOT_AUTH_MAXFIELDCOUNT 16
++
+ /* Options specific to the authentication mechanism. */
+ optionlist auth_dovecot_options[] = {
+ {
+@@ -43,7 +73,7 @@ auth_dovecot_options_block auth_dovecot_option_defaults = {
+ /* Static variables for reading from the socket */
+
+ static uschar sbuffer[256];
+-static int sbp;
++static int socket_buffer_left;
+
+
+
+@@ -67,9 +97,28 @@ void auth_dovecot_init(auth_instance *ablock)
+ ablock->client = FALSE;
+ }
+
+-static int strcut(uschar *str, uschar **ptrs, int nptrs)
++/*************************************************
++ * "strcut" to split apart server lines *
++ *************************************************/
++
++/* Dovecot auth protocol uses TAB \t as delimiter; a line consists
++of a command-name, TAB, and then any parameters, each separated by a TAB.
++A parameter can be param=value or a bool, just param.
++
++This function modifies the original str in-place, inserting NUL characters.
++It initialises ptrs entries, setting all to NULL and only setting
++non-NULL N entries, where N is the return value, the number of fields seen
++(one more than the number of tabs).
++
++Note that the return value will always be at least 1, is the count of
++actual fields (so last valid offset into ptrs is one less).
++*/
++
++static int
++strcut(uschar *str, uschar **ptrs, int nptrs)
+ {
+- uschar *tmp = str;
++ uschar *last_sub_start = str;
++ uschar *lastvalid = str + Ustrlen(str);
+ int n;
+
+ for (n = 0; n < nptrs; n++)
+@@ -79,19 +128,44 @@ static int strcut(uschar *str, uschar **ptrs, int nptrs)
+ while (*str) {
+ if (*str == '\t') {
+ if (n <= nptrs) {
+- *ptrs++ = tmp;
+- tmp = str + 1;
+- *str = 0;
++ *ptrs++ = last_sub_start;
++ last_sub_start = str + 1;
++ *str = '\0';
+ }
+ n++;
+ }
+ str++;
+ }
+
+- if (n < nptrs)
+- *ptrs = tmp;
++ if (last_sub_start < lastvalid) {
++ if (n <= nptrs) {
++ *ptrs = last_sub_start;
++ } else {
++ HDEBUG(D_auth) debug_printf("dovecot: warning: too many results from tab-splitting; saw %d fields, room for %d\n", n, nptrs);
++ n = nptrs;
++ }
++ } else {
++ n--;
++ HDEBUG(D_auth) debug_printf("dovecot: warning: ignoring trailing tab\n");
++ }
++
++ return n <= nptrs ? n : nptrs;
++}
+
+- return n;
++static void debug_strcut(uschar **ptrs, int nlen, int alen);
++static void
++debug_strcut(uschar **ptrs, int nlen, int alen)
++{
++ int i;
++ debug_printf("%d read but unreturned bytes; strcut() gave %d results: ",
++ socket_buffer_left, nlen);
++ for (i = 0; i < nlen; i++) {
++ debug_printf(" {%s}", ptrs[i]);
++ }
++ if (nlen < alen)
++ debug_printf(" last is %s\n", ptrs[i] ? ptrs[i] : US"<null>");
++ else
++ debug_printf(" (max for capacity)\n");
+ }
+
+ #define CHECK_COMMAND(str, arg_min, arg_max) do { \
+@@ -125,27 +199,27 @@ int count = 0;
+
+ for (;;)
+ {
+- if (sbp == 0)
++ if (socket_buffer_left == 0)
+ {
+- sbp = read(fd, sbuffer, sizeof(sbuffer));
+- if (sbp == 0) { if (count == 0) return NULL; else break; }
++ socket_buffer_left = read(fd, sbuffer, sizeof(sbuffer));
++ if (socket_buffer_left == 0) { if (count == 0) return NULL; else break; }
+ p = 0;
+ }
+
+- while (p < sbp)
++ while (p < socket_buffer_left)
+ {
+ if (count >= n - 1) break;
+ s[count++] = sbuffer[p];
+ if (sbuffer[p++] == '\n') break;
+ }
+
+- memmove(sbuffer, sbuffer + p, sbp - p);
+- sbp -= p;
++ memmove(sbuffer, sbuffer + p, socket_buffer_left - p);
++ socket_buffer_left -= p;
+
+ if (s[count-1] == '\n' || count >= n - 1) break;
+ }
+
+-s[count] = 0;
++s[count] = '\0';
+ return s;
+ }
+
+@@ -161,12 +235,14 @@ int auth_dovecot_server(auth_instance *ablock, uschar *data)
+ auth_dovecot_options_block *ob =
+ (auth_dovecot_options_block *)(ablock->options_block);
+ struct sockaddr_un sa;
+- uschar buffer[4096];
+- uschar *args[8];
++ uschar buffer[DOVECOT_AUTH_MAXLINELEN];
++ uschar *args[DOVECOT_AUTH_MAXFIELDCOUNT];
+ uschar *auth_command;
+ uschar *auth_extra_data = US"";
++ uschar *p;
+ int nargs, tmp;
+- int cuid = 0, cont = 1, found = 0, fd, ret = DEFER;
++ int crequid = 1, cont = 1, fd, ret = DEFER;
++ BOOL found = FALSE;
+
+ HDEBUG(D_auth) debug_printf("dovecot authentication\n");
+
+@@ -198,37 +274,46 @@ int auth_dovecot_server(auth_instance *ablock, uschar *data)
+
+ auth_defer_msg = US"authentication socket protocol error";
+
+- sbp = 0; /* Socket buffer pointer */
++ socket_buffer_left = 0; /* Global, used to read more than a line but return by line */
+ while (cont) {
+ if (dc_gets(buffer, sizeof(buffer), fd) == NULL)
+ OUT("authentication socket read error or premature eof");
+-
+- buffer[Ustrlen(buffer) - 1] = 0;
++ p = buffer + Ustrlen(buffer) - 1;
++ if (*p != '\n') {
++ OUT("authentication socket protocol line too long");
++ }
++ *p = '\0';
+ HDEBUG(D_auth) debug_printf("received: %s\n", buffer);
+ nargs = strcut(buffer, args, sizeof(args) / sizeof(args[0]));
++ /* HDEBUG(D_auth) debug_strcut(args, nargs, sizeof(args) / sizeof(args[0])); */
+
+ /* Code below rewritten by Kirill Miazine (km@krot.org). Only check commands that
+ Exim will need. Original code also failed if Dovecot server sent unknown
+ command. E.g. COOKIE in version 1.1 of the protocol would cause troubles. */
+- if (Ustrcmp(args[0], US"CUID") == 0) {
+- CHECK_COMMAND("CUID", 1, 1);
+- cuid = Uatoi(args[1]);
+- } else if (Ustrcmp(args[0], US"VERSION") == 0) {
++ /* pdp: note that CUID is a per-connection identifier sent by the server,
++ which increments at server discretion.
++ By contrast, the "id" field of the protocol is a connection-specific request
++ identifier, which needs to be unique per request from the client and is not
++ connected to the CUID value, so we ignore CUID from server. It's purely for
++ diagnostics. */
++ if (Ustrcmp(args[0], US"VERSION") == 0) {
+ CHECK_COMMAND("VERSION", 2, 2);
+ if (Uatoi(args[1]) != VERSION_MAJOR)
+ OUT("authentication socket protocol version mismatch");
+ } else if (Ustrcmp(args[0], US"MECH") == 0) {
+ CHECK_COMMAND("MECH", 1, INT_MAX);
+ if (strcmpic(US args[1], ablock->public_name) == 0)
+- found = 1;
++ found = TRUE;
+ } else if (Ustrcmp(args[0], US"DONE") == 0) {
+ CHECK_COMMAND("DONE", 0, 0);
+ cont = 0;
+ }
+ }
+
+- if (!found)
++ if (!found) {
++ auth_defer_msg = string_sprintf("Dovecot did not advertise mechanism \"%s\" to us", ablock->public_name);
+ goto out;
++ }
+
+ /* Added by PH: data must not contain tab (as it is
+ b64 it shouldn't, but check for safety). */
+@@ -264,14 +349,11 @@ int auth_dovecot_server(auth_instance *ablock, uschar *data)
+
+ Subsequently, the command was modified to add "secured" and "valid-client-
+ cert" when relevant.
+-
+- The auth protocol is documented here:
+- http://wiki.dovecot.org/Authentication_Protocol
+ ****************************************************************************/
+
+ auth_command = string_sprintf("VERSION\t%d\t%d\nCPID\t%d\n"
+ "AUTH\t%d\t%s\tservice=smtp\t%srip=%s\tlip=%s\tnologin\tresp=%s\n",
+- VERSION_MAJOR, VERSION_MINOR, getpid(), cuid,
++ VERSION_MAJOR, VERSION_MINOR, getpid(), crequid,
+ ablock->public_name, auth_extra_data, sender_host_address,
+ interface_address, data ? (char *) data : "");
+
+@@ -295,7 +377,7 @@ int auth_dovecot_server(auth_instance *ablock, uschar *data)
+ HDEBUG(D_auth) debug_printf("received: %s\n", buffer);
+ nargs = strcut(buffer, args, sizeof(args) / sizeof(args[0]));
+
+- if (Uatoi(args[1]) != cuid)
++ if (Uatoi(args[1]) != crequid)
+ OUT("authentication socket connection id mismatch");
+
+ switch (toupper(*args[0])) {
+@@ -316,7 +398,7 @@ int auth_dovecot_server(auth_instance *ablock, uschar *data)
+ goto out;
+ }
+
+- temp = string_sprintf("CONT\t%d\t%s\n", cuid, data);
++ temp = string_sprintf("CONT\t%d\t%s\n", crequid, data);
+ if (write(fd, temp, Ustrlen(temp)) < 0)
+ OUT("authentication socket write error");
+ break;
+--
+1.7.10.4
+
diff -Nru exim4-4.72/debian/patches/series exim4-4.72/debian/patches/series
--- exim4-4.72/debian/patches/series 2012-10-25 20:00:21.000000000 +0200
+++ exim4-4.72/debian/patches/series 2013-01-12 12:03:36.000000000 +0100
@@ -24,3 +24,4 @@
82_dkimpercent.diff
83_dkimexpand.diff
84_CVE-2012-5671.patch
+86_Dovecot-robustness.diff
Reply to: