X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=class%2Fdeliver%2FDeliver_SMTP.class.php;h=f2e980ee6fbddcec4848571cd115d406d2223911;hp=2a8ac7ca9586dd842b09430e2a56b708c6c907d0;hb=eeb17be51154fb909206aef8ef251c3d8427c4a8;hpb=5b8fd093bb0effdd6c19259a4c2c13efcdda0e6b diff --git a/class/deliver/Deliver_SMTP.class.php b/class/deliver/Deliver_SMTP.class.php index 2a8ac7ca..f2e980ee 100644 --- a/class/deliver/Deliver_SMTP.class.php +++ b/class/deliver/Deliver_SMTP.class.php @@ -1,242 +1,308 @@ authPop($host, '', $user, $pass); - } - - $rfc822_header = $message->rfc822_header; - $from = $rfc822_header->from[0]; - $to = $rfc822_header->to; - $cc = $rfc822_header->cc; - $bcc = $rfc822_header->bcc; + $this->authPop($host, '', $user, $pass); + } + + $rfc822_header = $message->rfc822_header; + + $from = $rfc822_header->from[0]; + $to = $rfc822_header->to; + $cc = $rfc822_header->cc; + $bcc = $rfc822_header->bcc; + $content_type = $rfc822_header->content_type; - $stream = fsockopen($host, $port, $errorNumber, $errorString); - if (!$stream) { - $this->dlv_msg = $errorString; - $this->dlv_ret_nr = $errorNumber; - return(0); - } - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } + // MAIL FROM: MUST be empty in cae of MDN (RFC2298) + if ($content_type->type0 == 'multipart' && + $content_type->type1 == 'report' && + isset($content_type->properties['report-type']) && + $content_type->properties['report-type']=='disposition-notification') { + $from->host = ''; + $from->mailbox = ''; + } + + if (($use_smtp_tls == true) and (check_php_version(4,3)) and (extension_loaded('openssl'))) { + $stream = fsockopen('tls://' . $host, $port, $errorNumber, $errorString); + } else { + $stream = fsockopen($host, $port, $errorNumber, $errorString); + } + + if (!$stream) { + $this->dlv_msg = $errorString; + $this->dlv_ret_nr = $errorNumber; + return(0); + } + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } - /* Lets introduce ourselves */ - if (! isset ($use_authenticated_smtp) - || $use_authenticated_smtp == false) { - fputs($stream, "HELO $domain\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } + /* + * If $_SERVER['HTTP_HOST'] is set, use that in our HELO to the SMTP + * server. This should fix the DNS issues some people have had + */ + if (sqgetGlobalVar('HTTP_HOST', $HTTP_HOST, SQ_SERVER)) { // HTTP_HOST is set + // optionally trim off port number + if($p = strrpos($HTTP_HOST, ':')) { + $HTTP_HOST = substr($HTTP_HOST, 0, $p); + } + $helohost = $HTTP_HOST; + } else { // For some reason, HTTP_HOST is not set - revert to old behavior + $helohost = $domain; + } + + /* Lets introduce ourselves */ + fputs($stream, "EHLO $helohost\r\n"); + $tmp = fgets($stream,1024); + if ($this->errorCheck($tmp,$stream)) { + return(0); + } + + if (( $smtp_auth_mech == 'cram-md5') or ( $smtp_auth_mech == 'digest-md5' )) { + // Doing some form of non-plain auth + if ($smtp_auth_mech == 'cram-md5') { + fputs($stream, "AUTH CRAM-MD5\r\n"); + } elseif ($smtp_auth_mech == 'digest-md5') { + fputs($stream, "AUTH DIGEST-MD5\r\n"); + } + + $tmp = fgets($stream,1024); + + if ($this->errorCheck($tmp,$stream)) { + return(0); + } + + // At this point, $tmp should hold "334 " + $chall = substr($tmp,4); + // Depending on mechanism, generate response string + if ($smtp_auth_mech == 'cram-md5') { + $response = cram_md5_response($user,$pass,$chall); + } elseif ($smtp_auth_mech == 'digest-md5') { + $response = digest_md5_response($user,$pass,$chall,'smtp',$host); + } + fputs($stream, $response); + + // Let's see what the server had to say about that + $tmp = fgets($stream,1024); + if ($this->errorCheck($tmp,$stream)) { + return(0); + } + + // CRAM-MD5 is done at this point. If DIGEST-MD5, there's a bit more to go + if ($smtp_auth_mech == 'digest-md5') { + // $tmp contains rspauth, but I don't store that yet. (No need yet) + fputs($stream,"\r\n"); + $tmp = fgets($stream,1024); + + if ($this->errorCheck($tmp,$stream)) { + return(0); + } + } + // CRAM-MD5 and DIGEST-MD5 code ends here + } elseif ($smtp_auth_mech == 'none') { + // No auth at all, just send helo and then send the mail + // We already said hi earlier, nothing more is needed. + } elseif ($smtp_auth_mech == 'login') { + // The LOGIN method + fputs($stream, "AUTH LOGIN\r\n"); + $tmp = fgets($stream, 1024); + + if ($this->errorCheck($tmp, $stream)) { + return(0); + } + fputs($stream, base64_encode ($user) . "\r\n"); + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } + + fputs($stream, base64_encode($pass) . "\r\n"); + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } + } elseif ($smtp_auth_mech == "plain") { + /* SASL Plain */ + $auth = base64_encode("$user\0$user\0$pass"); + + $query = "AUTH PLAIN\r\n"; + fputs($stream, $query); + $read=fgets($stream, 1024); + + if (substr($read,0,3) == '334') { // OK so far.. + fputs($stream, "$auth\r\n"); + $read = fgets($stream, 1024); + } + + $results=explode(" ",$read,3); + $response=$results[1]; + $message=$results[2]; } else { - fputs($stream, "EHLO $domain\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - fputs($stream, "AUTH LOGIN\r\n"); - $tmp = fgets($stream, 1024); - - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - fputs($stream, base64_encode ($user) . "\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - - fputs($stream, base64_encode($pass) . "\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - } + /* Right here, they've reached an unsupported auth mechanism. + This is the ugliest hack I've ever done, but it'll do till I can fix + things up better tomorrow. So tired... */ + if ($this->errorCheck("535 Unable to use this auth type",$stream)) { + return(0); + } + } + + /* Ok, who is sending the message? */ + $fromaddress = ($from->mailbox && $from->host) ? + $from->mailbox.'@'.$from->host : ''; + fputs($stream, 'MAIL FROM:<'.$fromaddress.">\r\n"); + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } - /* Ok, who is sending the message? */ - fputs($stream, 'MAIL FROM: <'.$from->mailbox.'@'.$from->host.">\r\n"); + /* send who the recipients are */ + for ($i = 0, $cnt = count($to); $i < $cnt; $i++) { + if (!$to[$i]->host) $to[$i]->host = $domain; + if ($to[$i]->mailbox) { + fputs($stream, 'RCPT TO:<'.$to[$i]->mailbox.'@'.$to[$i]->host.">\r\n"); + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } + } + } + + for ($i = 0, $cnt = count($cc); $i < $cnt; $i++) { + if (!$cc[$i]->host) $cc[$i]->host = $domain; + if ($cc[$i]->mailbox) { + fputs($stream, 'RCPT TO:<'.$cc[$i]->mailbox.'@'.$cc[$i]->host.">\r\n"); + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } + } + } + + for ($i = 0, $cnt = count($bcc); $i < $cnt; $i++) { + if (!$bcc[$i]->host) $bcc[$i]->host = $domain; + if ($bcc[$i]->mailbox) { + fputs($stream, 'RCPT TO:<'.$bcc[$i]->mailbox.'@'.$bcc[$i]->host.">\r\n"); + $tmp = fgets($stream, 1024); + if ($this->errorCheck($tmp, $stream)) { + return(0); + } + } + } + /* Lets start sending the actual message */ + fputs($stream, "DATA\r\n"); $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - - /* send who the recipients are */ - for ($i = 0, $cnt = count($to); $i < $cnt; $i++) { - if (!$to[$i]->host) $to[$i]->host = $domain; - fputs($stream, 'RCPT TO: <'.$to[$i]->mailbox.'@'.$to[$i]->host.">\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - } - for ($i = 0, $cnt = count($cc); $i < $cnt; $i++) { - if (!$cc[$i]->host) $cc[$i]->host = $domain; - fputs($stream, 'RCPT TO: <'.$cc[$i]->mailbox.'@'.$cc[$i]->host.">\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - } - for ($i = 0, $cnt = count($bcc); $i < $cnt; $i++) { - if (!$bcc[$i]->host) $bcc[$i]->host = $domain; - fputs($stream, 'RCPT TO: <'.$bcc[$i]->mailbox.'@'.$bcc[$i]->host.">\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } + if ($this->errorCheck($tmp, $stream)) { + return(0); } - /* Lets start sending the actual message */ - fputs($stream, "DATA\r\n"); - $tmp = fgets($stream, 1024); - if ($this->errorCheck($tmp, $stream)) { - return(0); - } - return $stream; + return $stream; } function finalizeStream($stream) { - fputs($stream, ".\r\n"); /* end the DATA part */ - $tmp = fgets($stream, 1024); - $this->errorCheck($tmp, $stream); - if ($this->dlv_ret_nr != 250) { - return(0); - } - fputs($stream, "QUIT\r\n"); /* log off */ - fclose($stream); - return true; + fputs($stream, "\r\n.\r\n"); /* end the DATA part */ + $tmp = fgets($stream, 1024); + $this->errorCheck($tmp, $stream); + if ($this->dlv_ret_nr != 250) { + return(0); + } + fputs($stream, "QUIT\r\n"); /* log off */ + fclose($stream); + return true; } + /* check if an SMTP reply is an error and set an error message) */ function errorCheck($line, $smtpConnection) { - global $color, $compose_new_win; - - /* Read new lines on a multiline response */ - $lines = $line; - while(ereg("^[0-9]+-", $line)) { - $line = fgets($smtpConnection, 1024); - $lines .= $line; - } - /* Status: 0 = fatal - * 5 = ok - */ - $err_num = substr($line, 0, strpos($line, " ")); - switch ($err_num) { - case 500: $message = 'Syntax error; command not recognized'; - $status = 0; - break; - case 501: $message = 'Syntax error in parameters or arguments'; - $status = 0; - break; - case 502: $message = 'Command not implemented'; - $status = 0; - break; - case 503: $message = 'Bad sequence of commands'; - $status = 0; - break; - case 504: $message = 'Command parameter not implemented'; - $status = 0; - break; - case 211: $message = 'System status, or system help reply'; - $status = 5; - break; - case 214: $message = 'Help message'; - $status = 5; - break; - case 220: $message = 'Service ready'; - $status = 5; - break; - case 221: $message = 'Service closing transmission channel'; - $status = 5; - break; - case 421: $message = 'Service not available, closing chanel'; - $status = 0; - break; - case 235: return(5); - break; - case 250: $message = 'Requested mail action okay, completed'; - $status = 5; - break; - case 251: $message = 'User not local; will forward'; - $status = 5; - break; - case 334: return(5); break; - case 450: $message = 'Requested mail action not taken: mailbox unavailable'; - $status = 0; - break; - case 550: $message = 'Requested action not taken: mailbox unavailable'; - $status = 0; - break; - case 451: $message = 'Requested action aborted: error in processing'; - $status = 0; - break; - case 551: $message = 'User not local; please try forwarding'; - $status = 0; - break; - case 452: $message = 'Requested action not taken: insufficient system storage'; - $status = 0; - break; - case 552: $message = 'Requested mail action aborted: exceeding storage allocation'; - $status = 0; - break; - case 553: $message = 'Requested action not taken: mailbox name not allowed'; - $status = 0; - break; - case 354: $message = 'Start mail input; end with .'; - $status = 5; - break; - case 554: $message = 'Transaction failed'; - $status = 0; - break; - /* RFC 2554 */ - case 432: $message = 'A password transition is needed'; - $status = 0; - break; - case 534: $message = 'Authentication mechanism is too weak'; - $status = 0; - break; - case 538: $message = 'Encryption required for requested authentication mechanism'; - $status = 0; - break; - case 454: $message = 'Temmporary authentication failure'; - $status = 0; - break; - case 530: $message = 'Authentication required'; - $status = 0; - break; - /* end RFC2554 */ - default: $message = 'Unknown response: '. nl2br(htmlspecialchars($lines)); - $status = 0; - $err_num = '001'; - break; - } - $this->dlv_ret_nr = $err_num; - $this->dlv_msg = $message; - if ($status == 5) { - return false; - } + + $err_num = substr($line, 0, 3); + $this->dlv_ret_nr = $err_num; + $server_msg = substr($line, 4); + + while(substr($line, 0, 4) == ($err_num.'-')) { + $line = fgets($smtpConnection, 1024); + $server_msg .= substr($line, 4); + } + + if ( ((int) $err_num{0}) < 4) { + return false; + } + + switch ($err_num) { + case '421': $message = _("Service not available, closing channel"); + break; + case '432': $message = _("A password transition is needed"); + break; + case '450': $message = _("Requested mail action not taken: mailbox unavailable"); + break; + case '451': $message = _("Requested action aborted: error in processing"); + break; + case '452': $message = _("Requested action not taken: insufficient system storage"); + break; + case '454': $message = _("Temporary authentication failure"); + break; + case '500': $message = _("Syntax error; command not recognized"); + break; + case '501': $message = _("Syntax error in parameters or arguments"); + break; + case '502': $message = _("Command not implemented"); + break; + case '503': $message = _("Bad sequence of commands"); + break; + case '504': $message = _("Command parameter not implemented"); + break; + case '530': $message = _("Authentication required"); + break; + case '534': $message = _("Authentication mechanism is too weak"); + break; + case '535': $message = _("Authentication failed"); + break; + case '538': $message = _("Encryption required for requested authentication mechanism"); + break; + case '550': $message = _("Requested action not taken: mailbox unavailable"); + break; + case '551': $message = _("User not local; please try forwarding"); + break; + case '552': $message = _("Requested mail action aborted: exceeding storage allocation"); + break; + case '553': $message = _("Requested action not taken: mailbox name not allowed"); + break; + case '554': $message = _("Transaction failed"); + break; + default: $message = _("Unknown response"); + break; + } + + $this->dlv_msg = $message; + $this->dlv_server_msg = nl2br(htmlspecialchars($server_msg)); + return true; } @@ -250,20 +316,20 @@ class Deliver_SMTP extends Deliver { $popConnection = fsockopen($pop_server, $pop_port, $err_no, $err_str); if (!$popConnection) { error_log("Error connecting to POP Server ($pop_server:$pop_port)" - . " $err_no : $err_str"); + . " $err_no : $err_str"); } else { $tmp = fgets($popConnection, 1024); /* banner */ - if (!eregi("^\+OK", $tmp, $regs)) { + if (substr($tmp, 0, 3) != '+OK') { return(0); } fputs($popConnection, "USER $user\r\n"); $tmp = fgets($popConnection, 1024); - if (!eregi("^\+OK", $tmp, $regs)) { + if (substr($tmp, 0, 3) != '+OK') { return(0); } fputs($popConnection, 'PASS ' . $pass . "\r\n"); $tmp = fgets($popConnection, 1024); - if (!eregi("^\+OK", $tmp, $regs)) { + if (substr($tmp, 0, 3) != '+OK') { return(0); } fputs($popConnection, "QUIT\r\n"); /* log off */