diff --git a/docker/kolab/utils/23-patch-system.sh b/docker/kolab/utils/23-patch-system.sh index 71aa699d..fa1d6849 100755 --- a/docker/kolab/utils/23-patch-system.sh +++ b/docker/kolab/utils/23-patch-system.sh @@ -1,9 +1,9 @@ #!/bin/bash PATCHPATH=$(pwd)/patches pushd /usr/share/roundcubemail/ || exit -patch -p1 -l < "$PATCHPATH/0002-WOAT-support.patch" -patch -p1 -l < "$PATCHPATH/0003-PROXY-protocol-support.patch" +# patch -p1 -l < "$PATCHPATH/0002-WOAT-support.patch" +# patch -p1 -l < "$PATCHPATH/0003-PROXY-protocol-support.patch" popd || exit -systemctl restart httpd +# systemctl restart httpd diff --git a/docker/kolab/utils/patches/0002-WOAT-support.patch b/docker/kolab/utils/patches/0002-WOAT-support.patch deleted file mode 100644 index 0a14f879..00000000 --- a/docker/kolab/utils/patches/0002-WOAT-support.patch +++ /dev/null @@ -1,208 +0,0 @@ -From d140792bdd838fc543128c977bfe47199c914e64 Mon Sep 17 00:00:00 2001 -From: Christian Mollekopf -Date: Thu, 14 Jul 2022 15:03:22 +0200 -Subject: [PATCH 2/3] WOAT support - ---- - plugins/enigma/config.inc.php.dist | 5 ++ - plugins/enigma/lib/enigma_engine.php | 93 +++++++++++++++++++++++-- - program/lib/Roundcube/rcube_message.php | 10 +-- - 3 files changed, 99 insertions(+), 9 deletions(-) - -diff --git a/plugins/enigma/config.inc.php.dist b/plugins/enigma/config.inc.php.dist -index fc620587e..f77ad26a8 100644 ---- a/plugins/enigma/config.inc.php.dist -+++ b/plugins/enigma/config.inc.php.dist -@@ -75,3 +75,8 @@ $config['enigma_password_time'] = 5; - // - enigma_options_lock = array('sign') - // - dont_override = array('enigma_sign_all') - $config['enigma_options_lock'] = array(); -+ -+// Enable Kolab's Web Of Anti-Trust feature -+// Fetches public keys from DNS. Default: false -+// To enable set it to True or an array of domain names. -+$config['enigma_woat'] = false; -diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php -index 4dbb464a5..45c98caef 100644 ---- a/plugins/enigma/lib/enigma_engine.php -+++ b/plugins/enigma/lib/enigma_engine.php -@@ -28,6 +28,7 @@ class enigma_engine - private $pgp_driver; - private $smime_driver; - private $password_time; -+ private $sender; - private $cache = array(); - - public $decryptions = array(); -@@ -267,6 +268,9 @@ class enigma_engine - - $recipients = array_unique($recipients); - -+ // Fetch keys from external sources, if configured -+ $this->sync_keys($recipients); -+ - // find recipient public keys - foreach ((array) $recipients as $email) { - if ($email == $from && $sign_key) { -@@ -377,6 +381,17 @@ class enigma_engine - return; - } - -+ // Get the message/part sender -+ if (!empty($p['object']->sender) && !empty($p['object']->sender['mailto'])) { -+ $this->sender = $p['object']->sender['mailto']; -+ } -+ if (!empty($p['structure']->headers) && !empty($p['structure']->headers['from'])) { -+ $from = rcube_mime::decode_address_list($p['structure']->headers['from'], 1, false); -+ if (($from = current($from)) && !empty($from['mailto'])) { -+ $this->sender = $from['mailto']; -+ } -+ } -+ - // Don't be tempted to support encryption in text/html parts - // Because of EFAIL vulnerability we should never support this (#6289) - -@@ -875,6 +890,11 @@ class enigma_engine - { - // @TODO: Handle big bodies using (temp) files - -+ // Import sender's key from external sources, if configured -+ if ($this->sender) { -+ $this->sync_keys([$this->sender]); -+ } -+ - // Get rid of possible non-ascii characters (#5962) - $sig_body = preg_replace('/[^\x00-\x7F]/', '', $sig_body); - -@@ -899,6 +919,11 @@ class enigma_engine - { - // @TODO: Handle big bodies using (temp) files - -+ // Import sender's key from external sources, if configured -+ if ($this->sender) { -+ $this->sync_keys([$this->sender]); -+ } -+ - // Get rid of possible non-ascii characters (#5962) - $msg_body = preg_replace('/[^\x00-\x7F]/', '', $msg_body); - -@@ -1014,19 +1039,25 @@ class enigma_engine - return; - } - -- $mode = $can_sign ? enigma_key::CAN_SIGN : enigma_key::CAN_ENCRYPT; -- $ret = null; -+ $mode = $can_sign ? enigma_key::CAN_SIGN : enigma_key::CAN_ENCRYPT; -+ $found = []; - - // check key validity and type - foreach ($result as $key) { - if (($subkey = $key->find_subkey($email, $mode)) - && (!$can_sign || $key->get_type() == enigma_key::TYPE_KEYPAIR) - ) { -- $ret = $key; -- break; -+ $found[] = $key; //$found[$subkey->get_creation_date(true)] = $key; - } - } - -+ // Use the most recent one -+ //if (count($found) > 1) { -+ //ksort($found, SORT_NUMERIC); -+ //} -+ -+ $ret = count($found) > 0 ? array_pop($found) : null; -+ - // cache private key info for better performance - // we can skip one list_keys() call when signing and attaching a key - if ($can_sign) { -@@ -1422,4 +1453,58 @@ class enigma_engine - ), true, $abort); - } - } -+ -+ /** -+ * Import public keys from DNS according to Kolab Web-Of-Anti-Trust -+ * -+ * @param array $recipients List of email addresses -+ */ -+ protected function sync_keys($recipients) -+ { -+ $import = []; -+ $woat = $this->rc->config->get('enigma_woat'); -+ -+ if (empty($woat)) { -+ return; -+ } -+ -+ foreach ($recipients as $recipient) { -+ if (!strpos($recipient, '@')) { -+ continue; -+ } -+ -+ list($local, $domain) = explode('@', $recipient); -+ -+ // Do this for configured domains only -+ if (is_array($woat) && !in_array_nocase($domain, $woat)) { -+ continue; -+ } -+ -+ // remove parts behind a recipient delimiter ("jeroen+Trash" => "jeroen") -+ $local = preg_replace('/\+.*$/', '', $local); -+ -+ $fqdn = sha1($local) . '._woat.' . $domain; -+ -+ // Fetch the TXT record(s) -+ if (($records = dns_get_record($fqdn, DNS_TXT)) === false) { -+ continue; -+ } -+ -+ foreach ($records as $record) { -+ if (strpos($record['txt'], 'v=woat1,') === 0) { -+ $entry = explode('public_key=', $record['txt']); -+ if (count($entry) == 2) { -+ $import[] = $entry[1]; -+ // For now we support only one key -+ break; -+ } -+ } -+ } -+ } -+ -+ // Import the fetched keys -+ if (!empty($import)) { -+ $this->import_key(implode("\n", $import)); -+ } -+ } - } -diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php -index 01b0e6dec..d5459bb50 100644 ---- a/program/lib/Roundcube/rcube_message.php -+++ b/program/lib/Roundcube/rcube_message.php -@@ -118,6 +118,11 @@ class rcube_message - false, false, true) - ); - -+ $this->mime = new rcube_mime($this->headers->charset); -+ $this->subject = str_replace("\n", '', $this->headers->get('subject')); -+ $from = $this->mime->decode_address_list($this->headers->from, 1); -+ $this->sender = current($from); -+ - if (!empty($this->headers->structure)) { - $this->get_mime_numbers($this->headers->structure); - $this->parse_structure($this->headers->structure); -@@ -126,11 +131,6 @@ class rcube_message - $this->body = $this->storage->get_body($uid); - } - -- $this->mime = new rcube_mime($this->headers->charset); -- $this->subject = str_replace("\n", '', $this->headers->get('subject')); -- $from = $this->mime->decode_address_list($this->headers->from, 1); -- $this->sender = current($from); -- - // notify plugins and let them analyze this structured message object - $this->app->plugins->exec_hook('message_load', array('object' => $this)); - } --- -2.35.3 - diff --git a/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch b/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch deleted file mode 100644 index 913aba37..00000000 --- a/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch +++ /dev/null @@ -1,148 +0,0 @@ -From f044424f99b8e33dbed1a00127bfcc5ad121d610 Mon Sep 17 00:00:00 2001 -From: Christian Mollekopf -Date: Thu, 14 Jul 2022 15:04:16 +0200 -Subject: [PATCH 3/3] PROXY protocol support - ---- - config/defaults.inc.php | 10 +++ - program/lib/Roundcube/rcube_imap_generic.php | 8 ++ - program/lib/Roundcube/rcube_utils.php | 79 ++++++++++++++++++++ - 3 files changed, 97 insertions(+) - -diff --git a/config/defaults.inc.php b/config/defaults.inc.php -index 20c1c6fd3..f705a47e8 100644 ---- a/config/defaults.inc.php -+++ b/config/defaults.inc.php -@@ -157,12 +157,22 @@ $config['imap_auth_type'] = null; - // IMAP socket context options - // See http://php.net/manual/en/context.ssl.php - // The example below enables server certificate validation -+// -+// proxy_protocol is used to inject HAproxy style headers in the TCP stream -+// See http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt - //$config['imap_conn_options'] = array( - // 'ssl' => array( - // 'verify_peer' => true, - // 'verify_depth' => 3, - // 'cafile' => '/etc/openssl/certs/ca.crt', - // ), -+// 'proxy_protocol' => 1 | 2 | array ( // required (either version number (1|2) or array with 'version' key) -+// 'version' => 1 | 2, // required, if array -+// 'remote_addr' => $_SERVER['REMOTE_ADDR'], -+// 'remote_port' => $_SERVER['REMOTE_PORT'], -+// 'local_addr' => $_SERVER['SERVER_ADDR'], -+// 'local_port' => $_SERVER['SERVER_PORT'], -+// ), - // ); - // Note: These can be also specified as an array of options indexed by hostname - $config['imap_conn_options'] = null; -diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php -index 9a398cdca..270be1201 100644 ---- a/program/lib/Roundcube/rcube_imap_generic.php -+++ b/program/lib/Roundcube/rcube_imap_generic.php -@@ -1035,6 +1035,14 @@ class rcube_imap_generic - return false; - } - -+ // insert proxy protocol header, if enabled -+ if (!empty($this->prefs['socket_options'])) { -+ $proxy_protocol_header = rcube_utils::proxy_protocol_header($this->prefs['socket_options'], $this->fp); -+ if (strlen($proxy_protocol_header) > 0) { -+ fwrite($this->fp, $proxy_protocol_header); -+ } -+ } -+ - if ($this->prefs['timeout'] > 0) { - stream_set_timeout($this->fp, $this->prefs['timeout']); - } -diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php -index d4273526b..3ad6422cb 100644 ---- a/program/lib/Roundcube/rcube_utils.php -+++ b/program/lib/Roundcube/rcube_utils.php -@@ -1458,4 +1458,83 @@ class rcube_utils - - return $temp_path; - } -+ -+ /** -+ * When proxy_protocol is configured for a connection type, -+ * generate the HAproxy style PROXY protocol header for injection -+ * into the TCP stream. -+ * http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt -+ * -+ * PROXY protocol headers must be sent before any other data is sent on the TCP socket. -+ * -+ * @param array $conn_options preferences array which may contain proxy_protocol (generally {driver}_conn_options) -+ * -+ * @return string proxy protocol header data, if enabled, otherwise empty string -+ */ -+ public static function proxy_protocol_header($conn_options = null) -+ { -+ if ($conn_options === null) -+ { -+ return ""; -+ } -+ // verify that proxy_protocol option is present -+ if (is_array($conn_options) && array_key_exists('proxy_protocol', $conn_options)) { -+ if (is_array($conn_options['proxy_protocol'])) { -+ $proxy_protocol_version = $conn_options['proxy_protocol']['version']; -+ $proxy_protocol_options = $conn_options['proxy_protocol']; -+ } -+ else { -+ $proxy_protocol_version = $conn_options['proxy_protocol']; -+ $proxy_protocol_options = null; -+ } -+ -+ $proxy_protocol_remote_addr = (array_key_exists('remote_addr', $proxy_protocol_options) ? $proxy_protocol_options['remote_addr'] : self::remote_addr() ); -+ $proxy_protocol_remote_port = (array_key_exists('remote_port', $proxy_protocol_options) ? $proxy_protocol_options['remote_port'] : $_SERVER['REMOTE_PORT'] ); -+ $proxy_protocol_local_addr = (array_key_exists('local_addr' ,$proxy_protocol_options) ? $proxy_protocol_options['local_addr'] : $_SERVER['SERVER_ADDR'] ); -+ $proxy_protocol_local_port = (array_key_exists('local_port', $proxy_protocol_options) ? $proxy_protocol_options['local_port'] : $_SERVER['SERVER_PORT'] ); -+ $proxy_protocol_ip_version = (strpos($proxy_protocol_remote_addr, ":") === false ? 4 : 6); -+ -+ if ($proxy_protocol_version === 1) { -+ // text based PROXY protocol -+ -+ // PROXY protocol does not support dual IPv6+IPv4 type addresses, e.g. ::127.0.0.1 -+ if ($proxy_protocol_ip_version === 6 && strpos($proxy_protocol_remote_addr, ".") !== false) { -+ $proxy_protocol_remote_addr = inet_ntop(inet_pton($proxy_protocol_remote_addr)); -+ } -+ if ($proxy_protocol_ip_version === 6 && strpos($proxy_protocol_local_addr, ".") !== false) { -+ $proxy_protocol_local_addr = inet_ntop(inet_pton($proxy_protocol_local_addr)); -+ } -+ -+ $proxy_protocol_text = "PROXY " . // protocol header -+ ($proxy_protocol_ip_version === 6 ? "TCP6 " : "TCP4 ") . // IP version type -+ $proxy_protocol_remote_addr . -+ " " . -+ $proxy_protocol_local_addr . -+ " " . -+ $proxy_protocol_remote_port . -+ " " . -+ $proxy_protocol_local_port . -+ "\r\n"; -+ return $proxy_protocol_text; -+ } -+ else if ($proxy_protocol_version === 2) { -+ // binary PROXY protocol -+ $proxy_protocol_bin = pack("H*", "0D0A0D0A000D0A515549540A" . // protocol header -+ "21" . // protocol version and command -+ ($proxy_protocol_ip_version === 6 ? "2" : "1") . // IP version type -+ "1"); // TCP -+ $proxy_protocol_addr = inet_pton($proxy_protocol_remote_addr) . -+ inet_pton($proxy_protocol_local_addr) . -+ pack("n", $proxy_protocol_remote_port) . -+ pack("n", $proxy_protocol_local_port); -+ $proxy_protocol_bin .= pack("n", strlen($proxy_protocol_addr)) . $proxy_protocol_addr; -+ return $proxy_protocol_bin; -+ } -+ else { -+ // unknown proxy protocol version -+ return ""; -+ } -+ } -+ return ""; -+ } - } --- -2.35.3 -