[prev in list] [next in list] [prev in thread] [next in thread] 

List:       squirrelmail-cvs
Subject:    [SM-CVS] SF.net SVN: squirrelmail:[14530] branches/SM-1_4-STABLE/squirrelmail/class/ deliver/Deliver
From:       pdontthink () users ! sourceforge ! net
Date:       2015-11-30 23:23:08
Message-ID: E1a3Xmp-0005Ym-Hg () sfs-ml-1 ! v29 ! ch3 ! sourceforge ! com
[Download RAW message or body]

Revision: 14530
          http://sourceforge.net/p/squirrelmail/code/14530
Author:   pdontthink
Date:     2015-11-30 23:23:07 +0000 (Mon, 30 Nov 2015)
Log Message:
-----------
Add STARTTLS support for SMTP connections

Modified Paths:
--------------
    branches/SM-1_4-STABLE/squirrelmail/class/deliver/Deliver_SMTP.class.php

Modified: branches/SM-1_4-STABLE/squirrelmail/class/deliver/Deliver_SMTP.class.php
===================================================================
--- branches/SM-1_4-STABLE/squirrelmail/class/deliver/Deliver_SMTP.class.php	2015-11-30 \
                22:54:16 UTC (rev 14529)
+++ branches/SM-1_4-STABLE/squirrelmail/class/deliver/Deliver_SMTP.class.php	2015-11-30 \
23:23:07 UTC (rev 14530) @@ -20,6 +20,29 @@
  */
 class Deliver_SMTP extends Deliver {
 
+    /**
+     * Array keys are uppercased ehlo keywords
+     * array key values are ehlo params. If ehlo-param contains space, it is \
splitted into array.  +     * @var array ehlo
+     * @since 1.4.23 and 1.5.1
+     */
+    var $ehlo = array();
+
+    /**
+     * @var string domain
+     * @since 1.4.23 and 1.5.1
+     */
+    var $domain = '';
+
+    /**
+     * SMTP STARTTLS rfc: "Both the client and the server MUST know if there 
+     * is a TLS session active."
+     * Variable should be set to true, when encryption is turned on.
+     * @var boolean
+     * @since 1.4.23 and 1.5.1 
+     */
+    var $tls_enabled = false;
+
     function preWriteToStream(&$s) {
         if ($s) {
             if ($s{0} == '.')   $s = '.' . $s;
@@ -55,32 +78,52 @@
             $from->mailbox = '';
         }
 
+        // for backward compatibility: boolean $use_smtp_tls set
+        // to TRUE means to use plain TLS (as opposed to STARTTLS)
+        //
+        if ($use_smtp_tls === TRUE)
+            $use_smtp_tls = 1;
+
         // NB: Using "ssl://" ensures the highest possible TLS version
         // will be negotiated with the server (whereas "tls://" only
         // uses TLS version 1.0)
         //
-        if (($use_smtp_tls == true) and (check_php_version(4,3)) and \
                (extension_loaded('openssl'))) {
-            if (function_exists('stream_socket_client')) {
-                $server_address = 'ssl://' . $host . ':' . $port;
-                $ssl_context = @stream_context_create($stream_options);
-                $connect_timeout = ini_get('default_socket_timeout');
-                // null timeout is broken
-                if ($connect_timeout == 0)
-                    $connect_timeout = 30;
-                $stream = @stream_socket_client($server_address, $errorNumber, \
$errorString, $connect_timeout, STREAM_CLIENT_CONNECT, $ssl_context); +        if \
($use_smtp_tls == 1) { +            if ((check_php_version(4,3)) && \
(extension_loaded('openssl'))) { +                if \
(function_exists('stream_socket_client')) { +                    $server_address = \
'ssl://' . $host . ':' . $port; +                    $ssl_context = \
@stream_context_create($stream_options); +                    $connect_timeout = \
ini_get('default_socket_timeout'); +                    // null timeout is broken
+                    if ($connect_timeout == 0)
+                        $connect_timeout = 30;
+                    $stream = @stream_socket_client($server_address, $errorNumber, \
$errorString, $connect_timeout, STREAM_CLIENT_CONNECT, $ssl_context); +               \
} else { +                    $stream = @fsockopen('ssl://' . $host, $port, \
$errorNumber, $errorString);   +                }
+                $this->tls_enabled = true;
             } else {
-                $stream = @fsockopen('ssl://' . $host, $port, $errorNumber, \
$errorString); +                /**
+                 * don't connect to server when user asks for smtps and 
+                 * PHP does not support it.
+                 */
+                $errorNumber = '';
+                $errorString = _("Secure SMTP (TLS) is enabled in SquirrelMail \
configuration, but used PHP version does not support it.");  }
         } else {
             $stream = @fsockopen($host, $port, $errorNumber, $errorString);
         }
 
         if (!$stream) {
+            // reset tls state var to default value, if connection fails
+            $this->tls_enabled = false;
+            // set error messages
             $this->dlv_msg = $errorString;
             $this->dlv_ret_nr = $errorNumber;
             $this->dlv_server_msg = _("Can't open SMTP stream.");
             return(0);
         }
+        // get server greeting
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return(0);
@@ -110,7 +153,8 @@
 
         /* Lets introduce ourselves */
         fputs($stream, "EHLO $helohost\r\n");
-        $tmp = fgets($stream,1024);
+        // Read ehlo response
+        $tmp = $this->parse_ehlo_response($stream);
         if ($this->errorCheck($tmp,$stream)) {
             // fall back to HELO if EHLO is not supported (error 5xx)
             if ($this->dlv_ret_nr{0} == '5') {
@@ -124,6 +168,60 @@
             }
         }
 
+        /**
+         * Implementing SMTP STARTTLS (rfc2487) in php 5.1.0+
+         * http://www.php.net/stream-socket-enable-crypto
+         */
+        if ($use_smtp_tls === 2) {
+            if (function_exists('stream_socket_enable_crypto')) {
+                // don't try starting tls, when client thinks that it is already \
active +                if ($this->tls_enabled) {
+                    $this->dlv_msg = _("TLS session is already activated.");
+                    return 0;
+                } elseif (!array_key_exists('STARTTLS',$this->ehlo)) {
+                    // check for starttls in ehlo response
+                    $this->dlv_msg = _("SMTP STARTTLS is enabled in SquirrelMail \
configuration, but used SMTP server does not support it"); +                    \
return 0; +                }
+
+                // issue starttls command
+                fputs($stream, "STARTTLS\r\n");
+                // get response
+                $tmp = fgets($stream,1024);
+                if ($this->errorCheck($tmp,$stream)) {
+                    return 0;
+                }
+
+                // start crypto on connection. suppress function errors.
+                if (@stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) \
{ +                    // starttls was successful (rfc2487 5.2 Result of the STARTTLS \
Command) +                    // get new EHLO response
+                    fputs($stream, "EHLO $helohost\r\n");
+                    // Read ehlo response
+                    $tmp = $this->parse_ehlo_response($stream);
+                    if ($this->errorCheck($tmp,$stream)) {
+                        // don't revert to helo here. server must support ESMTP
+                        return 0;
+                    }
+                    // set information about started tls
+                    $this->tls_enabled = true;
+                } else {
+                    /**
+                     * stream_socket_enable_crypto() call failed.
+                     */
+                    $this->dlv_msg = _("Unable to start TLS.");
+                    return 0;
+                    // Bug: can't get error message. See comments in \
sqimap_create_stream(). +                }
+            } else {
+                // php install does not support stream_socket_enable_crypto() \
function +                $this->dlv_msg = _("SMTP STARTTLS is enabled in \
SquirrelMail configuration, but used PHP version does not support functions that \
allow to enable encryption on open socket."); +                return 0;
+            }
+        }
+
+        // FIXME: check ehlo response before using authentication
+
         // Try authentication by a plugin
         //
         // NOTE: there is another hook in functions/auth.php called "smtp_auth"
@@ -389,5 +487,66 @@
             fclose($popConnection);
         }
     }
+
+    /**
+     * Parses ESMTP EHLO response (rfc1869)
+     *
+     * Reads SMTP response to EHLO command and fills class variables 
+     * (ehlo array and domain string). Returns last line.
+     * @param stream $stream smtp connection stream.
+     * @return string last ehlo line
+     * @since 1.4.23 and 1.5.1
+     */
+    function parse_ehlo_response($stream) {
+        // don't cache ehlo information
+        $this->ehlo=array();
+        $ret = '';
+        $firstline = true;
+        /**
+         * ehlo mailclient.example.org
+         * 250-mail.example.org
+         * 250-PIPELINING
+         * 250-SIZE 52428800
+         * 250-DATAZ
+         * 250-STARTTLS
+         * 250-AUTH LOGIN PLAIN
+         * 250 8BITMIME
+         */
+        while ($line=fgets($stream, 1024)){
+            // match[1] = first symbol after 250
+            // match[2] = domain or ehlo-keyword
+            // match[3] = greeting or ehlo-param
+            // match space after keyword in ehlo-keyword CR LF
+            if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)\r\n/",$line,$match)||
+                preg_match("/^250(-|\s)(\S*)\s*\r\n/",$line,$match)) {
+                if ($firstline) {
+                    // first ehlo line (250[-\ ]domain SP greeting)
+                    $this->domain = $match[2];
+                    $firstline=false;
+                } elseif (!isset($match[3])) {
+                    // simple one word extension
+                    $this->ehlo[strtoupper($match[2])]='';
+                } elseif (!preg_match("/\s/",trim($match[3]))) {
+                    // extension with one option
+                    // yes, I know about ctype extension. no, i don't want to depend \
on it +                    $this->ehlo[strtoupper($match[2])]=trim($match[3]);
+                } else {
+                    // ehlo-param with spaces
+                    $this->ehlo[strtoupper($match[2])]=explode(' ',trim($match[3]));
+                }
+                if ($match[1]==' ') {
+                    // stop while cycle, if we reach last 250 line
+                    $ret = $line;
+                    break;
+                }
+            } else {
+                // this is not 250 response
+                $ret = $line;
+                break;
+            }
+        }
+        return $ret;
+    }
+
 }
 

This was sent by the SourceForge.net collaborative development platform, the world's \
largest Open Source development site.


------------------------------------------------------------------------------
Go from Idea to Many App Stores Faster with Intel(R) XDK
Give your users amazing mobile app experiences with Intel(R) XDK.
Use one codebase in this all-in-one HTML5 development environment.
Design, debug & build mobile apps & 2D/3D high-impact games for multiple OSs.
http://pubads.g.doubleclick.net/gampad/clk?id=254741911&iu=/4140
-----
squirrelmail-cvs mailing list
List address: squirrelmail-cvs@lists.sourceforge.net
List info (subscribe/unsubscribe/change options): \
                https://lists.sourceforge.net/lists/listinfo/squirrelmail-cvs
Repository: http://squirrelmail.org/svn


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic