From fd7ab7950ab48601cae33dbe47023c869499bf95 Mon Sep 17 00:00:00 2001 From: tokul Date: Thu, 8 Dec 2005 18:24:47 +0000 Subject: [PATCH] adding error checking in deliver_sendmail class. 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 | 6 +++ class/deliver/Deliver_SendMail.class.php | 68 ++++++++++++++++++++---- config/conf.pl | 47 +++++++++++++++- config/config_default.php | 16 +++++- plugins/administrator/defines.php | 8 ++- src/compose.php | 13 ++--- 6 files changed, 137 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e9112df..17541dee 100644 --- 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 ------------------------------- diff --git a/class/deliver/Deliver_SendMail.class.php b/class/deliver/Deliver_SendMail.class.php index 818871b3..0f1bc961 100644 --- a/class/deliver/Deliver_SendMail.class.php +++ b/class/deliver/Deliver_SendMail.class.php @@ -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; } /** diff --git a/config/conf.pl b/config/conf.pl index 7d445447..e4391c47 100755 --- a/config/conf.pl +++ b/config/conf.pl @@ -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 = ; + 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"; diff --git a/config/config_default.php b/config/config_default.php index 6d1bb653..39cd1945 100644 --- a/config/config_default.php +++ b/config/config_default.php @@ -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 * diff --git a/plugins/administrator/defines.php b/plugins/administrator/defines.php index 3b979c94..05cce543 100644 --- a/plugins/administrator/defines.php +++ b/plugins/administrator/defines.php @@ -14,7 +14,10 @@ /** @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 ), diff --git a/src/compose.php b/src/compose.php index 468b262d..b03e6867 100644 --- a/src/compose.php +++ b/src/compose.php @@ -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 = '
'.sprintf(_("Error: Draft folder %s does not exist."), $draft_folder); + $msg = '
'.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 . '
' . - _("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) . '
' . + _("Server replied:") . ' ' . htmlspecialchars($deliver->dlv_ret_nr) . ' ' . + htmlspecialchars($deliver->dlv_server_msg); plain_error_message($msg, $color); } else { unset ($deliver); -- 2.25.1