Add STARTTLS support to SMTPMailSender
authorTim Düsterhus <duesterhus@woltlab.com>
Mon, 14 Apr 2014 16:00:32 +0000 (18:00 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Mon, 28 Apr 2014 19:17:12 +0000 (21:17 +0200)
wcfsetup/install/files/lib/system/io/RemoteFile.class.php
wcfsetup/install/files/lib/system/mail/SMTPMailSender.class.php

index 415cc8d32532bf03ccf4fbaed3139612e69376d3..4ff441d42c0d00f125dd834748caaa0ab30b4533 100644 (file)
@@ -72,4 +72,26 @@ class RemoteFile extends File {
        public function getErrorDesc() {
                return $this->errorDesc;
        }
+       
+       /**
+        * Switches TLS support for this connection.
+        * Usually used in combination with 'STARTTLS'
+        * 
+        * @param       boolean $enable         Whether TLS support should be enabled
+        * @return      boolean                 True on success, false otherwise
+        */
+       public function setTLS($enable) {
+               if (!$this->hasTLSSupport()) return false;
+               
+               return stream_socket_enable_crypto($this->resource, $enable, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+       }
+       
+       /**
+        * Returns whether TLS support is available.
+        * 
+        * @return      boolean
+        */
+       public function hasTLSSupport() {
+               return function_exists('stream_socket_enable_crypto');
+       }
 }
index 772903b191dc966ee617b7f8f67672592c2dc7cd..52b7ed03a982935166863aa5c0488a9d2fed5774 100644 (file)
@@ -7,7 +7,7 @@ use wcf\util\StringUtil;
 /**
  * Sends a Mail with a connection to a smtp server.
  * 
- * @author     Alexander Ebert
+ * @author     Tim Duesterhus, Alexander Ebert
  * @copyright  2001-2014 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    com.woltlab.wcf
@@ -74,8 +74,35 @@ class SMTPMailSender extends MailSender {
                
                // send ehlo
                $this->write('EHLO '.$host);
-               $this->getSMTPStatus();
+               $extensions = explode(Mail::$lineEnding, $this->read());
+               $this->getSMTPStatus(array_shift($extensions));
                if ($this->statusCode == 250) {
+                       $extensions = array_map(function($element) {
+                               return strtolower(substr($element, 4));
+                       }, $extensions);
+                       
+                       if ($this->connection->hasTLSSupport() && in_array('starttls', $extensions)) {
+                               $this->write('STARTTLS');
+                               $this->getSMTPStatus();
+                               
+                               if ($this->statusCode != 220) {
+                                       throw new SystemException($this->formatError("cannot enable STARTTLS, though '".MAIL_SMTP_HOST.":".MAIL_SMTP_PORT."' advertised it"));
+                               }
+                               
+                               if (!$this->connection->setTLS(true)) {
+                                       throw new SystemException('enabling TLS failed');
+                               }
+                               
+                               // repeat EHLO
+                               $this->write('EHLO '.$host);
+                               $extensions = explode(Mail::$lineEnding, $this->read());
+                               $this->getSMTPStatus(array_shift($extensions));
+                               
+                               if ($this->statusCode != 250) {
+                                       throw new SystemException($this->formatError("could not EHLO after enabling STARTTLS at '".MAIL_SMTP_HOST.":".MAIL_SMTP_PORT."'"));
+                               }
+                       }
+                       
                        // do authentication
                        if (MAIL_SMTP_USER != '' || MAIL_SMTP_PASSWORD != '') {
                                $this->auth();
@@ -237,6 +264,7 @@ class SMTPMailSender extends MailSender {
                        $result .= $read;
                        if (substr($read, 3, 1) == " ") break;
                }
+               
                return $result;
        }