]> git.sur5r.net Git - contagged/blobdiff - functions.php
more redesign and code cleanup
[contagged] / functions.php
index c517e8407a25a3481f8b594e3643803b85337f8e..9166d31ca0c5e9f77ead7d923a32e21ce2ae7029 100644 (file)
@@ -1,11 +1,11 @@
-<?
+<?php
 
 /**
  * assigns some standard variables to smarty templates
  */
 function smarty_std(){
   global $smarty;
-  $smarty->assign('USER',$_SESSION[ldapab][username]);
+  $smarty->assign('USER',$_SESSION['ldapab']['username']);
 }
 
 /**
@@ -14,21 +14,30 @@ function smarty_std(){
  */
 function ldap_login(){
   global $conf;
-  if(!empty($_SESSION[ldapab][username])){
-    //existing session! Check if valid
-    if($_COOKIE[ldapabconid] != $_SESSION[ldapab][conid]){
+  if(!empty($_SESSION['ldapab']['username'])){
+    // existing session! Check if valid
+    if($_SESSION['ldapab']['browserid'] != auth_browseruid()){
       //session hijacking detected
-       header('Location: login.php?username=');
-       exit;
+      header('Location: login.php?username=');
+      exit;
     }
-  } elseif ($conf[httpd_auth] && !empty($_SERVER[PHP_AUTH_USER])) {
-       $_SESSION[ldapab][username] = $_SERVER[PHP_AUTH_USER];
-       $_SESSION[ldapab][password] = $_SERVER[PHP_AUTH_PW];
+  } elseif ($conf['httpd_auth'] && !empty($_SERVER['PHP_AUTH_USER'])) {
+    // use HTTP auth if wanted and possible
+    $_SESSION['ldapab']['username'] = $_SERVER['PHP_AUTH_USER'];
+    $_SESSION['ldapab']['password'] = $_SERVER['PHP_AUTH_PW'];
+  } elseif (!empty($_COOKIE['ldapabauth'])) {
+    // check persistent cookie
+    $cookie = base64_decode($_COOKIE['ldapabauth']);
+    $cookie = x_Decrypt($cookie,get_cookie_secret());
+    list($u,$p) = unserialize($cookie);
+    $_SESSION['ldapab']['username'] = $u;
+    $_SESSION['ldapab']['password'] = $p;
   }
 
-  if(!do_ldap_bind($_SESSION[ldapab][username],
-                   $_SESSION[ldapab][password],
-                   $_SESSION[ldapab][binddn])){
+  if(empty($_SESSION['ldapab']) ||
+     !do_ldap_bind($_SESSION['ldapab']['username'],
+                   $_SESSION['ldapab']['password'],
+                   $_SESSION['ldapab']['binddn'])){
     header('Location: login.php?username=');
     exit;
   }
@@ -40,22 +49,28 @@ function ldap_login(){
 function do_ldap_bind($user,$pass,$dn=""){
   global $conf;
   global $LDAP_CON;
-  
-  //create global connection to LDAP if nessessary
+
+  //create global connection to LDAP if necessary
   if(!$LDAP_CON){
-    $LDAP_CON = ldap_connect($conf[ldapserver],$conf[ldapport]);
+    if (!empty($conf['ldapurl'])){
+      $LDAP_CON = ldap_connect($conf['ldapurl']);
+    }else{
+      $LDAP_CON = ldap_connect($conf['ldapserver'],$conf['ldapport']);
+    }
     if(!$LDAP_CON){
       die("couldn't connect to LDAP server");
     }
   }
 
+  if($conf['ldapv3']) ldap_set_option($LDAP_CON, LDAP_OPT_PROTOCOL_VERSION, 3);
+
   if(empty($dn)){
     //anonymous bind to lookup users
     //blank binddn or blank bindpw will result in anonymous bind
-    if(!ldap_bind($LDAP_CON,$conf[anonbinddn],$conf[anonbindpw])){
-      die("can not bind anonymously");
+    if(!ldap_bind($LDAP_CON,$conf['anonbinddn'],$conf['anonbindpw'])){
+      die("can not bind for user lookup");
     }
-  
+
     //when no user was given stay connected anonymous
     if(empty($user)){
       set_session('','','');
@@ -63,8 +78,8 @@ function do_ldap_bind($user,$pass,$dn=""){
     }
 
     //get dn for given user
-    $filter = str_replace('%u',$user,$conf[userfilter]);
-    $sr = ldap_search($LDAP_CON, $conf[usertree], $filter);;
+    $filter = str_replace('%u',$user,$conf['userfilter']);
+    $sr = ldap_search($LDAP_CON, $conf['usertree'], $filter);;
     $result = ldap_get_entries($LDAP_CON, $sr);
     if($result['count'] != 1){
       set_session('','','');
@@ -85,15 +100,70 @@ function do_ldap_bind($user,$pass,$dn=""){
 }
 
 /**
- * saves user data to Session
+ * Builds a pseudo UID from browser and IP data
+ *
+ * This is neither unique nor unfakable - still it adds some
+ * security. Using the first part of the IP makes sure
+ * proxy farms like AOLs are stil okay.
+ *
+ * @author  Andreas Gohr <andi@splitbrain.org>
+ *
+ * @return  string  a MD5 sum of various browser headers
+ */
+function auth_browseruid(){
+  $uid  = '';
+  if (empty($_SERVER['HTTP_USER_AGENT']))      { $_SERVER['HTTP_USER_AGENT']='USER_AGENT'; }
+  if (empty($_SERVER['HTTP_ACCEPT_ENCODING'])) { $_SERVER['HTTP_ACCEPT_ENCODING']='ACCEPT_ENCODING'; }
+  if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $_SERVER['HTTP_ACCEPT_LANGUAGE']='ACCEPT_LANGUAGE'; }
+  if (empty($_SERVER['HTTP_ACCEPT_CHARSET']))  { $_SERVER['HTTP_ACCEPT_CHARSET']='ACCEPT_CHARSET'; }
+  $uid .= $_SERVER['HTTP_USER_AGENT'];
+  $uid .= $_SERVER['HTTP_ACCEPT_ENCODING'];
+  $uid .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+  $uid .= $_SERVER['HTTP_ACCEPT_CHARSET'];
+  $uid .= substr($_SERVER['REMOTE_ADDR'],0,strpos($_SERVER['REMOTE_ADDR'],'.'));
+  return md5($uid);
+}
+
+
+/**
+ * saves user data to Session and cookies
  */
 function set_session($user,$pass,$dn){
+  global $conf;
+
   $rand = rand();
-  $_SESSION[ldapab][username]=$user;
-  $_SESSION[ldapab][binddn]  =$dn;
-  $_SESSION[ldapab][password]=$pass;
-  $_SESSION[ldapab][conid]   =$rand;
-  setcookie('ldapabconid',$rand,time()+60*60*24);
+  $_SESSION['ldapab']['username']  = $user;
+  $_SESSION['ldapab']['binddn']    = $dn;
+  $_SESSION['ldapab']['password']  = $pass;
+  $_SESSION['ldapab']['browserid'] = auth_browseruid();
+
+  // (re)set the persistent auth cookie
+  if($user == ''){
+    setcookie('ldapabauth','',time()+60*60*24*365);
+  }elseif(!empty($_REQUEST['remember'])){
+    $cookie = serialize(array($user,$pass));
+    $cookie = x_Encrypt($cookie,get_cookie_secret());
+    $cookie = base64_encode($cookie);
+    setcookie('ldapabauth',$cookie,time()+60*60*24*365);
+  }
+}
+
+/**
+ * Creates a random string to encrypt persistent auth
+ * cookies; the string is stored inside the cache dir
+ */
+function get_cookie_secret(){
+  $file = dirname(__FILE__).'/cache/.htcookiesecret.php';
+  if(@file_exists($file)){
+    return md5(trim(file($file)));
+  }
+
+  $secret = '<?php #'.(rand()*time()).'?>';
+  if(!$fh = fopen($file,'w')) die("Couldn't write to $file");
+  if(fwrite($fh, $secret) === FALSE) die("Couldn't write to $file");
+  fclose($fh);
+
+  return md5($secret);
 }
 
 /**
@@ -126,54 +196,13 @@ function ldap_get_binentries($conn,$srchRslt){
   return $data;
 }
 
+
 /**
  * loads ldap names and their cleartext meanings from
  * entries.conf file and returns it as hash
  */
 function namedentries($flip=false){
-  global $conf;
-
-  $entries[dn]                         = 'dn';
-  $entries[sn]                         = 'name';
-  $entries[givenName]                  = 'givenname';
-  $entries[title]                      = 'title';
-  $entries[o]                          = 'organization';
-  $entries[physicalDeliveryOfficeName] = 'office';
-  $entries[postalAddress]              = 'street';
-  $entries[postalCode]                 = 'zip';
-  $entries[l]                          = 'location';
-  $entries[telephoneNumber]            = 'phone';
-  $entries[facsimileTelephoneNumber]   = 'fax';
-  $entries[mobile]                     = 'mobile';
-  $entries[pager]                      = 'pager';
-  $entries[homePhone]                  = 'homephone';
-  $entries[homePostalAddress]          = 'homestreet';
-  $entries[jpegPhoto]                  = 'photo';
-  $entries[labeledURI]                 = 'url';
-  $entries[description]                = 'note';
-  $entries[manager]                    = 'manager';
-  $entries[cn]                         = 'displayname';
-
-  if($conf[extended]){
-    $entries[anniversary]              = 'anniversary';
-  }
-  if($conf[openxchange]){
-    $entries[mailDomain]               = 'domain';
-    $entries[userCountry]              = 'country';
-    $entries[birthDay]                 = 'birthday';
-    $entries[IPPhone]                  = 'ipphone';
-    $entries[OXUserCategories]         = 'categories';
-    $entries[OXUserInstantMessenger]   = 'instantmessenger';
-    $entries[OXTimeZone]               = 'timezone';
-    $entries[OXUserPosition]           = 'position';
-    $entries[relClientCert]            = 'certificate';
-  }
-
-  if($flip){
-    $entries = array_reverse($entries);
-    $entries = array_flip($entries);
-  }
-  return $entries;
+    trigger_error('deprecated namedentries called',E_USER_WARNING);
 }
 
 /**
@@ -181,34 +210,37 @@ function namedentries($flip=false){
  */
 function prepare_ldap_entry($in){
   global $conf;
-
-  //check dateformat
-  if(!preg_match('/\d\d\d\d-\d\d-\d\d/',$in[anniversary])){
-    $in[anniversary]='';
-  }
-
-  $entries = namedentries(true);
-  foreach(array_keys($in) as $key){
-    if(empty($entries[$key])){
-      $keyname=$key;
-    }else{
-      $keyname=$entries[$key];
-    }
-    if(is_array($in[$key])){
-      $out[$keyname] = $in[$key];
+  global $FIELDS;
+  global $OCLASSES;
+
+  //check dateformats
+  if(!preg_match('/\d\d\d\d-\d\d-\d\d/',$in['anniversary'])) $in['anniversary']='';
+  if(!preg_match('/\d\d\d\d-\d\d-\d\d/',$in['birthday'])) $in['birthday']='';
+
+  // we map all internal names to the configured LDAP attributes here
+  foreach($in as $key => $value){
+    if($FIELDS[$key]){
+        // normal mapped field
+        $out[$FIELDS[$key]][] = $value;
+    }elseif($FIELDS["_$key"]){
+        // mapped multi field
+        if(is_array($value)){
+            $out[$FIELDS["_$key"]] = $value;
+        }else{
+            $out[$FIELDS["_$key"]][] = $value; //shouldn't happen, but to be sure
+        }
     }else{
-      $out[$keyname][] = $in[$key];
+        // no mapping found - assume it to be a LDAP attribute (shouldn't happen)
+        if(is_array($value)){
+            $out[$key] = $value;
+        }else{
+            $out[$key][] = $value;
+        }
     }
   }
 
-  //standard Objectclass
-  $out[objectclass][] = 'inetOrgPerson';
-  if($conf[extended]){
-    $out[objectclass][] = 'contactPerson';
-  }
-  if($conf[openxchange]){
-    $out[objectclass][] = 'OXUserObject';
-  }
+  // add the Objectclasses
+  $out['objectclass'] = $OCLASSES;
 
   return clear_array($out);
 }
@@ -271,16 +303,17 @@ function get_users(){
   global $conf;
   global $LDAP_CON;
 
-  $sr = ldap_list($LDAP_CON,$conf[usertree],"ObjectClass=inetOrgPerson");
+  $sr = ldap_list($LDAP_CON,$conf['usertree'],"ObjectClass=inetOrgPerson");
   $result = ldap_get_binentries($LDAP_CON, $sr);
+  $users = array();
   if(count($result)){
     foreach ($result as $entry){
-      if(!empty($entry[sn][0])){
-        $users[$entry[dn]] = $entry[givenName][0]." ".$entry[sn][0];
+      if(!empty($entry['sn'][0])){
+        $users[$entry['dn']] = $entry['givenName'][0]." ".$entry['sn'][0];
       }
     }
   }
-  return $users; 
+  return $users;
 }
 
 /**
@@ -302,9 +335,9 @@ function ldap_store_objectclasses($dn,$classes){
 
   $sr     = ldap_search($LDAP_CON,$dn,"objectClass=*",array('objectClass'));
   $result = ldap_get_binentries($LDAP_CON, $sr);
-  $set    = $result[0][objectClass];
-  $set    = array_unique_renumber(array_merge($set,$classes));
-  $add[objectClass] = $set;
+  $set    = $result[0]['objectClass'];
+  $set    = array_unique_renumber(array_merge((array)$set,(array)$classes));
+  $add['objectClass'] = $set;
 
   $r = @ldap_mod_replace($LDAP_CON,$dn,$add);
   tpl_ldaperror();
@@ -314,6 +347,58 @@ function ldap_store_objectclasses($dn,$classes){
   print '</pre>';*/
 }
 
+/**
+ * Escape a string to be used in a LDAP filter
+ *
+ * Ported from Perl's Net::LDAP::Util escape_filter_value
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function ldap_filterescape($string){
+  return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
+                            '"\\\\\".join("",unpack("H2","$1"))',
+                            $string);
+}
+
+/**
+ * Queries public and private addressbooks, combining the
+ * results
+ *
+ * @todo This function should be used where ever possible, replacing
+ *       lots of duplicate code
+ */
+function ldap_queryabooks($filter,$types){
+  global $conf;
+  global $LDAP_CON;
+
+  // make sure $types is an array
+  if(!is_array($types)){
+    $types = explode(',',$types);
+    $types = array_map('trim',$types);
+  }
+
+  $results = array();
+  $result1 = array();
+  $result2 = array();
+
+  // public addressbook
+  $sr      = ldap_list($LDAP_CON,$conf['publicbook'],
+                       $filter,$types);
+  $result1 = ldap_get_binentries($LDAP_CON, $sr);
+  ldap_free_result($sr);
+
+  // private addressbook
+  if(!empty($_SESSION['ldapab']['binddn'])){
+    $sr      = @ldap_list($LDAP_CON,$conf['privatebook'].
+                          ','.$_SESSION['ldapab']['binddn'],
+                          $filter,$types);
+    $result2 = ldap_get_binentries($LDAP_CON, $sr);
+  }
+
+  // return merged results
+  return array_merge((array)$result1,(array)$result2);
+}
+
 /**
  * Makes array unique and renumbers the entries
  *
@@ -329,8 +414,40 @@ function array_unique_renumber($somearray){
    return $newarr;
 }
 
+/**
+ * Simple XOR encryption
+ *
+ * @author Dustin Schneider
+ * @link http://www.phpbuilder.com/tips/item.php?id=68
+ */
+function x_Encrypt($string, $key){
+    for($i=0; $i<strlen($string); $i++){
+        for($j=0; $j<strlen($key); $j++){
+            $string[$i] = $string[$i]^$key[$j];
+        }
+    }
+    return $string;
+}
+
+/**
+ * Simple XOR decryption
+ *
+ * @author Dustin Schneider
+ * @link http://www.phpbuilder.com/tips/item.php?id=68
+ */
+function x_Decrypt($string, $key){
+    for($i=0; $i<strlen($string); $i++){
+        for($j=0; $j<strlen($key); $j++){
+            $string[$i] = $key[$j]^$string[$i];
+        }
+    }
+    return $string;
+}
+
 /**
  * Decodes UTF8 recursivly for the given array
+ *
+ * @deprecated
  */
 function utf8_decode_array(&$array) {
   trigger_error('deprecated utf8_decode_array called',E_USER_WARNING);
@@ -348,6 +465,8 @@ function utf8_decode_array(&$array) {
 
 /**
  * Encodes the given array to UTF8 recursively
+ *
+ * @deprecated
  */
 function utf8_encode_array(&$array) {
   trigger_error('deprecated utf8_encode_array called',E_USER_WARNING);
@@ -363,4 +482,5 @@ function utf8_encode_array(&$array) {
   }
 }
 
+
 ?>