Added (optional) detection of IMAP and SMTP support for different authentication...
[squirrelmail.git] / config / conf.pl
index 2215074e5057f852be87ec482d227f298281366f..eaa2a589053aaf12758ce4772faa1ffc3e90a0b8 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";
+          }
+        }
+
+        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 "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";
+        
         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     = command112a(); }
+              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    = command112b(); }
+              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";
@@ -1043,6 +1109,191 @@ sub command111 {
     }
     return $new_optional_delimiter;
 }
+# IMAP authentication type
+# Possible values: plain, cram-md5, digest-md5
+# Now offers to detect supported mechs, assuming server & port are set correctly
+
+sub command112a {
+       print "If you have already set the hostname and port number, I can try to\n";
+       print "detect the methods your IMAP server supports.\n";
+       print "I will try to detect CRAM-MD5 and DIGEST-MD5 support.  I can't test\n";
+       print "for \"plain\" without knowing a username and password.\n";
+       print "\nTry to detect auth methods? [y/N]: ";
+       $inval=<STDIN>;
+       chomp($inval);
+       if ($inval =~ /^y\b/i) {
+         # Yes, let's try to detect.
+         print "Trying to detect IMAP capabilities...\n";
+         my $host = $imapServerAddress . ':'. $imapPort;
+         print "CRAM-MD5:\t";
+         my $tmp = detect_auth_support('IMAP',$host,'CRAM-MD5');
+         if (defined($tmp)) {
+                 if ($tmp eq 'YES') {
+                       print "$WHT SUPPORTED$NRM\n";
+                 } else {
+                   print "$WHT NOT SUPPORTED$NRM\n";
+                 }
+      } else {
+           print $WHT . " ERROR DETECTING$NRM\n";
+         }
+
+         print "DIGEST-MD5:\t";
+         $tmp = detect_auth_support('IMAP',$host,'DIGEST-MD5');
+         if (defined($tmp)) {
+               if ($tmp eq 'YES') {
+                       print "$WHT SUPPORTED$NRM\n";
+               } else {
+                       print "$WHT NOT SUPPORTED$NRM\n";
+               }
+         } else {
+           print $WHT . " ERROR DETECTING$NRM\n";
+         }
+         
+       } 
+         print "\nWhat authentication mechanism do you want to use for IMAP connections?\n\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 IMAP SERVER MUST SUPPORT THE MECHANISM YOU CHOOSE HERE ***\n";
+         print "If you don't understand or are unsure, you probably want \"plain\"\n\n";
+         print "plain, cram-md5, or digest-md5 [$WHT$imap_auth_mech$NRM]: $WHT";
+      $inval=<STDIN>;
+      chomp($inval);
+      if ( ($inval =~ /^cram-md5\b/i) || ($inval =~ /^digest-md5\b/i) || ($inval =~ /^plain\b/i)) {
+        return lc($inval);
+      } else {
+        # user entered garbage or default value so nothing needs to be set
+        return $imap_auth_mech;
+      }
+}
+
+       
+# SMTP authentication type
+# Possible choices: none, plain, cram-md5, digest-md5
+sub command112b {
+    print "If you have already set the hostname and port number, I can try to\n";
+    print "detect the methods your SMTP server supports.\n";
+    print "\nTry to detect auth methods? [y/N]: ";
+    $inval=<STDIN>;
+    chomp($inval);
+    if ($inval =~ /^y\b/i) {
+               # Yes, let's try to detect.
+               print "Detecting supported methods...\n";
+               
+               # Special case!
+               # Check none by trying to relay to junk@birdbrained.org
+               $host = $smtpServerAddress . ':' . $smtpPort;
+               use IO::Socket;
+               my $sock = IO::Socket::INET->new($host);
+               print "Testing none:\t\t$WHT";
+               if (!defined($sock)) {
+                       print " ERROR TESTING\n";
+                       close $sock;
+               } else {
+                       print $sock "mail from: tester\@squirrelmail.org\n";
+                       $got = <$sock>;  # Discard
+                       print $sock "rcpt to: junk\@birdbrained.org\n";
+                       $got = <$sock>;  # This is the important line
+                       if ($got =~ /^250\b/) {  # SMTP will relay without auth
+                               print "SUPPORTED$NRM\n";
+               } else {
+                         print "NOT SUPPORTED$NRM\n";
+               }
+                       print $sock "rset\n";
+                       print $sock "quit\n";
+                       close $sock;
+               }
+               # Try plain (SquirrelMail default)
+               print "Testing plain:\t\t";
+               $tmp=detect_auth_support('SMTP',$host,'LOGIN');
+               if (defined($tmp)) {
+               if ($tmp eq 'YES') {
+               print $WHT . "SUPPORTED$NRM\n";
+               } else {
+               print $WHT . "NOT SUPPORTED$NRM\n";
+               }
+             } else {
+                 print $WHT . "ERROR DETECTING$NRM\n";
+       }
+
+               # Try CRAM-MD5
+        print "Testing CRAM-MD5:\t";
+        $tmp=detect_auth_support('SMTP',$host,'CRAM-MD5');
+        if (defined($tmp)) {
+            if ($tmp eq 'YES') {
+                print $WHT . "SUPPORTED$NRM\n";
+            } else {
+                print $WHT . "NOT SUPPORTED$NRM\n";
+            }
+          } else {
+              print $WHT . "ERROR DETECTING$NRM\n";
+        }
+
+
+        print "Testing DIGEST-MD5:\t";
+        $tmp=detect_auth_support('SMTP',$host,'DIGEST-MD5');
+        if (defined($tmp)) {
+            if ($tmp eq 'YES') {
+                print $WHT . "SUPPORTED$NRM\n";
+            } else {
+                print $WHT . "NOT SUPPORTED$NRM\n";
+            }
+          } else {
+              print $WHT . "ERROR DETECTING$NRM\n";
+        }
+    } 
+    print "\tWhat authentication mechanism do you want to use for SMTP connections?\n";
+    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 SMTP SERVER MUST SUPPORT THE MECHANISM YOU CHOOSE HERE ***\n";
+    print "If you don't understand or are unsure, you probably want \"none\"\n\n";
+    print "none, plain, cram-md5, or digest-md5 [$WHT$smtp_auth_mech$NRM]: $WHT";
+    $inval=<STDIN>;
+    chomp($inval);
+    if ($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 {
+      # user entered garbage, or default value so nothing needs to be set
+         return;
+    }
+}
+
+# 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 {
@@ -2374,7 +2625,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
@@ -2525,21 +2776,30 @@ sub save_data {
        # string
         print CF "\$prefs_val_field = '$prefs_val_field';\n";
        # boolean
-       print CF "\$no_list_for_subscribe = $no_list_for_subscribe;\n";
-        print CF "\n";
-
-        print CF "/**\n";
-        print CF " * Make sure there are no characters after the PHP closing\n";
-        print CF " * tag below (including newline characters and whitespace).\n";
-        print CF " * Otherwise, that character will cause the headers to be\n";
-        print CF " * sent and regular output to begin, which will majorly screw\n";
-        print CF " * things up when we try to send more headers later.\n";
-        print CF " */\n";
-        print CF "?>";
-
-        close CF;
+               print CF "\$no_list_for_subscribe = $no_list_for_subscribe;\n";
 
-        print "Data saved in config.php\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 "\@include SM_PATH . 'config/config_local.php';\n";
+    
+               print CF "\n/**\n";
+           print CF " * Make sure there are no characters after the PHP closing\n";
+           print CF " * tag below (including newline characters and whitespace).\n";
+           print CF " * Otherwise, that character will cause the headers to be\n";
+           print CF " * sent and regular output to begin, which will majorly screw\n";
+           print CF " * things up when we try to send more headers later.\n";
+           print CF " */\n";
+           print CF "?>";
+        
+               close CF;
+
+           print "Data saved in config.php\n";
     } else {
         print "Error saving config.php: $!\n";
     }
@@ -2682,6 +2942,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 +2980,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 =~ /^\.\./ );
 
@@ -2729,3 +2991,71 @@ sub change_to_rel_path() {
 
     return $new_path;
 }
+
+sub detect_auth_support {
+# Attempts to auto-detect if a specific auth mechanism is supported.
+# Called by 'command112a' and 'command112b'
+# ARGS: service-name (IMAP or SMTP), host:port, mech-name (ie. CRAM-MD5)
+
+       # Misc setup
+       use IO::Socket;
+       my $service = shift;
+       my $host = shift;
+       my $mech = shift;
+       # Sanity checks
+       if ((!defined($service)) or (!defined($host)) or (!defined($mech))) {
+         # Error - wrong # of args
+         print "BAD ARGS!\n";
+         return undef;
+       }
+       
+       if ($service eq 'SMTP') {
+               $cmd = "AUTH $mech\n";
+               $logout = "QUIT\n";
+       } elsif ($service eq 'IMAP') {
+               $cmd = "A01 AUTHENTICATE $mech\n";
+               $logout = "C01 LOGOUT\n";
+       } else {
+               # unknown service - whoops.
+               return undef;
+       }
+
+       # Get this show on the road
+    my $sock=IO::Socket::INET->new($host);
+    if (!defined($sock)) {
+        # Connect failed
+        return undef;
+    }
+       my $discard = <$sock>; # Server greeting/banner - who cares..
+       print $sock $cmd;
+
+       my $response = <$sock>;
+       if (!defined($response)) {
+               return undef;
+       }
+
+       # So at this point, we have a response, and it is (hopefully) valid.
+       if ($service eq 'SMTP') {
+               if (($response =~ /^535/) or ($response =~/^502/)) {
+                       # Not supported
+                       close $sock;
+                       return 'NO';
+               }
+       } elsif ($service eq 'IMAP') {
+               if ($response =~ /^A01/) {
+                       # Not supported
+                       close $sock;
+                       return 'NO';
+               }
+       } else {
+               # Unknown service - this shouldn't be able to happen.
+               close $sock;
+               return undef;
+       }
+
+       # If it gets here, the mech is supported
+       print $sock "*\n";  # Attempt to cancel authentication
+       print $sock $logout; # Try to log out, but we don't really care if this fails
+       close $sock;
+       return 'YES';
+}