adding error checking in deliver_sendmail class.
authortokul <tokul@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Thu, 8 Dec 2005 18:24:47 +0000 (18:24 +0000)
committertokul <tokul@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Thu, 8 Dec 2005 18:24:47 +0000 (18:24 +0000)
sendmail -i -t arguments moved to configuration
fixed unsanitized output in plain_error_message() calls.

git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@10451 7612ce4b-ef26-0410-bec9-ea0150e637f0

ChangeLog
class/deliver/Deliver_SendMail.class.php
config/conf.pl
config/config_default.php
plugins/administrator/defines.php
src/compose.php

index 6e9112dfe6b193aeed45dfa54573105b9bc2d0dc..17541dee1d523c6c6e4630a6d73d6e5795081567 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -502,6 +502,12 @@ Version 1.5.1 -- CVS
     by the IMAP server. (Such as THREAD=SORT, THREAD=REFERENCES).
   - Inclusion of Compatibility plugin automatic (no patch needed for plugin)
   - Moved sqm_baseuri() into more centralized location (strings.php)
+  - Introduced $sendmail_args configuration variable in order to control
+    /usr/sbin/sendmail command arguments (#1365779). Deliver_SendMail class was 
+    modified to provide support of $sendmail_args. Modifications broke backwards 
+    compatibility with qmail-inject workarounds.
+  - Added execution error handling in Deliver_SendMail class (#1374174).
+  - Sanitized message composition error messages.
 
 Version 1.5.0 - 2 February 2004
 -------------------------------
index 818871b3436a54824ed74bd6f25c4961bffddcd8..0f1bc9615b7ec2e9ada71fb6a3430c7edaa87180 100644 (file)
@@ -12,6 +12,8 @@
  * @package squirrelmail
  */
 
+/** @ignore */
+if (!defined('SM_PATH')) define('SM_PATH','../../');
 
 /** This of course depends upon Deliver */
 require_once(SM_PATH . 'class/deliver/Deliver.class.php');
@@ -21,6 +23,44 @@ require_once(SM_PATH . 'class/deliver/Deliver.class.php');
  * @package squirrelmail
  */
 class Deliver_SendMail extends Deliver {
+    /**
+     * Extra sendmail arguments
+     *
+     * Parameter can be set in class constructor function.
+     *
+     * WARNING: Introduction of this parameter broke backwards compatibility 
+     * with workarounds specific to qmail-inject.
+     *
+     * If parameter needs some security modifications, it should be set to 
+     * private in PHP 5+ in order to prevent uncontrolled access.
+     * @var string
+     * @since 1.5.1
+     */
+    var $sendmail_args = '-i -t';
+
+    /**
+     * Stores used sendmail command
+     * Private variable that is used to inform about used sendmail command.
+     * @var string
+     * @since 1.5.1
+     */
+    var $sendmail_command = '';
+
+    /**
+     * Constructor function
+     * @param array configuration options. array key = option name, 
+     * array value = option value.
+     * @return void
+     * @since 1.5.1
+     */
+    function Deliver_SendMail($params=array()) {
+        if (!empty($params) && is_array($params)) {
+            // set extra sendmail arguments
+            if (isset($params['sendmail_args'])) {
+                $this->sendmail_args = $params['sendmail_args'];
+            }
+        }
+    }
 
    /**
     * function preWriteToStream
@@ -46,7 +86,7 @@ class Deliver_SendMail extends Deliver {
     *
     * @param Message $message Message object containing the from address
     * @param string $sendmail_path Location of sendmail binary
-    * @return void
+    * @return resource
     * @access public
     */
     function initStream($message, $sendmail_path) {
@@ -54,26 +94,32 @@ class Deliver_SendMail extends Deliver {
         $from = $rfc822_header->from[0];
         $envelopefrom = trim($from->mailbox.'@'.$from->host);
         $envelopefrom = str_replace(array("\0","\n"),array('',''),$envelopefrom);
-        if (strstr($sendmail_path, "qmail-inject")) {
-            $stream = popen (escapeshellcmd("$sendmail_path -f$envelopefrom"), "w");
-        } else {
-            $stream = popen (escapeshellcmd("$sendmail_path -i -t -f$envelopefrom"), "w");
-        }
+        // save executed command for future reference
+        $this->sendmail_command = "$sendmail_path $this->sendmail_args -f$envelopefrom";
+        // open process handle for writing
+        $stream = popen (escapeshellcmd($this->sendmail_command), "w");
         return $stream;
     }
 
    /**
-    * function finalizeStream
-    *
-    * Close the stream.
+    * Closes process handle.
     *
     * @param resource $stream
     * @return boolean
     * @access public
     */
     function finalizeStream($stream) {
-        pclose($stream);
-        return true;
+        $ret = true;
+        $status = pclose($stream);
+        // check pclose() status.
+        if ($status!=0) {
+            $ret = false;
+            $this->dlv_msg=_("Email delivery error");
+            $this->dlv_ret_nr=$status;
+            // we can get better error messsage only if we switch to php 4.3+ and proc_open().
+            $this->dlv_server_msg=sprintf(_("Can't execute command '%s'."),$this->sendmail_command);
+        }
+        return $ret;
     }
 
    /**
index 7d4454472df52fe6f1b3e4b22cf67c7daf0c2c7a..e4391c47aa5935042f96cbe05d0cdc5463bbdbcb 100755 (executable)
@@ -363,6 +363,12 @@ $time_zone_type = '0'                   if ( !$time_zone_type );
 $prefs_user_size = 128                  if ( !$prefs_user_size );
 $prefs_key_size = 64                    if ( !$prefs_key_size );
 $prefs_val_size = 65536                 if ( !$prefs_val_size );
+# add qmail-inject test here for backwards compatibility
+if ( !$sendmail_args && $sendmail_path =~ /qmail-inject/ ) { 
+    $sendmail_args = '';
+} elsif ( !$sendmail_args ) {
+    $sendmail_args = '-i -t';
+}
 
 if ( $ARGV[0] eq '--install-plugin' ) {
     print "Activating plugin " . $ARGV[1] . "\n";
@@ -456,7 +462,8 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) && ( $command ne ":q" ) ) {
           if ( lc($useSendmail) eq 'true' ) {
             print $WHT . "Sendmail" . $NRM . "\n--------\n";
             print "4.   Sendmail Path         : $WHT$sendmail_path$NRM\n";
-            print "5.   Header encryption key : $WHT$encode_header_key$NRM\n";
+            print "5.   Sendmail arguments    : $WHT$sendmail_args$NRM\n";
+            print "6.   Header encryption key : $WHT$encode_header_key$NRM\n";
             print "\n";
           } else {
             print $WHT . "SMTP Settings" . $NRM . "\n-------------\n";
@@ -721,7 +728,8 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) && ( $command ne ":q" ) ) {
               elsif ( $command == 9 )  { $optional_delimiter     = command111(); }
             } elsif ( $show_smtp_settings && lc($useSendmail) eq 'true' ) {
               if    ( $command == 4 )  { $sendmail_path          = command15(); }
-              elsif ( $command == 5 )  { $encode_header_key      = command114(); }
+              elsif ( $command == 5 )  { $sendmail_args          = command_sendmail_args(); }
+              elsif ( $command == 6 )  { $encode_header_key      = command114(); }
             } elsif ( $show_smtp_settings ) {
               if    ( $command == 4 )  { $smtpServerAddress      = command16(); }
               elsif ( $command == 5 )  { $smtpPort               = command17(); }
@@ -1043,6 +1051,7 @@ sub command14 {
 
 # sendmail_path
 sub command15 {
+    # TODO: fix check
     if ( $sendmail_path[0] !~ /./ ) {
         $sendmail_path = "/usr/sbin/sendmail";
     }
@@ -1057,6 +1066,27 @@ sub command15 {
     return $new_sendmail_path;
 }
 
+# Extra sendmail arguments
+sub command_sendmail_args {
+    print "Specify additional sendmail program arguments.\n";
+    print "\n";
+    print "Make sure that arguments are supported by your sendmail program. -f argument \n";
+    print "is added automatically by SquirrelMail scripts. Variable defaults to standard\n";
+    print "/usr/sbin/sendmail arguments. If you use qmail-inject, nbsmtp or any other \n";
+    print "sendmail wrapper, which does not support -i and -t arguments, set variable to\n";
+    print "empty string or use arguments suitable for your mailer.\n"; 
+    print "\n";
+    print "[$WHT$sendmail_args$NRM]: $WHT";
+    $new_sendmail_args = <STDIN>;
+    if ( $new_sendmail_args eq "\n" ) {
+        $new_sendmail_args = $sendmail_args;
+    } else {
+        # strip linefeeds and crs.
+        $new_sendmail_args =~ s/[\r\n]//g;
+    }
+    return trim($new_sendmail_args);
+}
+
 # smtpServerAddress
 sub command16 {
     print "This is the hostname of your SMTP server.\n";
@@ -3420,6 +3450,8 @@ sub save_data {
         print CF "\$smtpPort               = $smtpPort;\n";
         # string
         print CF "\$sendmail_path          = '$sendmail_path';\n";
+        # string
+        print CF "\$sendmail_args          = '$sendmail_args';\n";
         # boolean
 #        print CF "\$use_authenticated_smtp = $use_authenticated_smtp;\n";
         # boolean
@@ -4057,6 +4089,17 @@ sub detect_auth_support {
     return 'YES';
 }
 
+# trims whitespace
+# Example code from O'Reilly Perl Cookbook
+sub trim {
+    my @out = @_;
+    for (@out) {
+        s/^\s+//;
+        s/\s+$//;
+    }
+    return wantarray ? @out : $out[0];
+}
+
 sub clear_screen() {
     if ( $^O =~ /^mswin/i) {
         system "cls";
index 6d1bb6530724cd7c041326643159d5baa8ebc602..39cd1945a7c33d29e37e7b9558cca1b39edb4d02 100644 (file)
@@ -169,11 +169,25 @@ $encode_header_key = '';
  *
  * Program that should be used when sending email. SquirrelMail expects that
  * this program will follow options used by original sendmail
- * (http://www.sendmail.org).
+ * (http://www.sendmail.org). Support of -f argument is required.
  * @global string $sendmail_path
  */
 $sendmail_path = '/usr/sbin/sendmail';
 
+/**
+ * Extra sendmail command arguments.
+ * 
+ * Sets additional sendmail command arguments. Make sure that arguments are 
+ * supported by your sendmail program. -f argument is added automatically by
+ * SquirrelMail scripts. Variable defaults to standard /usr/sbin/sendmail 
+ * arguments. If you use qmail-inject, nbsmtp or any other sendmail wrapper,
+ * which does not support -t and -i arguments, set variable to empty string
+ * or use arguments suitable for your mailer. 
+ * @global string $sendmail_args
+ * @since 1.5.1
+ */
+$sendmail_args = '-i -t';
+
 /**
  * IMAP server address
  *
index 3b979c946e38eeded70e6ef69a507d7a5c34cbbb..05cce543b987b0a41e3975e90d3c6ddaf2fde9e8 100644 (file)
 /** @ignore */
 if (!defined('SM_PATH')) define('SM_PATH','../../');
 
-/** */
+/**
+ * Load SquirrelMail SMPREF constants for default_unseen_notify and 
+ * default_unseen_type variables.
+ */
 require_once( SM_PATH . 'functions/constants.php' );
 
 /* Define constants for the various option types. */
@@ -134,6 +137,9 @@ $defcfg = array( '$config_version' => array( 'name' => _("Config File Version"),
                  '$sendmail_path' => array( 'name' => _("Sendmail Path"),
                                             'type' => SMOPT_TYPE_STRING,
                                             'size' => 40 ),
+                 '$sendmail_args' => array( 'name' => _("Sendmail Arguments"),
+                                            'type' => SMOPT_TYPE_STRING,
+                                            'size' => 40 ),
                  '$smtpServerAddress' => array( 'name' => _("SMTP Server Address"),
                                                 'type' => SMOPT_TYPE_STRING,
                                                 'size' => 40 ),
index 468b262dc95f3dfba5bdb202bde61a0805c4ed36..b03e6867d0da2808f52c74c41305dfeae3259592 100644 (file)
@@ -1608,8 +1608,8 @@ function deliverMessage($composeMessage, $draft=false) {
                 $smtpServerAddress, $smtpPort, $user, $pass, $authPop);
     } elseif (!$draft) {
         require_once(SM_PATH . 'class/deliver/Deliver_SendMail.class.php');
-        global $sendmail_path;
-        $deliver = new Deliver_SendMail();
+        global $sendmail_path, $sendmail_args;
+        $deliver = new Deliver_SendMail(array('sendmail_args'=>$sendmail_args));
         $stream = $deliver->initStream($composeMessage,$sendmail_path);
     } elseif ($draft) {
         global $draft_folder;
@@ -1628,7 +1628,7 @@ function deliverMessage($composeMessage, $draft=false) {
             $composeMessage->purgeAttachments();
             return $length;
         } else {
-            $msg  = '<br />'.sprintf(_("Error: Draft folder %s does not exist."), $draft_folder);
+            $msg  = '<br />'.sprintf(_("Error: Draft folder %s does not exist."), htmlspecialchars($draft_folder));
             plain_error_message($msg, $color);
             return false;
         }
@@ -1639,9 +1639,10 @@ function deliverMessage($composeMessage, $draft=false) {
         $success = $deliver->finalizeStream($stream);
     }
     if (!$success) {
-        $msg  = $deliver->dlv_msg . '<br />' .
-            _("Server replied:") . ' ' . $deliver->dlv_ret_nr . ' ' .
-            $deliver->dlv_server_msg;
+        // $deliver->dlv_server_msg is not always server's reply
+        $msg  = htmlspecialchars($deliver->dlv_msg) . '<br />' .
+            _("Server replied:") . ' ' . htmlspecialchars($deliver->dlv_ret_nr) . ' ' .
+            htmlspecialchars($deliver->dlv_server_msg);
         plain_error_message($msg, $color);
     } else {
         unset ($deliver);