steffen: server/kolab-resource-handlers/kolab-resource-handlers/resmgr kolabfilter.php, 1.30, 1.31 resmgr.php, 1.72, 1.73

cvs at intevation.de cvs at intevation.de
Wed Nov 30 02:20:16 CET 2005


Author: steffen

Update of /kolabrepository/server/kolab-resource-handlers/kolab-resource-handlers/resmgr
In directory doto:/tmp/cvs-serv25579/kolab-resource-handlers/kolab-resource-handlers/resmgr

Modified Files:
	kolabfilter.php resmgr.php 
Log Message:
Finally a From header verifier that might actually work without messing things up!

Index: kolabfilter.php
===================================================================
RCS file: /kolabrepository/server/kolab-resource-handlers/kolab-resource-handlers/resmgr/kolabfilter.php,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- kolabfilter.php	29 Nov 2005 01:51:06 -0000	1.30
+++ kolabfilter.php	30 Nov 2005 01:20:14 -0000	1.31
@@ -98,55 +98,155 @@
   return false;
 }
 
-// Check that mail from our domains have trustable
-// From: header and that mail from the outside
-// does not impersonate any user from our domain
+/**
+ Returns a list of allowed email addresses for user $sasluser
+ or a PEAR_Error object if something croaked.
+*/
+function addrs_for_uid( $sasluser )
+{
+  global $params;
+  /* Connect to the LDAP server and retrieve the users'
+   allowed email addresses */
+  $ldap = ldap_connect($params['ldap_uri']);
+  if (!ldap_bind($ldap, $params['bind_dn'], $params['bind_pw'])) {
+    myLog('Unable to contact LDAP server: ' . ldap_error($ldap));
+    return new PEAR_Error('Unable to contact LDAP server: ' . ldap_error($ldap));
+  }
+  
+  $filter = "(&(objectClass=kolabInetOrgPerson)(|(mail=$sasluser)(uid=$sasluser)))";
+  $result = ldap_search($ldap, $params['base_dn'],
+			$filter,
+			array("dn", "mail", "alias" ));
+  if (!$result) {
+    myLog('Unable to perform LDAP search: ' . ldap_error($ldap));
+    return new PEAR_Error('Unable to perform LDAP search: ' . ldap_error($ldap));
+  }
+  
+  $entries = ldap_get_entries($ldap, $result);
+  if ($entries['count'] != 1) {
+    myLog($entries['count']." objects returned for uid $sasluser");
+    return new PEAR_Error("Temporary LDAP error, unable to look up user $sasluser");
+  }
+  unset($entries[0]['mail']['count']);
+  unset($entries[0]['alias']['count']);
+  $addrs = array_merge($entries[0]['mail'],$entries[0]['alias']);
+  $mail = $entries[0]['mail'][0];
+
+  ldap_free_result($result);
+
+  $filter = "(&(objectClass=kolabInetOrgPerson)(kolabDelegate=$mail))";
+  $result = ldap_search($ldap, $params['base_dn'],
+			$filter,
+			array("dn", "mail" ));
+  if (!$result) {
+    myLog('Unable to perform LDAP search: ' . ldap_error($ldap));
+    return new PEAR_Error('Unable to perform LDAP search: ' . ldap_error($ldap));
+  }
+  
+  $entries = ldap_get_entries($ldap, $result);
+  unset( $entries['count'] );
+  foreach( $entries as $adr ) {
+    if( $adr['mail']['count'] > 0 ) {
+      unset($adr['mail']['count']);
+      $addrs = array_merge($addrs,$adr['mail']);
+    }
+  }
+  ldap_free_result($result);
+  ldap_close($ldap);
+
+  #myLog("Found addresses ".print_r($addrs,true)." for user $sasluser", RM_LOG_DEBUG);
+  return $addrs;
+}
+
+/** Check that the From header is not trying
+    to impersonate a valid user that is not
+    $sasluser. Returns one of:
+
+    * True if From can be accepted
+    * False if From must be rejected
+    * A string with a corrected From header that makes
+      From acceptable
+    * A PEAR_Error object if something croaked
+*/
 function verify_sender( $sasluser, $sender, $from, $client_addr ) {
   global $params;
 
-  // Allow anything from fellow Kolab-hosts
-  /*
+  /* Allow anything from localhost and
+     fellow Kolab-hosts */
+  if( $client_addr == '127.0.0.1' ) return true;
   $kolabhosts = split(',', $params['kolabhosts'] );
   $kolabhosts = array_map( "gethostbyname", $kolabhosts );
   foreach( $kolabhosts as $ip ) {
     if( $client_addr == $ip ) return true;
   }
-  */
 
-  $adrs = imap_rfc822_parse_adrlist($from, $params['email_domain']);
+  if( is_array($params['email_domain']) ) {
+    $domains = $params['email_domain'];
+  } else {
+    $domains = array($params['email_domain']);
+  }
+
+  if( $sasluser ) {
+    if( PEAR::isError($allowed_addrs = addrs_for_uid($sasluser)) ) {
+      myLog("Error reading allowed addresses for $sasluser: ".$allowed_addrs->getMessage(), RM_LOG_ERROR);
+      return $allowed_addrs;
+    }
+  } else {
+    $allowed_addrs = false;
+  }
+
+  $adrs = imap_rfc822_parse_adrlist($from, $params['email_domain'][0]);
   foreach ($adrs as $adr) {
     $from = $adr->mailbox.'@'.$adr->host;
     $fromdom = $adr->host;
-
-    if( is_array($params['email_domain']) ) {
-      $domains = $params['email_domain'];
+    if( $sasluser ) {
+      if( !in_array( strtolower($from), $allowed_addrs ) ) {
+	myLog("$from is not an allowed From address for $sasluser", RM_LOG_DEBUG);
+	return false;
+      }
     } else {
-      $domains = array($params['email_domain']);
+      foreach( $domains as $domain ) {
+	if( strtolower($fromdom) == $domain ) {
+	  if( $params['reject_forged_from_header'] ) {
+	    myLog("$from is not an allowed From address for unauthenticated users", RM_LOG_DEBUG);	    
+	    return false;
+	  } else {
+	    /* Rewrite */
+	    myLog("$from is not an allowed From address for unauthenticated users, rewriting", RM_LOG_DEBUG);
+	    return "$from (UNTRUSTED, sender is <$sender>)";
+	  }
+	}
+      }
     }
+  }
+
+  /* All seems OK */
+  return true;
+
+
+  /* TODO: What do we do about subdomains? */
+  /*
     $senderdom = substr(strrchr($sender, '@'), 1);
     foreach( $domains as $domain ) {
       if( $params['verify_subdomains'] ) {	
-		//myLog( "Checking if ".substr($senderdom, -strlen($domain)-1)." == .$domain", RM_LOG_DEBUG );
-		//myLog( "Checking if ".substr($fromdom, -strlen($domain)-1)." == .$domain", RM_LOG_DEBUG );
-		if( $client_addr != '127.0.0.1' &&
-		    ($senderdom == $domain ||
-		     $fromdom   == $domain ||
-		     substr($senderdom, -strlen($domain)-1) == ".$domain" ||
-		     substr($fromdom, -strlen($domain)-1) == ".$domain" ) &&
-		    $sender != $from ) {
-		  return false;
-		}
+	if( ($senderdom == $domain ||
+	     $fromdom   == $domain ||
+	     substr($senderdom, -strlen($domain)-1) == ".$domain" ||
+	     substr($fromdom, -strlen($domain)-1) == ".$domain" ) &&
+	    $sender != $from ) {
+	  return false;
+	}
       } else {
-		if( $client_addr != '127.0.0.1' && 
-		    ($senderdom == $domain ||
-		     $fromdom   == $domain ) &&
-		    $sender != $from ) {
+	if( ($senderdom == $domain ||
+	     $fromdom   == $domain ) &&
+	    $sender != $from ) {
 		  return false;
-		}
+	}
       }
     }
   }
   return true;
+  */
 }
 
 $options = parse_args( array( 's', 'r', 'c', 'h', 'u' ), $_SERVER['argv']); //getopt("s:r:c:h:u:");
@@ -172,7 +272,7 @@
   $recipients[$i] = strtolower($recipients[$i]);
 }
 
-myLog("Kolabfilter starting up, sender=$sender, recipients=".join(',', $recipients)
+myLog("Kolabfilter starting up, user=$sasl_username, sender=$sender, recipients=".join(',', $recipients)
       .", client_address=$client_address", RM_LOG_DEBUG);
 
 $ical = false;
@@ -189,23 +289,22 @@
     // Done with headers
     $headers_done = true;
     if( $from && $params['verify_from_header'] ) {
-      if( !verify_sender( $sasl_username, $sender, strtolower($from), $client_address) ) {
-		myLog("$sender and $from differ!", RM_LOG_DEBUG);
-		if( $params['reject_forged_from_header'] ) {
-		  // Always reject mismatches
-		  $senderok = false;
-		} else {
-		  // Only rewrite if from is ours and envelope not
-		  if( is_my_domain( $from ) && !is_my_domain( $sender ) ) {
-		    if( !ereg( "\(UNTRUSTED, sender is $sender\)", $from ) ) {
-		      myLog("Rewriting From header", RM_LOG_DEBUG);
-		      $rewrittenfrom = "From: $from (UNTRUSTED, sender is $sender)\r\n";
-		    } /* else already rewritten */
-		  } else {
-			// Not our domain in From, reject
-			$senderok = false;
-		  }
-		}
+      $rc = verify_sender( $sasl_username, $sender, $from, $client_address);
+      if( PEAR::isError($rc) ) {
+	$msg = $error->getMessage().", code ".$error->getCode();
+	mylog($msg, RM_LOG_ERROR);
+	fwrite(STDOUT, $msg."\n"); 
+	exit(EX_TEMPFAIL);
+      } else if( $rc === true ) {
+	/* All OK, do nothing */
+      } else if( $rc === false ) {
+	/* Reject! */
+	$senderok = false;
+      } else if( is_string($rc) ) {
+	/* Rewrite from */
+	if( strpos( $from, $rc )===false ) {
+	  $rewrittenfrom = "From: $rc\r\n";
+	}
       }
     }
   } else if( !$headers_done && $params['allow_sender_header'] && eregi( '^Sender: (.*)', $line, $regs ) ) {

Index: resmgr.php
===================================================================
RCS file: /kolabrepository/server/kolab-resource-handlers/kolab-resource-handlers/resmgr/resmgr.php,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -d -r1.72 -r1.73
--- resmgr.php	29 Nov 2005 03:08:11 -0000	1.72
+++ resmgr.php	30 Nov 2005 01:20:14 -0000	1.73
@@ -651,6 +651,7 @@
       myLog('Unable to get mailbox list: ' . $mailboxes->getMessage(), RM_LOG_ERROR);      
     }
     $calmbox = false;
+    myLog('Mailboxes under account: '.print_r($mailboxes,true), RM_LOG_DEBUG);
     foreach( $mailboxes as $mailbox ) {
       $a = $imap->getAnnotation('/vendor/kolab/folder-type',
 				/*array('value.shared' => 'event.default')*/'value.shared',





More information about the commits mailing list