Merging in the tassium-auth branch.
authortassium <tassium@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Wed, 6 Nov 2002 18:55:13 +0000 (18:55 +0000)
committertassium <tassium@7612ce4b-ef26-0410-bec9-ea0150e637f0>
Wed, 6 Nov 2002 18:55:13 +0000 (18:55 +0000)
git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@4118 7612ce4b-ef26-0410-bec9-ea0150e637f0

class/deliver/Deliver_SMTP.class.php
config/conf.pl
config/config_default.php
doc/rfc_documents.txt
functions/auth.php
functions/imap_general.php
src/compose.php
src/read_body.php

index 756b298..4c8e49a 100644 (file)
@@ -22,18 +22,24 @@ class Deliver_SMTP extends Deliver {
     }
     
     function initStream($message, $domain, $length=0, $host='', $port='', $user='', $pass='', $authpop=false) {
-
-        if ($authpop) {
-          $this->authPop($host, '', $user, $pass);
+       global $use_smtp_tls,$smtp_auth_mech,$username,$key,$onetimepad;
+    
+       if ($authpop) {
+          $this->authPop($host, '', $username, $pass);
        }
-
-        $rfc822_header = $message->rfc822_header;      
+       
+    $rfc822_header = $message->rfc822_header;      
        $from = $rfc822_header->from[0];  
        $to =   $rfc822_header->to;
        $cc =   $rfc822_header->cc;
-       $bcc =   $rfc822_header->bcc;
+       $bcc =  $rfc822_header->bcc;
+
+    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);
+       }
 
-       $stream = fsockopen($host, $port, $errorNumber, $errorString);
        if (!$stream) {
            $this->dlv_msg = $errorString;
            $this->dlv_ret_nr = $errorNumber;
@@ -45,36 +51,84 @@ class Deliver_SMTP extends Deliver {
        }
     
        /* 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);
-           }
-        } 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 ((( $smtp_auth_mech == 'cram-md5') or ( $smtp_auth_mech == 'digest-md5' )) and (extension_loaded('mhash')))
+       {
+         // Doing some form of non-plain auth
+         fputs($stream, "EHLO $domain\r\n");
+         $tmp = fgets($stream,1024);
+         if ($this->errorCheck($tmp,$stream)) {
+           return(0);
+         }
+         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 <challenge string>"
+         $chall = substr($tmp,4);
+         // Depending on mechanism, generate response string 
+         if ($smtp_auth_mech == 'cram-md5') {
+           $response = cram_md5_response($username,$pass,$chall);
+         } elseif ($smtp_auth_mech == 'digest-md5') {
+           $response = digest_md5_response($username,$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
+         fputs($stream, "HELO $domain\r\n");
+      $tmp = fgets($stream, 1024);
+         if ($this->errorCheck($tmp, $stream)) {
+        return(0);
+         }
+       } elseif ($smtp_auth_mech == 'plain') {
+         // The plain LOGIN method
+      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);
-           }
+         if ($this->errorCheck($tmp, $stream)) {
+       return(0);
+         }
+      fputs($stream, base64_encode ($username) . "\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);
-           }
+      fputs($stream, base64_encode($pass) . "\r\n");
+      $tmp = fgets($stream, 1024);
+         if ($this->errorCheck($tmp, $stream)) {
+       return(0);
+         }
        }
     
        /* Ok, who is sending the message? */
@@ -139,7 +193,7 @@ class Deliver_SMTP extends Deliver {
     
     function errorCheck($line, $smtpConnection) {
        global $color, $compose_new_win;
-    
+       
        /* Read new lines on a multiline response */
        $lines = $line;
        while(ereg("^[0-9]+-", $line)) {
@@ -178,18 +232,21 @@ class Deliver_SMTP extends Deliver {
        case 221:   $message = 'Service closing transmission channel';
            $status = 5;
            break;
-       case 421:   $message = 'Service not available, closing chanel';
+       case 421:   $message = 'Service not available, closing channel';
            $status = 0;
            break;
-       case 235:   return(5); 
-           break;
+       case 235:   $message = 'Authentication successful';
+                       $status = 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 334:   $message = 'OK - continue request';
+                       $status = 5;
+                       break;
        case 450:   $message = 'Requested mail action not taken:  mailbox unavailable';
            $status = 0;
            break;
@@ -234,6 +291,9 @@ class Deliver_SMTP extends Deliver {
            $status = 0;
            break;
         /* end RFC2554 */      
+       case 535: $message = 'Authentication failed';
+               $status = 0;
+        break;
        default:    $message = 'Unknown response: '. nl2br(htmlspecialchars($lines));
            $status = 0;
            $err_num = '001';
index 2215074..f0ee8f8 100755 (executable)
@@ -270,9 +270,6 @@ if ( !$force_username_lowercase ) {
 if ( !$optional_delimiter ) {
     $optional_delimiter = "detect";
 }
-if ( !$use_authenticated_smtp ) {
-    $use_authenticated_smtp = "false";
-}
 if ( !$auto_create_special ) {
     $auto_create_special = "false";
 }
@@ -334,6 +331,22 @@ if ( !$prefs_val_field ) {
     $prefs_val_field = 'prefval';
 }
 
+if ( !$use_smtp_tls) {
+       $use_smtp_tls= 'false';
+}
+
+if ( !$smtp_auth_mech ) {
+       $smtp_auth_mech = 'none';
+}
+
+if ( !$use_imap_tls ) {
+    $use_imap_tls = 'false';
+}
+
+if ( !$imap_auth_mech ) {
+    $imap_auth_mech = 'plain';
+}
+
 if ( $ARGV[0] eq '--install-plugin' ) {
     print "Activating plugin " . $ARGV[1] . "\n";
     push @plugins, $ARGV[1];
@@ -398,28 +411,67 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) ) {
         print "\n";
         print "R   Return to Main Menu\n";
     } elsif ( $menu == 2 ) {
-        print $WHT. "Server Settings\n" . $NRM;
-        print "1.  Domain               : $WHT$domain$NRM\n";
-        print "2.  IMAP Server          : $WHT$imapServerAddress$NRM\n";
-        print "3.  IMAP Port            : $WHT$imapPort$NRM\n";
-        print "4.  Use Sendmail/SMTP    : $WHT";
+        print $WHT. "Server Settings\n\n" . $NRM;
+        print $WHT . "General" . $NRM . "\n";
+        print "-------\n";
+        print "1.  Domain                 : $WHT$domain$NRM\n";
+        print "2.  Invert Time            : $WHT$invert_time$NRM\n";
+        print "3.  Sendmail or SMTP       : $WHT";
         if ( lc($useSendmail) eq "true" ) {
             print "Sendmail";
         } else {
             print "SMTP";
         }
         print "$NRM\n";
-        if ( lc($useSendmail) eq "true" ) {
-            print "5.    Sendmail Path      : $WHT$sendmail_path$NRM\n";
-        } else {
-            print "6.    SMTP Server        : $WHT$smtpServerAddress$NRM\n";
-            print "7.    SMTP Port          : $WHT$smtpPort$NRM\n";
-            print "8.    Authenticated SMTP : $WHT$use_authenticated_smtp$NRM\n";
-            print "9.    POP Before SMTP    : $WHT$pop_before_smtp$NRM\n";
+        print "\n";
+        
+        if ( $show_imap_settings ) {
+          print $WHT . "IMAP Settings". $NRM . "\n--------------\n";
+          print "4.  IMAP Server            : $WHT$imapServerAddress$NRM\n";
+          print "5.  IMAP Port              : $WHT$imapPort$NRM\n";
+          print "6.  Authentication type    : $WHT$imap_auth_mech$NRM\n";
+          print "7.  Secure IMAP (TLS)      : $WHT$use_imap_tls$NRM\n";
+          print "8.  Server software        : $WHT$imap_server_type$NRM\n";
+          print "9.  Delimiter              : $WHT$optional_delimiter$NRM\n";
+          print "\n";
+        } elsif ( $show_smtp_settings ) {
+          if ( lc($useSendmail) eq "true" ) {
+            print $WHT . "Sendmail" . $NRM . "\n--------\n";
+            print "4.   Sendmail Path         : $WHT$sendmail_path$NRM\n";
+            print "\n";
+          } else {
+            print $WHT . "SMTP Settings" . $NRM . "\n-------------\n";
+            print "4.   SMTP Server           : $WHT$smtpServerAddress$NRM\n";
+            print "5.   SMTP Port             : $WHT$smtpPort$NRM\n";
+            print "6.   POP before SMTP       : $WHT$pop_before_smtp$NRM\n";
+            print "7.   SMTP Authentication   : $WHT$smtp_auth_mech$NRM\n";
+            print "8.   Secure SMTP (TLS)     : $WHT$use_smtp_tls$NRM\n";
+            print "\n";
+          }
         }
-        print "10. Server               : $WHT$imap_server_type$NRM\n";
-        print "11. Invert Time          : $WHT$invert_time$NRM\n";
-        print "12. Delimiter            : $WHT$optional_delimiter$NRM\n";
+
+        if ($show_imap_settings == 0) {
+          print "A.  Update IMAP Settings   : ";
+          print "$WHT$imapServerAddress$NRM:";
+          print "$WHT$imapPort$NRM ";
+          print "($WHT$imap_server_type$NRM)\n";
+        } 
+        if ($show_smtp_settings == 0) {
+          if ( lc($useSendmail) eq "true" ) {
+            print "B.  Change Sendmail Config : $WHT$sendmail_path$NRM\n";
+          } else {
+            print "B.  Update SMTP Settings   : ";
+            print "$WHT$smtpServerAddress$NRM:";
+            print "$WHT$smtpPort$NRM\n";
+          }
+        }
+        if ( $show_smtp_settings || $show_imap_settings )
+        {
+          print "H.  Hide " . 
+                ($show_imap_settings ? "IMAP Server" : 
+                  (lc($useSendmail) eq "true") ? "Sendmail" : "SMTP") . " Settings\n";
+        }
+        
         print "\n";
         print "R   Return to Main Menu\n";
     } elsif ( $menu == 3 ) {
@@ -600,18 +652,30 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) ) {
             elsif ( $command == 9 ) { $provider_name                 = command8(); }
 
         } elsif ( $menu == 2 ) {
-            if    ( $command == 1 )  { $domain                 = command11(); }
-            elsif ( $command == 2 )  { $imapServerAddress      = command12(); }
-            elsif ( $command == 3 )  { $imapPort               = command13(); }
-            elsif ( $command == 4 )  { $useSendmail            = command14(); }
-            elsif ( $command == 5 )  { $sendmail_path          = command15(); }
-            elsif ( $command == 6 )  { $smtpServerAddress      = command16(); }
-            elsif ( $command == 7 )  { $smtpPort               = command17(); }
-            elsif ( $command == 8 )  { $use_authenticated_smtp = command18(); }
-            elsif ( $command == 9 )  { $pop_before_smtp        = command18a(); }
-            elsif ( $command == 10 ) { $imap_server_type       = command19(); }
-            elsif ( $command == 11 ) { $invert_time            = command110(); }
-            elsif ( $command == 12 ) { $optional_delimiter     = command111(); }
+            if ( $command eq "a" )    { $show_imap_settings = 1; $show_smtp_settings = 0; }
+            elsif ( $command eq "b" ) { $show_imap_settings = 0; $show_smtp_settings = 1; }
+            elsif ( $command eq "h" ) { $show_imap_settings = 0; $show_smtp_settings = 0; }
+            elsif ( $command <= 3 ) {
+              if    ( $command == 1 )  { $domain                 = command11(); }
+              elsif ( $command == 2 )  { $invert_time            = command110(); }
+              elsif ( $command == 3 )  { $useSendmail            = command14(); }
+              $show_imap_settings = 0; $show_smtp_settings = 0;
+            } elsif ( $show_imap_settings ) {
+              if    ( $command == 4 )  { $imapServerAddress      = command12(); }
+              elsif ( $command == 5 )  { $imapPort               = command13(); }
+              elsif ( $command == 6 )  { $imap_auth_mech     = command112("IMAP",$imap_auth_mech); }
+              elsif ( $command == 7 )  { $use_imap_tls       = command113("IMAP",$use_imap_tls); }
+              elsif ( $command == 8 )  { $imap_server_type       = command19(); }
+              elsif ( $command == 9 )  { $optional_delimiter     = command111(); }
+            } elsif ( $show_smtp_settings && lc($useSendmail) eq "true" ) {
+              if ( $command == 4 )  { $sendmail_path          = command15(); }
+            } elsif ( $show_smtp_settings ) {
+              if    ( $command == 4 )  { $smtpServerAddress      = command16(); }
+              elsif ( $command == 5 )  { $smtpPort               = command17(); }
+              elsif ( $command == 6 )  { $pop_before_smtp        = command18a(); }
+              elsif ( $command == 7 )  { $smtp_auth_mech    = command112("SMTP",$smtp_auth_mech); }
+              elsif ( $command == 8 )  { $use_smtp_tls      = command113("SMTP",$use_smtp_tls); }
+            }
         } elsif ( $menu == 3 ) {
             if    ( $command == 1 )  { $default_folder_prefix          = command21(); }
             elsif ( $command == 2 )  { $show_prefix_option             = command22(); }
@@ -852,7 +916,7 @@ sub command11 {
 
 # imapServerAddress
 sub command12 {
-    print "This is the address where your IMAP server resides.\n";
+    print "This is the hostname where your IMAP server can be contacted.\n";
     print "[$WHT$imapServerAddress$NRM]: $WHT";
     $new_imapServerAddress = <STDIN>;
     if ( $new_imapServerAddress eq "\n" ) {
@@ -918,7 +982,7 @@ sub command15 {
 
 # smtpServerAddress
 sub command16 {
-    print "This is the location of your SMTP server.\n";
+    print "This is the hostname of your SMTP server.\n";
     print "[$WHT$smtpServerAddress$NRM]: $WHT";
     $new_smtpServerAddress = <STDIN>;
     if ( $new_smtpServerAddress eq "\n" ) {
@@ -944,6 +1008,8 @@ sub command17 {
 
 # authenticated server 
 sub command18 {
+    return;
+       # This sub disabled by tassium - it has been replaced with smtp_auth_mech
     print "Do you wish to use an authenticated SMTP server?  Your server must\n";
     print "support this in order for SquirrelMail to work with it.  We implemented\n";
     print "it according to RFC 2554.\n";
@@ -1044,6 +1110,72 @@ sub command111 {
     return $new_optional_delimiter;
 }
 
+# authentication type
+# This sub gets reused for IMAP and SMTP, so pass in the server type as an arg
+# Second arg is the default value to use
+# Possible choices: plain, cram-md5, digest-md5
+# SMTP also can be disabled with 'none'
+sub command112 {
+    my($default_val,$service,$inval);
+    $service=$_[0];
+    $default_val=$_[1];
+    print "What authentication mechanism do you want to use for " . $service . " logins?\n";
+    if ($service eq "SMTP") {
+      print $WHT . "none" . $NRM . " - Your SMTP server does not require authorization.\n";
+    }
+    print $WHT . "plain" . $NRM . " - Plaintext. If you can do better, you probably should.\n";
+    print $WHT . "cram-md5" . $NRM . " - Slightly better than plaintext. (Requires PHP mhash extension)\n";
+    print $WHT . "digest-md5" . $NRM . " - Privacy protection - better than cram-md5. (Requires PHP mhash extension)\n";
+    print "\n*** YOUR " . $service . " SERVER MUST SUPPORT THE MECHANISM YOU CHOOSE ***\n";
+    print "If you don't understand or are unsure, you probably want \"plain\"\n\n";
+    if ($service eq "SMTP") {
+      print "none, ";
+    }
+    print "plain, cram-md5, or digest-md5 [$WHT$default_val$NRM]: $WHT";
+    $inval=<STDIN>;
+    chomp($inval);
+    if ( ($service eq "SMTP") && ($inval =~ /^none\b/i) ) {
+      # SMTP doesn't necessarily require logins
+      return "none";
+    }
+    if ( ($inval =~ /^cram-md5\b/i) || ($inval =~ /^digest-md5\b/i) || 
+    ($inval =~ /^plain\b/i)) {
+      return lc($inval);
+    } else {
+      return $default_val;
+    }
+}
+
+# TLS
+# This sub is reused for IMAP and SMTP
+# Args: service name, default value
+sub command113 {
+       my($default_val,$service,$inval);
+       $service=$_[0];
+       $default_val=$_[1];
+       print "TLS (Transport Layer Security) encrypts the traffic between server and client.\n";
+       print "If you're familiar with SSL, you get the idea.\n";
+       print "To use this feature, your " . $service . " server must offer TLS\n";
+       print "capability, plus PHP 4.3.x with OpenSSL support.\n";
+       print "\nIf your " . $service . " server is localhost, you can safely disable this.\n";
+       print "If it is remote, you may wish to seriously consider enabling this.\n";
+    print "Enable TLS (y/n) [$WHT";
+    if ($default_val eq "true") {
+      print "y";
+    } else {
+      print "n";
+    }
+    print "$NRM]: $WHT"; 
+    $inval=<STDIN>;
+    $inval =~ tr/yn//cd;
+    return "true"  if ( $inval eq "y" );
+    return "false" if ( $inval eq "n" );
+    return $default_val;
+
+
+}
+
+
 # MOTD
 sub command71 {
     print "\nYou can now create the welcome message that is displayed\n";
@@ -2374,7 +2506,7 @@ sub save_data {
        # string
         print CF "\$sendmail_path          = '$sendmail_path';\n";
        # boolean
-        print CF "\$use_authenticated_smtp = $use_authenticated_smtp;\n";
+#        print CF "\$use_authenticated_smtp = $use_authenticated_smtp;\n";
        # boolean
         print CF "\$pop_before_smtp        = $pop_before_smtp;\n";
        # string
@@ -2526,6 +2658,14 @@ sub save_data {
         print CF "\$prefs_val_field = '$prefs_val_field';\n";
        # boolean
        print CF "\$no_list_for_subscribe = $no_list_for_subscribe;\n";
+
+       # string
+       print CF "\$smtp_auth_mech = '$smtp_auth_mech';\n";
+       print CF "\$imap_auth_mech = '$imap_auth_mech';\n";
+       # boolean
+    print CF "\$use_imap_tls = $use_imap_tls;\n";
+       print CF "\$use_smtp_tls = $use_smtp_tls;\n";
+
         print CF "\n";
 
         print CF "/**\n";
@@ -2682,6 +2822,7 @@ sub change_to_SM_path() {
     # If the path is absolute, don't bother.
     return "\'" . $old_path . "\'"  if ( $old_path eq '');
     return "\'" . $old_path . "\'"  if ( $old_path =~ /^\// );
+    return $old_path                if ( $old_path =~ /^\$/);
     return $old_path                if ( $old_path =~ /^SM_PATH/ );
 
     # For relative paths, split on '../'
@@ -2719,6 +2860,7 @@ sub change_to_rel_path() {
     my $new_path = '';
 
     return $old_path if ( $old_path eq '');
+    return $old_path if ( $old_path =~ /^\$/ );
     return $old_path if ( $old_path =~ /^\// );
     return $old_path if ( $old_path =~ /^\.\./ );
 
index d37a2fe..c6a79d7 100644 (file)
@@ -512,6 +512,24 @@ global $no_list_for_subscribe;
 $no_list_for_subscribe = false;
 
 /**
+ * Advanced authentication options
+ * CRAM-MD5, DIGEST-MD5, Plain, and TLS
+ * Set reasonable defaults - you'd never know this was there unless you ask for it
+ */
+global $use_imap_tls;
+global $use_smtp_tls;
+$use_imap_tls = false;
+$use_smtp_tls = false;
+
+/* auth_mech can be either 'plain', 'cram-md5', or 'digest-md5'
+   SMTP can also be 'none'
+*/
+global $smtp_auth_mech;
+global $imap_auth_mech;
+$smtp_auth_mech = 'none';
+$imap_auth_mech = 'plain';
+
+/**
  * Make sure there are no characters after the PHP closing
  * tag below (including newline characters and whitespace).
  * Otherwise, that character will cause the headers to be
index c74be67..afb8075 100644 (file)
@@ -13,8 +13,10 @@ NUMBER     DESCRIPTION
 RFC 1730   IMAP version 4
 RFC 2060   IMAP version 4rev1
 RFC 2183   Content-Disposition MIME header
+RFC 2195   IMAP/POP AUTHorize Extension for Simple Challenge/Response
 RFC 2298   Details return receipts
 RFC 2342   The IMAP4 NAMESPACE command
 RFC 2616   HTTP/1.1
 RFC 2683   IMAP4 Implementation Recommendations
 RFC 2822   Format of an email message (sendmail)
+RFC 2831   Using Digest Authentication as a SASL Mechanism (digest-md5)
index 24c92ff..0de160c 100644 (file)
  * $Id$
  */
 
+/* Put in a safety net here, in case a naughty admin didn't run conf.pl when they upgraded */
+
+if (! isset($smtp_auth_mech)) {
+  $smtp_auth_mech = 'none';
+}
+
+if (! isset($imap_auth_mech)) {
+  $imap_auth_mech = 'plain';
+}
+
+if (! isset($use_imap_tls)) {
+  $use_imap_tls = false;
+}
+
+if (! isset($use_smtp_tls)) {
+  $use_smtp_tls = false;
+}
+
 function is_logged_in() {
 
     if ( sqsession_is_registered('user_is_logged_in') ) {
@@ -37,4 +55,99 @@ function is_logged_in() {
     }
 }
 
+function cram_md5_response ($username,$password,$challenge) {
+
+/* Given the challenge from the server, supply the response using
+   cram-md5 (See RFC 2195 for details)
+   NOTE: Requires mhash extension to PHP
+*/
+$challenge=base64_decode($challenge);
+$hash=bin2hex(mhash(MHASH_MD5,$challenge,$password));
+$response=base64_encode($username . " " . $hash) . "\r\n";
+return $response;
+}
+
+function digest_md5_response ($username,$password,$challenge,$service,$host) {
+/* Given the challenge from the server, calculate and return the response-string
+   for digest-md5 authentication.  (See RFC 2831 for more details) */
+  $result=digest_md5_parse_challenge($challenge);
+  
+// verify server supports qop=auth
+  $qop = explode(",",$result['qop']);
+  //if (!in_array("auth",$qop)) {
+    // rfc2831: client MUST fail if no qop methods supported
+   // return false;
+  //}
+  $cnonce = base64_encode(bin2hex(mhash(MHASH_MD5, microtime())));
+  $ncount = "00000001";
+
+  /* This can be auth (authentication only), auth-int (integrity protection), or
+     auth-conf (confidentiality protection).  Right now only auth is supported.
+        DO NOT CHANGE THIS VALUE */
+  $qop_value = "auth";
+
+  $digest_uri_value = $service . '/' . $host;
+
+  // build the $response_value
+  //FIXME This will probably break badly if a server sends more than one realm
+  $string_a1 = utf8_encode($username).":";
+  $string_a1 .= utf8_encode($result['realm']).":";
+  $string_a1 .= utf8_encode($password);
+  $string_a1 = mhash(MHASH_MD5, $string_a1);
+  $A1 = $string_a1 . ":" . $result['nonce'] . ":" . $cnonce;
+  $A1 = bin2hex(mhash(MHASH_MD5, $A1));
+  $A2 = "AUTHENTICATE:$digest_uri_value";
+  // If qop is auth-int or auth-conf, A2 gets a little extra
+  if ($qop_value != 'auth') {
+    $A2 .= ':00000000000000000000000000000000';
+  }
+  $A2 = bin2hex(mhash(MHASH_MD5, $A2));
+
+  $string_response = $result['nonce'] . ':' . $ncount . ':' . $cnonce . ':' . $qop_value;
+  $response_value = bin2hex(mhash(MHASH_MD5, $A1.":".$string_response.":".$A2));
+
+  $reply = 'charset=utf-8,username="' . $username . '",realm="' . $result["realm"] . '",';
+  $reply .= 'nonce="' . $result['nonce'] . '",nc=' . $ncount . ',cnonce="' . $cnonce . '",';
+  $reply .= "digest-uri=\"$digest_uri_value\",response=$response_value";
+  $reply .= ',qop=' . $qop_value;
+  $reply = base64_encode($reply);
+  return $reply . "\r\n";
+}
+
+function digest_md5_parse_challenge($challenge) {
+/* This function parses the challenge sent during DIGEST-MD5 authentication and
+   returns an array. See the RFC for details on what's in the challenge string.
+*/
+  $challenge=base64_decode($challenge);
+  while (strlen($challenge)) {
+    if ($challenge{0} == ',') { // First char is a comma, must not be 1st time through loop
+      $challenge=substr($challenge,1);
+    }
+    $key=explode('=',$challenge,2);
+    $challenge=$key[1];
+    $key=$key[0];
+    if ($challenge{0} == '"') {
+      // We're in a quoted value
+      // Drop the first quote, since we don't care about it
+      $challenge=substr($challenge,1);
+      // Now explode() to the next quote, which is the end of our value
+      $val=explode('"',$challenge,2);
+      $challenge=$val[1]; // The rest of the challenge, work on it in next iteration of loop
+      $value=explode(',',$val[0]);
+      // Now, for those quoted values that are only 1 piece..
+      if (sizeof($value) == 1) {
+        $value=$value[0];  // Convert to non-array
+      }
+    } else {
+      // We're in a "simple" value - explode to next comma
+      $val=explode(',',$challenge,2);
+      $challenge=$val[1];
+      $value=$val[0];
+    }
+    $parsed["$key"]=$value;
+  } // End of while loop
+  return $parsed;
+}
+
 ?>
index 8575e7e..7efb973 100755 (executable)
@@ -12,6 +12,8 @@
  */
 
 require_once(SM_PATH . 'functions/page_header.php');
+require_once(SM_PATH . 'functions/auth.php');
+
 
 global $sqimap_session_id;
 $sqimap_session_id = 1;
@@ -205,10 +207,16 @@ function sqimap_read_data ($imap_stream, $pre, $handle_errors, &$response, &$mes
  * will be displayed.  This function returns the imap connection handle.
  */
 function sqimap_login ($username, $password, $imap_server_address, $imap_port, $hide) {
-    global $color, $squirrelmail_language, $onetimepad;
+    global $color, $squirrelmail_language, $onetimepad, $use_imap_tls, $imap_auth_mech;
 
     $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
-
+       $host=$imap_server_address;
+       
+       if (($use_imap_tls == true) and (check_php_version(4,3)) and (extension_loaded('openssl'))) {
+         /* Use TLS by prefixing "tls://" to the hostname */
+         $imap_server_address = 'tls://' . $imap_server_address;
+       }
+    
     $imap_stream = fsockopen ( $imap_server_address, $imap_port, $error_number, $error_string, 15);
 
     /* Do some error correction */
@@ -229,10 +237,51 @@ function sqimap_login ($username, $password, $imap_server_address, $imap_port, $
     /* Decrypt the password */
     $password = OneTimePadDecrypt($password, $onetimepad);
 
-    $query = 'LOGIN "' . quoteIMAP($username) .  '" "' . quoteIMAP($password) . '"';
-    $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
-
-    /* If the connection was not successful, lets see why */
+       if ((($imap_auth_mech == 'cram-md5') OR ($imap_auth_mech == 'digest-md5')) AND (extension_loaded('mhash')))  {
+      // We're using some sort of authentication OTHER than plain
+         $tag=sqimap_session_id(false);
+         if ($imap_auth_mech == 'digest-md5') {
+           $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
+         } elseif ($imap_auth_mech == 'cram-md5') {
+           $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
+         }
+         fputs($imap_stream,$query);
+         $answer=sqimap_fgets($imap_stream);
+         // Trim the "+ " off the front
+         $response=explode(" ",$answer,3);
+         if ($response[0] == '+') {
+           // Got a challenge back
+               $challenge=$response[1];
+               if ($imap_auth_mech == 'digest-md5') {
+                 $reply = digest_md5_response($username,$password,$challenge,'imap',$host);
+               } elseif ($imap_auth_mech == 'cram-md5') {
+                 $reply = cram_md5_response($username,$password,$challenge);
+               }
+               fputs($imap_stream,$reply);
+               $read=sqimap_fgets($imap_stream);
+               if ($imap_auth_mech == 'digest-md5') {
+                 // DIGEST-MD5 has an extra step..
+                 if (substr($read,0,1) == '+') { // OK so far..
+                   fputs($imap_stream,"\r\n");
+                   $read=sqimap_fgets($imap_stream);
+                 }
+               }
+               $results=explode(" ",$read,3);
+               $response=$results[1];
+               $message=$results[2];
+      } else {
+               // Fake the response, so the error trap at the bottom will work
+               $response="BAD";
+               $message='IMAP server does not appear to support the authentication method selected.';
+               $message .= '  Please contact your system administrator.';
+      }
+    } else {
+         // Original PLAIN login code
+      $query = 'LOGIN "' . quoteIMAP($username) .  '" "' . quoteIMAP($password) . '"';
+      $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
+    }
+    
+       /* If the connection was not successful, lets see why */
     if ($response != 'OK') {
         if (!$hide) {
             if ($response != 'NO') {
index 03f9124..36cdf51 100644 (file)
@@ -1322,15 +1322,17 @@ function deliverMessage($composeMessage, $draft=false) {
     if (!$useSendmail && !$draft) {
        require_once(SM_PATH . 'class/deliver/Deliver_SMTP.class.php');
        $deliver = new Deliver_SMTP();
-       global $smtpServerAddress, $smtpPort, $use_authenticated_smtp, $pop_before_smtp;
-       if ($use_authenticated_smtp) {
-           global $key, $onetimepad;
-           $user = $username;
-           $pass = OneTimePadDecrypt($key, $onetimepad);
+       global $smtpServerAddress, $smtpPort, $pop_before_smtp, $smtp_auth_mech;
+
+       if ($smtp_auth_mech == 'none') {
+               $user = '';
+               $pass = '';
        } else {
-           $user = '';
-           $pass = '';
+               global $key, $onetimepad;
+               $user = $username;
+               $pass = OneTimePadDecrypt($key, $onetimepad);
        }
+
        $authPop = (isset($pop_before_smtp) && $pop_before_smtp) ? true : false;
        $stream = $deliver->initStream($composeMessage,$domain,0,
                          $smtpServerAddress, $smtpPort, $user, $pass, $authPop);
index cfab22a..ce813fb 100644 (file)
@@ -269,14 +269,14 @@ function SendMDN ( $mailbox, $passed_id, $sender, $message, $imapConnection) {
     } else {
         require_once(SM_PATH . 'class/deliver/Deliver_SMTP.class.php');
         $deliver = new Deliver_SMTP();
-        global $smtpServerAddress, $smtpPort, $use_authenticated_smtp, $pop_before_smtp;
-        if ($use_authenticated_smtp) {
+        global $smtpServerAddress, $smtpPort, $smtp_auth_mech, $pop_before_smtp;
+               if ($smtp_auth_mech == 'none') {
+                       $user = '';
+                       $pass = '';
+               } else {
             global $key, $onetimepad;
             $user = $username;
             $pass = OneTimePadDecrypt($key, $onetimepad);
-        } else {
-            $user = '';
-            $pass = '';
         }
         $authPop = (isset($pop_before_smtp) && $pop_before_smtp) ? true : false;
         $stream = $deliver->initStream($composeMessage,$domain,0,