From a86d9cd5aa19694b2a99c5971359e46731503e4b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 24 Oct 2018 11:17:02 +0200 Subject: [PATCH 1/3] Fix so unicode in local part of the email address is also supported in recipient inputs (#6490) Relax javascript email address checker. --- CHANGELOG | 1 + program/js/common.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 103bc6770..399f1449f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ CHANGELOG Roundcube Webmail - Elastic: Improved UX of search dialogs (#6416) - Elastic: Fix unwanted thread expanding when selecting a collapsed thread in non-mobile mode (#6445) - Log errors caused by low pcre.backtrack_limit when sending a mail message (#6433) +- Fix so unicode in local part of the email address is also supported in recipient inputs (#6490) - Fix bug where autocomplete list could be displayed out of screen (#6469) - Fix style/navigation on error page depending on authentication state (#6362) - Fix so invalid smtp_helo_host is never used, fallback to localhost (#6408) diff --git a/program/js/common.js b/program/js/common.js index 406ca23a4..1422042ad 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -402,7 +402,7 @@ triggerEvent: function(evt, e) // check if input is a valid email address // By Cal Henderson // http://code.iamcal.com/php/rfc822/ -function rcube_check_email(input, inline, count) +function rcube_check_email(input, inline, count, strict) { if (!input) return count ? 0 : false; @@ -438,7 +438,7 @@ function rcube_check_email(input, inline, count) '\\u05d1\\u05f2\\u05b7\\u05e9\\u05e4\\u05bc\\u05d9\\u05dc\\x2e\\u05d8\\u05e2\\u05e1\\u05d8' ], icann_addr = 'mailtest\\x40('+icann_domains.join('|')+')', - word = '('+atom+'|'+quoted_string+')', + word = strict ? '('+atom+'|'+quoted_string+')' : '[^\\u0000-\\u0020\\u002e\\u00a0\\u0040\\u007f\\u2028\\u2029]+', delim = '[,;\\s\\n]', local_part = word+'(\\x2e'+word+')*', addr_spec = '(('+local_part+'\\x40'+domain+')|('+icann_addr+'))', From c4916a8fe3f81a190e919491f1e8ca8f482112e9 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 24 Oct 2018 12:13:13 +0200 Subject: [PATCH 2/3] Simplify code that uses setError() followed by return --- program/lib/Roundcube/rcube_imap_generic.php | 32 ++++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 6c637b90f..80bd9caa2 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -405,6 +405,8 @@ class rcube_imap_generic { $this->errornum = $code; $this->error = $msg; + + return $code; } /** @@ -522,9 +524,8 @@ class rcube_imap_generic { if ($type == 'CRAM-MD5' || $type == 'DIGEST-MD5') { if ($type == 'DIGEST-MD5' && !class_exists('Auth_SASL')) { - $this->setError(self::ERROR_BYE, + return $this->setError(self::ERROR_BYE, "The Auth_SASL package is required for DIGEST-MD5 authentication"); - return self::ERROR_BAD; } $this->putLine($this->nextTag() . " AUTHENTICATE $type"); @@ -596,9 +597,8 @@ class rcube_imap_generic $challenge = substr($line, 2); $challenge = base64_decode($challenge); if (strpos($challenge, 'rspauth=') === false) { - $this->setError(self::ERROR_BAD, + return $this->setError(self::ERROR_BAD, "Unexpected response from server to DIGEST-MD5 response"); - return self::ERROR_BAD; } $this->putLine(''); @@ -609,21 +609,18 @@ class rcube_imap_generic } else if ($type == 'GSSAPI') { if (!extension_loaded('krb5')) { - $this->setError(self::ERROR_BYE, + return $this->setError(self::ERROR_BYE, "The krb5 extension is required for GSSAPI authentication"); - return self::ERROR_BAD; } if (empty($this->prefs['gssapi_cn'])) { - $this->setError(self::ERROR_BYE, + return $this->setError(self::ERROR_BYE, "The gssapi_cn parameter is required for GSSAPI authentication"); - return self::ERROR_BAD; } if (empty($this->prefs['gssapi_context'])) { - $this->setError(self::ERROR_BYE, + return $this->setError(self::ERROR_BYE, "The gssapi_context parameter is required for GSSAPI authentication"); - return self::ERROR_BAD; } putenv('KRB5CCNAME=' . $this->prefs['gssapi_cn']); @@ -640,8 +637,7 @@ class rcube_imap_generic } catch (Exception $e) { trigger_error($e->getMessage(), E_USER_WARNING); - $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); - return self::ERROR_BAD; + return $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); } $this->putLine($this->nextTag() . " AUTHENTICATE GSSAPI " . $token); @@ -658,8 +654,7 @@ class rcube_imap_generic } catch (Exception $e) { trigger_error($e->getMessage(), E_USER_WARNING); - $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); - return self::ERROR_BAD; + return $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); } $this->putLine(base64_encode($challenge)); @@ -726,13 +721,11 @@ class rcube_imap_generic if ($line && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { $this->parseCapability($matches[1], true); } + return $this->fp; } - else { - $this->setError($result, "AUTHENTICATE $type: $line"); - } - return $result; + return $this->setError($result, "AUTHENTICATE $type: $line"); } /** @@ -747,8 +740,7 @@ class rcube_imap_generic { // Prevent from sending credentials in plain text when connection is not secure if ($this->getCapability('LOGINDISABLED')) { - $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); - return false; + return $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); } list($code, $response) = $this->execute('LOGIN', array( From 3dad8c590824dae10194020a25d59201e565f586 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 24 Oct 2018 12:29:50 +0200 Subject: [PATCH 3/3] Fix incorrect IMAP SASL GSSAPI negotiation (#6308) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap_generic.php | 29 +++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 399f1449f..7cb49a088 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ CHANGELOG Roundcube Webmail - Elastic: Improved UX of search dialogs (#6416) - Elastic: Fix unwanted thread expanding when selecting a collapsed thread in non-mobile mode (#6445) - Log errors caused by low pcre.backtrack_limit when sending a mail message (#6433) +- Fix incorrect IMAP SASL GSSAPI negotiation (#6308) - Fix so unicode in local part of the email address is also supported in recipient inputs (#6490) - Fix bug where autocomplete list could be displayed out of screen (#6469) - Fix style/navigation on error page depending on authentication state (#6362) diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 80bd9caa2..612265047 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -648,16 +648,37 @@ class rcube_imap_generic } try { - $challenge = base64_decode(substr($line, 2)); - $gssapicontext->unwrap($challenge, $challenge); - $gssapicontext->wrap($challenge, $challenge, true); + $itoken = base64_decode(substr($line, 2)); + + if (!$gssapicontext->unwrap($itoken, $itoken)) { + throw new Exception("GSSAPI SASL input token unwrap failed"); + } + + if (strlen($itoken) < 4) { + throw new Exception("GSSAPI SASL input token invalid"); + } + + // Integrity/encryption layers are not supported. The first bit + // indicates that the server supports "no security layers". + // 0x00 should not occur, but support broken implementations. + $server_layers = ord($itoken[0]); + if ($server_layers && ($server_layers & 0x1) != 0x1) { + throw new Exception("Server requires GSSAPI SASL integrity/encryption"); + } + + // Construct output token. 0x01 in the first octet = SASL layer "none", + // zero in the following three octets = no data follows. + // See https://github.com/cyrusimap/cyrus-sasl/blob/e41cfb986c1b1935770de554872247453fdbb079/plugins/gssapi.c#L1284 + if (!$gssapicontext->wrap(pack("CCCC", 0x1, 0, 0, 0), $otoken, true)) { + throw new Exception("GSSAPI SASL output token wrap failed"); + } } catch (Exception $e) { trigger_error($e->getMessage(), E_USER_WARNING); return $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); } - $this->putLine(base64_encode($challenge)); + $this->putLine(base64_encode($otoken)); $line = $this->readReply(); $result = $this->parseResult($line);