]> git.sur5r.net Git - contagged/blob - inc/functions.php
Replace preg_replace('//e') with preg_replace_callback
[contagged] / inc / functions.php
1 <?php
2
3 /**
4  * assigns some standard variables to smarty templates
5  */
6 function smarty_std(){
7   global $smarty;
8   $smarty->assign('USER',$_SESSION['ldapab']['username']);
9 }
10
11 /**
12  * Uses Username and Password from Session to initialize the LDAP handle
13  * If it fails it redirects to login.php
14  */
15 function ldap_login(){
16   global $conf;
17   if(!empty($_SESSION['ldapab']['username'])){
18     // existing session! Check if valid
19     if($_SESSION['ldapab']['browserid'] != auth_browseruid()){
20       //session hijacking detected
21       header('Location: login.php?username=');
22       exit;
23     }
24   } elseif ($conf['httpd_auth'] && !empty($_SERVER['PHP_AUTH_USER'])) {
25     // use HTTP auth if wanted and possible
26     $_SESSION['ldapab']['username'] = $_SERVER['PHP_AUTH_USER'];
27     $_SESSION['ldapab']['password'] = $_SERVER['PHP_AUTH_PW'];
28   } elseif (!empty($_COOKIE['ldapabauth'])) {
29     // check persistent cookie
30     $cookie = base64_decode($_COOKIE['ldapabauth']);
31     $cookie = x_Decrypt($cookie,get_cookie_secret());
32     list($u,$p) = unserialize($cookie);
33     $_SESSION['ldapab']['username'] = $u;
34     $_SESSION['ldapab']['password'] = $p;
35   }
36
37   if(empty($_SESSION['ldapab']) ||
38      !do_ldap_bind($_SESSION['ldapab']['username'],
39                    $_SESSION['ldapab']['password'],
40                    $_SESSION['ldapab']['binddn'])){
41     header('Location: login.php?username=');
42     exit;
43   }
44 }
45
46 /**
47  * Creates a global LDAP connection handle called $LDAP_CON
48  */
49 function do_ldap_bind($user,$pass,$dn=""){
50   global $conf;
51   global $LDAP_CON;
52
53   //create global connection to LDAP if necessary
54   if(!$LDAP_CON){
55     if (!empty($conf['ldapurl'])){
56       $LDAP_CON = ldap_connect($conf['ldapurl']);
57     }else{
58       $LDAP_CON = ldap_connect($conf['ldapserver'],$conf['ldapport']);
59     }
60     if(!$LDAP_CON){
61       die("couldn't connect to LDAP server");
62     }
63   }
64
65   if($conf['ldapv3']) ldap_set_option($LDAP_CON, LDAP_OPT_PROTOCOL_VERSION, 3);
66
67   if(empty($dn)){
68     //anonymous bind to lookup users
69     //blank binddn or blank bindpw will result in anonymous bind
70     if(!@ldap_bind($LDAP_CON,$conf['anonbinddn'],$conf['anonbindpw'])){
71       die("can not bind for user lookup");
72     }
73
74     //when no user was given stay connected anonymous
75     if(empty($user)){
76       set_session('','','');
77       return true;
78     }
79
80     //get dn for given user
81     $filter = str_replace('%u',$user,$conf['userfilter']);
82     $sr = ldap_search($LDAP_CON, $conf['usertree'], $filter);;
83     $result = ldap_get_entries($LDAP_CON, $sr);
84     if($result['count'] != 1){
85       set_session('','','');
86       return false;
87     }
88     $dn = $result[0]['dn'];
89   }
90
91   //bind with dn
92   if(@ldap_bind($LDAP_CON,$dn,$pass)){
93     //bind successful -> set up session
94     set_session($user,$pass,$dn);
95     return true;
96   }
97   //bind failed -> remove session
98   set_session('','','');
99   return false;
100 }
101
102 /**
103  * Builds a pseudo UID from browser and IP data
104  *
105  * This is neither unique nor unfakable - still it adds some
106  * security. Using the first part of the IP makes sure
107  * proxy farms like AOLs are stil okay.
108  *
109  * @author  Andreas Gohr <andi@splitbrain.org>
110  *
111  * @return  string  a MD5 sum of various browser headers
112  */
113 function auth_browseruid(){
114   $uid  = '';
115   if (empty($_SERVER['HTTP_USER_AGENT']))      { $_SERVER['HTTP_USER_AGENT']='USER_AGENT'; }
116   if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $_SERVER['HTTP_ACCEPT_LANGUAGE']='ACCEPT_LANGUAGE'; }
117   if (empty($_SERVER['HTTP_ACCEPT_CHARSET']))  { $_SERVER['HTTP_ACCEPT_CHARSET']='ACCEPT_CHARSET'; }
118   $uid .= $_SERVER['HTTP_USER_AGENT'];
119   $uid .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
120   $uid .= $_SERVER['HTTP_ACCEPT_CHARSET'];
121   $uid .= substr($_SERVER['REMOTE_ADDR'],0,strpos($_SERVER['REMOTE_ADDR'],'.'));
122   return md5($uid);
123 }
124
125
126 /**
127  * saves user data to Session and cookies
128  */
129 function set_session($user,$pass,$dn){
130   global $conf;
131
132   $rand = rand();
133   $_SESSION['ldapab']['username']  = $user;
134   $_SESSION['ldapab']['binddn']    = $dn;
135   $_SESSION['ldapab']['password']  = $pass;
136   $_SESSION['ldapab']['browserid'] = auth_browseruid();
137
138   // (re)set the persistent auth cookie
139   if($user == ''){
140     setcookie('ldapabauth','',time()+60*60*24*365);
141   }elseif(!empty($_REQUEST['remember'])){
142     $cookie = serialize(array($user,$pass));
143     $cookie = x_Encrypt($cookie,get_cookie_secret());
144     $cookie = base64_encode($cookie);
145     setcookie('ldapabauth',$cookie,time()+60*60*24*365);
146   }
147 }
148
149 /**
150  * Creates a random string to encrypt persistent auth
151  * cookies; the string is stored inside the cache dir
152  */
153 function get_cookie_secret(){
154   $file = dirname(__FILE__).'/../cache/.htcookiesecret.php';
155   if(@file_exists($file)){
156     return md5(trim(file($file)));
157   }
158
159   $secret = '<?php #'.(rand()*time()).'?>';
160   if(!$fh = fopen($file,'w')) die("Couldn't write to $file");
161   if(fwrite($fh, $secret) === FALSE) die("Couldn't write to $file");
162   fclose($fh);
163
164   return md5($secret);
165 }
166
167 /**
168  * binary safe function to get all search result data.
169  * It will use ldap_get_values_len() instead and build the array
170  * note: it's similar with the array returned by ldap_get_entries()
171  * except it has no "count" elements
172  *
173  * @author: Original code by Ovidiu Geaboc <ogeaboc@rdanet.com>
174  */
175 function ldap_get_binentries($conn,$srchRslt){
176   if(!@ldap_count_entries($conn,$srchRslt)){
177     return null;
178   }
179   $entry = ldap_first_entry($conn, $srchRslt);
180   $i=0;
181   do {
182     $dn = ldap_get_dn($conn,$entry);
183     $attrs = ldap_get_attributes($conn, $entry);
184     for($j=0; $j<$attrs['count']; $j++) {
185       $vals = ldap_get_values_len($conn, $entry,$attrs[$j]);
186       for($k=0; $k<$vals['count']; $k++){
187         $data[$i][$attrs[$j]][$k]=$vals[$k];
188       }
189     }
190     $data[$i]['dn']=$dn;
191     $i++;
192   }while ($entry = ldap_next_entry($conn, $entry));
193
194   return $data;
195 }
196
197
198 /**
199  * loads ldap names and their cleartext meanings from
200  * entries.conf file and returns it as hash
201  */
202 function namedentries($flip=false){
203     trigger_error('deprecated namedentries called',E_USER_WARNING);
204 }
205
206 /**
207  * Creates an array for submission to ldap from websitedata
208  */
209 function prepare_ldap_entry($in){
210   global $conf;
211   global $FIELDS;
212   global $OCLASSES;
213
214   //check dateformats
215   if(!preg_match('/\d\d\d\d-\d\d-\d\d/',$in['anniversary'])) $in['anniversary']='';
216   if(!preg_match('/\d\d\d\d-\d\d-\d\d/',$in['birthday'])) $in['birthday']='';
217
218   // we map all internal names to the configured LDAP attributes here
219   foreach($in as $key => $value){
220     if($FIELDS[$key]){
221         // normal mapped field
222         $out[$FIELDS[$key]][] = $value;
223     }elseif($FIELDS["_$key"]){
224         // mapped multi field
225         if(is_array($value)){
226             $out[$FIELDS["_$key"]] = $value;
227         }else{
228             $out[$FIELDS["_$key"]][] = $value; //shouldn't happen, but to be sure
229         }
230     }else{
231         // no mapping found we ignore it
232     }
233   }
234
235   // special tag handling for Thunderbird
236   if($conf['tbtaghack'] && in_array('contactPerson',$OCLASSES)){
237     if($in['marker'][0]) $out['custom1'][] = $in['marker'][0];
238     if($in['marker'][1]) $out['custom2'][] = $in['marker'][1];
239     if($in['marker'][2]) $out['custom3'][] = $in['marker'][2];
240     if($in['marker'][3]) $out['custom4'][] = $in['marker'][3];
241   }
242
243
244   // add the Objectclasses
245   $out['objectclass'] = $OCLASSES;
246
247   return clear_array($out);
248 }
249
250 /**
251  * remove empty element from arrays recursively
252  *
253  * @author Original by <xntx@msn.com>
254  */
255 function clear_array ( $a ) {
256   if ($a !== array()) {
257     $b = array();
258     foreach ( $a as $key => $value ) {
259         if (is_array($value)) {
260           if (clear_array($value) !== false) {
261             $b[$key] = clear_array ( $value );
262           }
263         } elseif ($value !== '') {
264           $b[$key] = $value;
265         }
266     }
267     if ($b !== array()) {
268         return $b;
269     } else {
270         return false;
271     }
272   } else {
273     return false;
274   }
275 }
276
277 /**
278  * deletes an entryfrom ldap - optional with recursion
279  *
280  * @author Original by <gabriel@hrz.uni-marburg.de>
281  */
282 function ldap_full_delete($ds,$dn,$recursive=false){
283   if($recursive == false){
284     return(ldap_delete($ds,$dn));
285   }else{
286     //searching for sub entries
287     $sr=ldap_list($ds,$dn,"ObjectClass=*",array(""));
288     $info = ldap_get_entries($ds, $sr);
289     for($i=0;$i<$info['count'];$i++){
290       //deleting recursively sub entries
291       $result=myldap_delete($ds,$info[$i]['dn'],$recursive);
292       if(!$result){
293         //return result code, if delete fails
294         return($result);
295       }
296     }
297     return(ldap_delete($ds,$dn));
298   }
299 }
300
301 /**
302  * Returns all User Accounts as assoziative array
303  */
304 function get_users(){
305   global $conf;
306   global $LDAP_CON;
307
308   $sr = ldap_list($LDAP_CON,$conf['usertree'],"ObjectClass=inetOrgPerson");
309   $result = ldap_get_binentries($LDAP_CON, $sr);
310   $users = array();
311   if(count($result)){
312     foreach ($result as $entry){
313       if(!empty($entry['sn'][0])){
314         $users[$entry['dn']] = $entry['givenName'][0]." ".$entry['sn'][0];
315       }
316     }
317   }
318   return $users;
319 }
320
321 /**
322  * makes sure the given DN contains exactly one space
323  * after each ,
324  */
325 function normalize_dn($dn){
326   $dn = preg_replace('/,/',', ',$dn);
327   $dn = preg_replace('/,\s+/',', ',$dn);
328   return $dn;
329 }
330
331 /**
332  * Merges the given classes with the existing ones
333  */
334 function ldap_store_objectclasses($dn,$classes){
335   global $conf;
336   global $LDAP_CON;
337
338   $sr     = ldap_search($LDAP_CON,$dn,"objectClass=*",array('objectClass'));
339   $result = ldap_get_binentries($LDAP_CON, $sr);
340   $set    = $result[0]['objectClass'];
341   $set    = array_unique_renumber(array_merge((array)$set,(array)$classes));
342   $add['objectClass'] = $set;
343
344   $r = @ldap_mod_replace($LDAP_CON,$dn,$add);
345   tpl_ldaperror('store object classes');
346
347 /*  print '<pre>';
348   print_r($set);
349   print '</pre>';*/
350 }
351
352 /**
353  * Escape a string to be used in a LDAP filter
354  *
355  * Ported from Perl's Net::LDAP::Util escape_filter_value
356  *
357  * @author Andreas Gohr <andi@splitbrain.org>
358  */
359 function ldap_filterescape($string){
360   return preg_replace_callback(
361     '/([\x00-\x1F\*\(\)\\\\])/',
362     function ($matches) {
363       return "\\" . implode("", unpack("H2", $matches[1]));
364     },
365     $string
366   );
367 }
368
369 /**
370  * Queries public and private addressbooks, combining the
371  * results
372  *
373  * @todo This function should be used where ever possible, replacing
374  *       lots of duplicate code
375  */
376 function ldap_queryabooks($filter,$types){
377   global $conf;
378   global $LDAP_CON;
379
380   // make sure $types is an array
381   if(!is_array($types)){
382     $types = explode(',',$types);
383     $types = array_map('trim',$types);
384   }
385
386   $results = array();
387   $result1 = array();
388   $result2 = array();
389   $result3 = array();
390
391   // public addressbook
392   $sr      = @ldap_search($LDAP_CON,$conf['publicbook'],
393                         $filter,$types);
394   tpl_ldaperror();
395   $result1 = ldap_get_binentries($LDAP_CON, $sr);
396   ldap_free_result($sr);
397
398   // private addressbook
399   if(!empty($_SESSION['ldapab']['binddn']) && $conf['privatebook']){
400     $sr      = @ldap_list($LDAP_CON,$conf['privatebook'].
401                           ','.$_SESSION['ldapab']['binddn'],
402                           $filter,$types);
403     if(ldap_errno($LDAP_CON) != 32) tpl_ldaperror(); // ignore missing address book
404     $result2 = ldap_get_binentries($LDAP_CON, $sr);
405   }
406
407   // user account entries
408   if ($conf['displayusertree']) {
409     $sr      = @ldap_list($LDAP_CON,$conf['usertree'],
410                         $filter,$types);
411     tpl_ldaperror();
412     $result3 = ldap_get_binentries($LDAP_CON, $sr);
413     ldap_free_result($sr);
414   }
415
416
417
418   // return merged results
419   return array_merge((array)$result1,(array)$result2,(array)$result3);
420 }
421
422 /**
423  * Makes array unique and renumbers the entries
424  *
425  * @author <kay_rules@yahoo.com>
426  */
427 function array_unique_renumber($somearray){
428    $tmparr = array_unique($somearray);
429    $i=0;
430    foreach ($tmparr as $v) {
431        $newarr[$i] = $v;
432        $i++;
433    }
434    return $newarr;
435 }
436
437 /**
438  * Simple XOR encryption
439  *
440  * @author Dustin Schneider
441  * @link http://www.phpbuilder.com/tips/item.php?id=68
442  */
443 function x_Encrypt($string, $key){
444     for($i=0; $i<strlen($string); $i++){
445         for($j=0; $j<strlen($key); $j++){
446             $string[$i] = $string[$i]^$key[$j];
447         }
448     }
449     return $string;
450 }
451
452 /**
453  * Simple XOR decryption
454  *
455  * @author Dustin Schneider
456  * @link http://www.phpbuilder.com/tips/item.php?id=68
457  */
458 function x_Decrypt($string, $key){
459     for($i=0; $i<strlen($string); $i++){
460         for($j=0; $j<strlen($key); $j++){
461             $string[$i] = $key[$j]^$string[$i];
462         }
463     }
464     return $string;
465 }
466
467 /**
468  * Decodes UTF8 recursivly for the given array
469  *
470  * @deprecated
471  */
472 function utf8_decode_array(&$array) {
473   trigger_error('deprecated utf8_decode_array called',E_USER_WARNING);
474
475   foreach (array_keys($array) as $key) {
476     if($key === 'dn') continue;
477     if($key === 'jpegPhoto') continue;
478     if (is_array($array[$key])) {
479       utf8_decode_array($array[$key]);
480     }else {
481       $array[$key] = utf8_decode($array[$key]);
482     }
483   }
484 }
485
486 /**
487  * Encodes the given array to UTF8 recursively
488  *
489  * @deprecated
490  */
491 function utf8_encode_array(&$array) {
492   trigger_error('deprecated utf8_encode_array called',E_USER_WARNING);
493
494   foreach (array_keys($array) as $key) {
495     if($key === 'dn') continue;
496     if($key === 'jpegPhoto') continue;
497     if (is_array($array[$key])) {
498       utf8_encode_array($array[$key]);
499     }else {
500       $array[$key] = utf8_encode($array[$key]);
501     }
502   }
503 }
504
505 /**
506  * Returns all the fields used in the template
507  *
508  * Returned fields are already decoded to LDAP internals
509  */
510 function get_fields_from_template($tpl){
511     global $smarty;
512     global $FIELDS;
513     $tpl  = $smarty->template_dir.'/'.$tpl;
514     $data = @file_get_contents($tpl);
515     $matches = array();
516     preg_match_all('/\$entry\.(\w+)/',$data,$matches);
517     $matches = array_unique((array) $matches[1]);
518     $return  = array();
519     foreach($matches as $f){
520         if($FIELDS[$f]){
521             $return[] = $FIELDS[$f];
522         }elseif($FIELDS["_$f"]){
523             $return[] = $FIELDS["_$f"];
524         }elseif($f = 'markers'){
525             $return[] = 'marker';
526         }
527     }
528     return $return;
529 }
530