FusionDirectory
class_ldap.inc
Go to the documentation of this file.
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2003-2010 Cajus Pollmeier
5  Copyright (C) 2003 Alejandro Escanero Blanco <aescanero@chaosdimension.org>
6  Copyright (C) 1998 Eric Kilfoil <eric@ipass.net>
7  Copyright (C) 2011-2016 FusionDirectory
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23 
34 class LDAP
35 {
36  var $hascon = FALSE;
37  var $reconnect = FALSE;
38  var $tls = FALSE;
39 
45  var $cid = FALSE;
46 
47  var $hasres = [];
48  var $sr = [];
49  var $re = [];
50  var $basedn = "";
51 
52  /* 0 if we are fetching the first entry, otherwise 1 */
53  var $start = [];
54 
55  /* Any error messages to be returned can be put here */
56  var $error = "";
57 
58  var $srp = 0;
59 
60  /* Information read from slapd.oc.conf */
61  var $objectClasses = [];
62  /* the dn for the bind */
63  var $binddn = "";
64  /* the dn's password for the bind */
65  var $bindpw = "";
66  var $hostname = "";
67  var $follow_referral = FALSE;
68  var $referrals = [];
69 
70  /* 0, empty or negative values will disable this check */
71  var $max_ldap_query_time = 0;
72 
86  function __construct ($binddn, $bindpw, $hostname, $follow_referral = FALSE, $tls = FALSE)
87  {
88  global $config;
89  $this->follow_referral = $follow_referral;
90  $this->tls = $tls;
91  $this->binddn = $binddn;
92  $this->bindpw = $bindpw;
93  $this->hostname = $hostname;
94 
95  /* Check if MAX_LDAP_QUERY_TIME is defined */
96  if (is_object($config) && ($config->get_cfg_value("ldapMaxQueryTime") != "")) {
97  $str = $config->get_cfg_value("ldapMaxQueryTime");
98  $this->max_ldap_query_time = (float)($str);
99  }
100 
101  $this->connect();
102  }
103 
106  public function __wakeup ()
107  {
108  $this->cid = FALSE;
109  $this->hascon = FALSE;
110  }
111 
127  public static function init (string $server, string $base, string $binddn = '', string $pass = ''): LDAP
128  {
129  global $config;
130 
131  $ldap = new LDAP($binddn, $pass, $server,
132  isset($config->current['LDAPFOLLOWREFERRALS']) && $config->current['LDAPFOLLOWREFERRALS'] == 'TRUE',
133  isset($config->current['LDAPTLS']) && $config->current['LDAPTLS'] == 'TRUE');
134 
135  /* Sadly we've no proper return values here. Use the error message instead. */
136  if (!$ldap->success()) {
137  throw new FatalError(htmlescape(sprintf(_('FATAL: Error when connecting to LDAP. Server said "%s".'), $ldap->get_error())));
138  }
139 
140  /* Preset connection base to $base and return to caller */
141  $ldap->cd($base);
142  return $ldap;
143  }
144 
150  function getSearchResource ()
151  {
152  $this->sr[$this->srp] = NULL;
153  $this->start[$this->srp] = 0;
154  $this->hasres[$this->srp] = FALSE;
155  return $this->srp++;
156  }
157 
163  static function prepare4filter ($dn)
164  {
165  trigger_error('deprecated, use ldap_escape_f instead');
166  return ldap_escape_f($dn);
167  }
168 
174  static function invalidCredentialsError (): string
175  {
176  return _(ldap_err2str(49));
177  }
178 
184  function connect ()
185  {
186  $this->hascon = FALSE;
187  $this->reconnect = FALSE;
188  if ($this->cid = @ldap_connect($this->hostname)) {
189  @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
190  if ($this->follow_referral) {
191  @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
192  @ldap_set_rebind_proc($this->cid, [&$this, 'rebind']);
193  }
194  if ($this->tls) {
195  @ldap_start_tls($this->cid);
196  }
197 
198  $this->error = 'No Error';
199  $serverctrls = [];
200  if (class_available('ppolicyAccount')) {
201  $serverctrls = [['oid' => LDAP_CONTROL_PASSWORDPOLICYREQUEST]];
202  }
203  $result = @ldap_bind_ext($this->cid, $this->binddn, $this->bindpw, $serverctrls);
204  if (@ldap_parse_result($this->cid, $result, $errcode, $matcheddn, $errmsg, $referrals, $ctrls)) {
205  if (isset($ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error'])) {
206  $this->hascon = FALSE;
207  switch ($ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error']) {
208  case 0:
209  /* passwordExpired - password has expired and must be reset */
210  $this->error = _('It seems your user password has expired. Please use <a href="recovery.php">password recovery</a> to change it.');
211  break;
212  case 1:
213  /* accountLocked */
214  $this->error = _('Account locked. Please contact your system administrator!');
215  break;
216  case 2:
217  /* changeAfterReset - password must be changed before the user will be allowed to perform any other operation */
218  $this->error = 'changeAfterReset';
219  break;
220  case 3:
221  /* passwordModNotAllowed */
222  case 4:
223  /* mustSupplyOldPassword */
224  case 5:
225  /* insufficientPasswordQuality */
226  case 6:
227  /* passwordTooShort */
228  case 7:
229  /* passwordTooYoung */
230  case 8:
231  /* passwordInHistory */
232  default:
233  $this->error = sprintf(_('Unexpected ppolicy error "%s", please contact the administrator'), $ctrls[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error']);
234  break;
235  }
236  // Note: Also available: expire, grace
237  } else {
238  $this->hascon = ($errcode == 0);
239  if ($errcode == 49) {
240  $this->error = static::invalidCredentialsError();
241  } elseif (empty($errmsg)) {
242  $this->error = ldap_err2str($errcode);
243  } else {
244  $this->error = $errmsg;
245  }
246  }
247  } else {
248  $this->error = 'Parsing of LDAP result from bind failed';
249  $this->hascon = FALSE;
250  }
251  } else {
252  $this->error = 'Could not connect to LDAP server';
253  }
254 
255  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'connect');
256  }
257 
261  function rebind ($ldap, $referral)
262  {
263  $credentials = $this->get_credentials($referral);
264  if (@ldap_bind($ldap, $credentials['ADMINDN'], $credentials['ADMINPASSWORD'])) {
265  $this->error = "Success";
266  $this->hascon = TRUE;
267  $this->reconnect = TRUE;
268  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rebind');
269  return 0;
270  } else {
271  $this->error = "Could not bind to " . $credentials['ADMINDN'];
272  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rebind');
273  return NULL;
274  }
275  }
276 
280  function reconnect ()
281  {
282  if ($this->reconnect) {
283  $this->unbind();
284  }
285  }
286 
290  function unbind ()
291  {
292  @ldap_unbind($this->cid);
293  $this->cid = FALSE;
294  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, '', 'unbind');
295  }
296 
300  function disconnect ()
301  {
302  if ($this->hascon) {
303  @ldap_close($this->cid);
304  $this->hascon = FALSE;
305  $this->cid = FALSE;
306  }
307  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, '', 'disconnect');
308  }
309 
315  function cd ($dir)
316  {
317  if ($dir == '..') {
318  $this->basedn = $this->getParentDir();
319  } else {
320  $this->basedn = $dir;
321  }
322  }
323 
331  function getParentDir ($basedn = '')
332  {
333  if ($basedn == '') {
334  $basedn = $this->basedn;
335  }
336  return preg_replace("/[^,]*[,]*[ ]*(.*)/", "$1", $basedn);
337  }
338 
350  function search ($srp, $filter, $attrs = [], $scope = 'subtree', array $controls = NULL)
351  {
352  if ($this->hascon) {
353  if ($this->reconnect) {
354  $this->connect();
355  }
356 
357  $startTime = microtime(TRUE);
358  $this->clearResult($srp);
359  switch (strtolower($scope)) {
360  case 'base':
361  if (isset($controls)) {
362  $this->sr[$srp] = @ldap_read($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
363  } else {
364  $this->sr[$srp] = @ldap_read($this->cid, $this->basedn, $filter, $attrs);
365  }
366  break;
367  case 'one':
368  if (isset($controls)) {
369  $this->sr[$srp] = @ldap_list($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
370  } else {
371  $this->sr[$srp] = @ldap_list($this->cid, $this->basedn, $filter, $attrs);
372  }
373  break;
374  case 'subtree':
375  default:
376  if (isset($controls)) {
377  $this->sr[$srp] = @ldap_search($this->cid, $this->basedn, $filter, $attrs, 0, 0, 0, LDAP_DEREF_NEVER, $controls);
378  } else {
379  $this->sr[$srp] = @ldap_search($this->cid, $this->basedn, $filter, $attrs);
380  }
381  break;
382  }
383  $this->error = @ldap_error($this->cid);
384  $this->resetResult($srp);
385  $this->hasres[$srp] = TRUE;
386 
387  /* Check if query took longer as specified in max_ldap_query_time */
388  $diff = microtime(TRUE) - $startTime;
389  if ($this->max_ldap_query_time && ($diff > $this->max_ldap_query_time)) {
390  $warning = new FusionDirectoryWarning(htmlescape(sprintf(_('LDAP performance is poor: last query took about %.2fs!'), $diff)));
391  $warning->display();
392  }
393 
394  $this->log("LDAP operation: time=".$diff." operation=search('".$this->basedn."', '$filter')");
395  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'search(base="'.$this->basedn.'",scope="'.$scope.'",filter="'.$filter.'")');
396  return $this->sr[$srp];
397  } else {
398  $this->error = "Could not connect to LDAP server";
399  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'search(base="'.$this->basedn.'",scope="'.$scope.'",filter="'.$filter.'")');
400  return "";
401  }
402  }
403 
410  function parse_result ($srp): array
411  {
412  if ($this->hascon && $this->hasres[$srp]) {
413  if (ldap_parse_result($this->cid, $this->sr[$srp], $errcode, $matcheddn, $errmsg, $referrals, $controls)) {
414  return [$errcode, $matcheddn, $errmsg, $referrals, $controls];
415  }
416  throw new FusionDirectoryException(_('Parsing LDAP result failed'));
417  } else {
418  throw new FusionDirectoryException(_('No LDAP result to parse'));
419  }
420  }
421 
422  /*
423  * \brief List
424  *
425  * \param integer $srp
426  *
427  * \param string $filter Initialized at "(objectclass=*)"
428  *
429  * \param string $basedn Empty string
430  *
431  * \param array $attrs
432  */
433  function ls ($srp, $filter = "(objectclass=*)", $basedn = "", $attrs = ["*"])
434  {
435  trigger_error('deprecated');
436  $this->cd($basedn);
437  return $this->search($srp, $filter, $attrs, 'one');
438  }
439 
440  /*
441  * \brief Concatenate
442  *
443  * \param integer $srp
444  *
445  * \param string $dn The DN
446  *
447  * \param array $attrs
448  *
449  * \param string $filter Initialized at "(objectclass=*)"
450  */
451  function cat ($srp, $dn, $attrs = ["*"], $filter = "(objectclass=*)")
452  {
453  if ($this->hascon) {
454  if ($this->reconnect) {
455  $this->connect();
456  }
457 
458  $this->clearResult($srp);
459  $this->sr[$srp] = @ldap_read($this->cid, $dn, $filter, $attrs);
460  $this->error = @ldap_error($this->cid);
461  $this->resetResult($srp);
462  $this->hasres[$srp] = TRUE;
463  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'cat(dn="'.$dn.'",filter="'.$filter.'")');
464  return $this->sr[$srp];
465  } else {
466  $this->error = "Could not connect to LDAP server";
467  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'cat(dn="'.$dn.'",filter="'.$filter.'")');
468  return "";
469  }
470  }
471 
479  function object_match_filter ($dn, $filter)
480  {
481  if ($this->hascon) {
482  if ($this->reconnect) {
483  $this->connect();
484  }
485  $res = @ldap_read($this->cid, $dn, $filter, ["objectClass"]);
486  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'object_match_filter(dn="'.$dn.'",filter="'.$filter.'")');
487  return @ldap_count_entries($this->cid, $res);
488  } else {
489  $this->error = "Could not connect to LDAP server";
490  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'object_match_filter(dn="'.$dn.'",filter="'.$filter.'")');
491  return FALSE;
492  }
493  }
494 
500  function set_size_limit ($size)
501  {
502  /* Ignore zero settings */
503  if ($size == 0) {
504  @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
505  }
506  if ($this->hascon) {
507  @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
508  } else {
509  $this->error = "Could not connect to LDAP server";
510  }
511  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $size, 'set_size_limit');
512  }
513 
520  function fetch ($srp, bool $cleanUpNumericIndices = FALSE)
521  {
522  if ($this->hascon) {
523  if ($this->hasres[$srp]) {
524  if ($this->start[$srp] == 0) {
525  if ($this->sr[$srp]) {
526  $this->start[$srp] = 1;
527  $this->re[$srp] = @ldap_first_entry($this->cid, $this->sr[$srp]);
528  } else {
529  return [];
530  }
531  } else {
532  $this->re[$srp] = @ldap_next_entry($this->cid, $this->re[$srp]);
533  }
534  $att = [];
535  if ($this->re[$srp]) {
536  $att = @ldap_get_attributes($this->cid, $this->re[$srp]);
537  $att['dn'] = trim(@ldap_get_dn($this->cid, $this->re[$srp]));
538  if ($cleanUpNumericIndices && isset($att['count'])) {
539  for ($i = 0; $i < $att['count']; ++$i) {
540  /* Remove numeric keys */
541  unset($att[$i]);
542  }
543  unset($att['count']);
544  }
545  }
546  $this->error = @ldap_error($this->cid);
547  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'fetch()');
548  return $att;
549  } else {
550  $this->error = "Perform a fetch with no search";
551  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'fetch()');
552  return "";
553  }
554  } else {
555  $this->error = "Could not connect to LDAP server";
556  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'fetch()');
557  return "";
558  }
559  }
560 
566  function resetResult ($srp)
567  {
568  $this->start[$srp] = 0;
569  }
570 
576  function clearResult ($srp)
577  {
578  if ($this->hasres[$srp]) {
579  $this->hasres[$srp] = FALSE;
580  @ldap_free_result($this->sr[$srp]);
581  }
582  }
583 
589  function getDN ($srp)
590  {
591  if ($this->hascon) {
592  if ($this->hasres[$srp]) {
593  if (!$this->re[$srp]) {
594  $this->error = "Perform a Fetch with no valid Result";
595  } else {
596  $rv = @ldap_get_dn($this->cid, $this->re[$srp]);
597 
598  $this->error = @ldap_error($this->cid);
599  return trim($rv);
600  }
601  } else {
602  $this->error = "Perform a Fetch with no Search";
603  return "";
604  }
605  } else {
606  $this->error = "Could not connect to LDAP server";
607  return "";
608  }
609  }
610 
616  function count ($srp)
617  {
618  if ($this->hascon) {
619  if ($this->hasres[$srp]) {
620  $rv = @ldap_count_entries($this->cid, $this->sr[$srp]);
621  $this->error = @ldap_error($this->cid);
622  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'count()');
623  return $rv;
624  } else {
625  $this->error = "Perform a Fetch with no Search";
626  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'count()');
627  return "";
628  }
629  } else {
630  $this->error = "Could not connect to LDAP server";
631  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'count()');
632  return "";
633  }
634  }
635 
636 
644  function rm ($attrs = "", $dn = "")
645  {
646  if ($this->hascon) {
647  if ($this->reconnect) {
648  $this->connect();
649  }
650  if ($dn == '') {
651  $dn = $this->basedn;
652  }
653 
654  $r = ldap_mod_del($this->cid, $dn, $attrs);
655  $this->error = @ldap_error($this->cid);
656  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rm('.$dn.')');
657  return $r;
658  } else {
659  $this->error = 'Could not connect to LDAP server';
660  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rm('.$dn.')');
661  return '';
662  }
663  }
664 
665  function mod_add ($attrs = "", $dn = "")
666  {
667  if ($this->hascon) {
668  if ($this->reconnect) {
669  $this->connect();
670  }
671  if ($dn == "") {
672  $dn = $this->basedn;
673  }
674 
675  $r = @ldap_mod_add($this->cid, $dn, $attrs);
676  $this->error = @ldap_error($this->cid);
677  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'mod_add('.$dn.')');
678  return $r;
679  } else {
680  $this->error = "Could not connect to LDAP server";
681  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'mod_add('.$dn.')');
682  return "";
683  }
684  }
685 
691  function rmdir ($deletedn)
692  {
693  if ($this->hascon) {
694  if ($this->reconnect) {
695  $this->connect();
696  }
697  $r = @ldap_delete($this->cid, $deletedn);
698  $this->error = @ldap_error($this->cid);
699  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rmdir('.$deletedn.')');
700  return ($r ? $r : 0);
701  } else {
702  $this->error = "Could not connect to LDAP server";
703  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rmdir('.$deletedn.')');
704  return "";
705  }
706  }
707 
708 
718  function rename_dn ($source, $dest)
719  {
720  /* Check if source and destination are the same entry */
721  if (strtolower($source) == strtolower($dest)) {
722  trigger_error("Source and destination can't be the same entry.");
723  $this->error = "Source and destination can't be the same entry.";
724  return FALSE;
725  }
726 
727  /* Check if destination entry exists */
728  if ($this->dn_exists($dest)) {
729  trigger_error("Destination '$dest' already exists.");
730  $this->error = "Destination '$dest' already exists.";
731  return FALSE;
732  }
733 
734  /* Extract the name and the parent part out ouf source dn.
735  e.g. cn=herbert,ou=department,dc=...
736  parent => ou=department,dc=...
737  dest_rdn => cn=herbert
738  */
739  $parent = preg_replace("/^[^,]+,/", "", $dest);
740  $dest_rdn = preg_replace("/,.*$/", "", $dest);
741 
742  if ($this->hascon) {
743  if ($this->reconnect) {
744  $this->connect();
745  }
746  /* We have to pass TRUE as deleteoldrdn in case the attribute is single-valued */
747  $r = ldap_rename($this->cid, $source, $dest_rdn, $parent, TRUE);
748  $this->error = ldap_error($this->cid);
749 
750  /* Check if destination dn exists, if not the server may not support this operation */
751  $r &= $this->dn_exists($dest);
752  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rename("'.$source.'","'.$dest.'")');
753  return $r;
754  } else {
755  $this->error = "Could not connect to LDAP server";
756  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rename("'.$source.'","'.$dest.'")');
757  return FALSE;
758  }
759  }
760 
761 
773  function rmdir_recursive ($srp, $deletedn)
774  {
775  if ($this->hascon) {
776  if ($this->reconnect) {
777  $this->connect();
778  }
779  $delarray = [];
780 
781  /* Get sorted list of dn's to delete */
782  $this->cd($deletedn);
783  $this->search($srp, '(objectClass=*)', ['dn']);
784  while ($attrs = $this->fetch($srp)) {
785  $delarray[$attrs['dn']] = strlen($attrs['dn']);
786  }
787  arsort($delarray);
788  reset($delarray);
789 
790  /* Really Delete ALL dn's in subtree */
791  $r = TRUE;
792  foreach (array_keys($delarray) as $key) {
793  $r = @ldap_delete($this->cid, $key);
794  if ($r === FALSE) {
795  break;
796  }
797  }
798  $this->error = @ldap_error($this->cid);
799  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rmdir_recursive("'.$deletedn.'")');
800  return ($r ? $r : 0);
801  } else {
802  $this->error = "Could not connect to LDAP server";
803  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'rmdir_recursive("'.$deletedn.'")');
804  return "";
805  }
806  }
807 
808  function makeReadableErrors ($error, $attrs)
809  {
810  if ($this->success()) {
811  return "";
812  }
813 
814  $str = "";
815  if (isset($attrs['objectClass'])
816  && preg_match("/^objectClass: value #([0-9]*) invalid per syntax$/", $this->get_additional_error(), $m)) {
817  $ocs = $attrs['objectClass'];
818  if (!is_array($ocs)) {
819  $ocs = [$ocs];
820  }
821  if (isset($ocs[$m[1]])) {
822  $str .= " - <b>objectClass: ".$ocs[$m[1]]."</b>";
823  }
824  }
825  if ($error == "Undefined attribute type") {
826  $str = " - <b>attribute: ".preg_replace("/:.*$/", "", $this->get_additional_error())."</b>";
827  }
828 
829  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $attrs, "Erroneous data");
830 
831  return $str;
832  }
833 
839  function modify (array $attrs)
840  {
841  if (count($attrs) == 0) {
842  return 0;
843  }
844  if ($this->hascon) {
845  if ($this->reconnect) {
846  $this->connect();
847  }
848  $r = @ldap_modify($this->cid, $this->basedn, $attrs);
849  $this->error = @ldap_error($this->cid);
850  if (!$this->success()) {
851  $this->error .= $this->makeReadableErrors($this->error, $attrs);
852  }
853  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'modify('.$this->basedn.')');
854  return ($r ? $r : 0);
855  } else {
856  $this->error = "Could not connect to LDAP server";
857  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'modify('.$this->basedn.')');
858  return "";
859  }
860  }
861 
867  function modify_batch (array $changes)
868  {
869  if (count($changes) == 0) {
870  return TRUE;
871  }
872  if ($this->hascon) {
873  if ($this->reconnect) {
874  $this->connect();
875  }
876  $r = @ldap_modify_batch($this->cid, $this->basedn, $changes);
877  $this->error = @ldap_error($this->cid);
878  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'modify_batch('.$this->basedn.')');
879  return $r;
880  } else {
881  $this->error = 'Could not connect to LDAP server';
882  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'modify_batch('.$this->basedn.')');
883  return FALSE;
884  }
885  }
886 
892  function add ($attrs)
893  {
894  if ($this->hascon) {
895  if ($this->reconnect) {
896  $this->connect();
897  }
898  $r = @ldap_add($this->cid, $this->basedn, $attrs);
899  $this->error = @ldap_error($this->cid);
900  if (!$this->success()) {
901  $this->error .= $this->makeReadableErrors($this->error, $attrs);
902  }
903  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'add('.$this->basedn.')');
904  return ($r ? $r : 0);
905  } else {
906  $this->error = "Could not connect to LDAP server";
907  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->error, 'add('.$this->basedn.')');
908  return "";
909  }
910  }
911 
912  /*
913  * $target is a dn, i.e. "ou=example,ou=orga,dc=base"
914  *
915  * Creates missing trees, in our example ou=orga,dc=base will get created if not existing, same thing for ou=example,ou=orga,dc=base
916  * */
917  function create_missing_trees ($srp, $target, $ignoreReferralBases = TRUE)
918  {
919  $real_path = substr($target, 0, strlen($target) - strlen($this->basedn) - 1);
920 
921  if ($target == $this->basedn) {
922  $l = ["dummy"];
923  } else {
924  $l = array_reverse(ldap_explode_dn($real_path, 0));
925  }
926  unset($l['count']);
927  $cdn = $this->basedn;
928 
929  /* Load schema if available... */
930  $classes = $this->get_objectclasses();
931 
932  foreach ($l as $part) {
933  if ($part != "dummy") {
934  $cdn = "$part,$cdn";
935  }
936 
937  /* Ignore referrals */
938  if ($ignoreReferralBases) {
939  $found = FALSE;
940  foreach ($this->referrals as $ref) {
941  if ($ref['BASE'] == $cdn) {
942  $found = TRUE;
943  break;
944  }
945  }
946  if ($found) {
947  continue;
948  }
949  }
950 
951  /* Create missing entry? */
952  if (!$this->dn_exists($cdn)) {
953  $type = preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
954  $param = preg_replace('/^[^=]+=([^,]+).*$/', '\\1', $cdn);
955  $param = preg_replace(['/\\\\,/','/\\\\"/'], [',','"'], $param);
956 
957  $na = [];
958 
959  /* Automatic or traditional? */
960  if (count($classes)) {
961  if ($type == 'l') {
962  /* Locality has l as MAY so autodetection fails */
963  $ocname = 'locality';
964  } else {
965  /* Get name of first matching objectClass */
966  $ocname = '';
967  foreach ($classes as $class) {
968  if (isset($class['MUST']) && in_array($type, $class['MUST'])) {
969  /* Look for first classes that is structural... */
970  if (isset($class['STRUCTURAL'])) {
971  $ocname = $class['NAME'];
972  break;
973  }
974 
975  /* Look for classes that are auxiliary... */
976  if (isset($class['AUXILIARY'])) {
977  $ocname = $class['NAME'];
978  }
979  }
980  }
981  }
982 
983  /* Bail out, if we've nothing to do... */
984  if ($ocname == '') {
985  throw new FusionDirectoryError(htmlescape(sprintf(_('Cannot automatically create subtrees with RDN "%s": no object class found!'), $type)));
986  }
987 
988  /* Assemble_entry */
989  $na['objectClass'] = [$ocname];
990  if (isset($classes[$ocname]['AUXILIARY'])) {
991  $na['objectClass'][] = $classes[$ocname]['SUP'];
992  }
993  if ($type == 'dc') {
994  /* This is bad actually, but - tell me a better way? */
995  $na['objectClass'][] = 'organization';
996  $na['o'] = $param;
997  }
998  $na[$type] = $param;
999 
1000  // Fill in MUST values - but do not overwrite existing ones.
1001  $oc = $ocname;
1002  do {
1003  if (isset($classes[$oc]['MUST']) && is_array($classes[$oc]['MUST'])) {
1004  foreach ($classes[$oc]['MUST'] as $attr) {
1005  if (isset($na[$attr]) && !empty($na[$attr])) {
1006  continue;
1007  }
1008  $na[$attr] = 'filled';
1009  }
1010  }
1011  $oc = ($classes[$oc]['SUP'] ?? NULL);
1012  } while ($oc);
1013  } else {
1014  /* Use alternative add... */
1015  switch ($type) {
1016  case 'ou':
1017  $na['objectClass'] = 'organizationalUnit';
1018  $na['ou'] = $param;
1019  break;
1020  case 'dc':
1021  $na['objectClass'] = ['dcObject', 'top', 'organization'];
1022  $na['dc'] = $param;
1023  $na['o'] = $param;
1024  break;
1025  default:
1026  throw new FusionDirectoryError(htmlescape(sprintf(_('Cannot automatically create subtrees with RDN "%s": not supported'), $type)));
1027  }
1028  }
1029  $this->cd($cdn);
1030  $this->add($na);
1031 
1032  if (!$this->success()) {
1033  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $cdn, 'dn');
1034  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $na, 'Content');
1035  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $this->get_error(), 'LDAP error');
1036 
1037  throw new FusionDirectoryLdapError($cdn, LDAP_ADD, $this->get_error(), $this->get_errno());
1038  }
1039  }
1040  }
1041  }
1042 
1043 
1050  {
1051  $additional_error = '';
1052  @ldap_get_option($this->cid, LDAP_OPT_ERROR_STRING, $additional_error);
1053  return $additional_error;
1054  }
1055 
1061  function success (): bool
1062  {
1063  return (trim($this->error) === 'Success');
1064  }
1065 
1069  function get_error ($details = TRUE): string
1070  {
1071  if (($this->error == 'Success') || !$details) {
1072  return $this->error;
1073  } else {
1074  $adderror = $this->get_additional_error();
1075  if ($adderror != '') {
1076  return sprintf(
1077  _('%s (%s, while operating on "%s" using LDAP server "%s")'),
1078  $this->error, $adderror, $this->basedn, $this->hostname
1079  );
1080  } else {
1081  return sprintf(
1082  _('%s (while operating on LDAP server "%s")'),
1083  $this->error, $this->hostname
1084  );
1085  }
1086  }
1087  }
1088 
1094  function get_errno (): int
1095  {
1096  if ($this->error == 'Success') {
1097  return 0;
1098  } else {
1099  return @ldap_errno($this->cid) ?? -1;
1100  }
1101  }
1102 
1108  function hitSizeLimit (): bool
1109  {
1110  /* LDAP_SIZELIMIT_EXCEEDED 0x04 */
1111  return ($this->get_errno() == 0x04);
1112  }
1113 
1114  function get_credentials ($url, $referrals = NULL)
1115  {
1116  $ret = [];
1117  $url = preg_replace('!\?\?.*$!', '', $url);
1118  $server = preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
1119 
1120  if ($referrals === NULL) {
1121  $referrals = $this->referrals;
1122  }
1123 
1124  if (isset($referrals[$server])) {
1125  return $referrals[$server];
1126  } else {
1127  $ret['ADMINDN'] = $this->binddn;
1128  $ret['ADMINPASSWORD'] = $this->bindpw;
1129  }
1130 
1131  return $ret;
1132  }
1133 
1134 
1148  function generateLdif (string $dn, string $filter = '(objectClass=*)', string $scope = 'sub', int $limit = 0, int $wrap = NULL): string
1149  {
1150  $limit = (($limit == 0) ? '' : ' -z '.$limit);
1151  if ($wrap === NULL) {
1152  $wrap = '';
1153  } else {
1154  $wrap = ' -o ldif-wrap='.($wrap ? $wrap : 'no');
1155  }
1156 
1157  // Check scope values
1158  $scope = trim($scope);
1159  if (!empty($scope) && !in_array($scope, ['base', 'one', 'sub', 'children'])) {
1160  throw new LDIFExportException(sprintf('Invalid parameter for scope "%s", please use "base", "one", "sub" or "children".', $scope));
1161  }
1162  $scope = (empty($scope) ? '' : ' -s '.$scope);
1163 
1164  // Prepare parameters to be valid for shell execution
1165  $dn = escapeshellarg($dn);
1166  $pwd = escapeshellarg($this->bindpw);
1167  $host = escapeshellarg($this->hostname);
1168  $admin = escapeshellarg($this->binddn);
1169  $filter = escapeshellarg($filter);
1170 
1171  $cmd = 'ldapsearch'.($this->tls ? ' -ZZ' : '')." -x -LLLL -D {$admin} {$filter} {$limit} {$wrap} {$scope} -H {$host} -b {$dn} -w {$pwd} ";
1172 
1173  // Create list of process pipes
1174  $descriptorspec = [
1175  0 => ["pipe", "r"], // stdin
1176  1 => ["pipe", "w"], // stdout
1177  2 => ["pipe", "w"] // stderr
1178  ];
1179 
1180  // Try to open the process
1181  $process = proc_open($cmd, $descriptorspec, $pipes);
1182  if ($process !== FALSE) {
1183  // Write the password to stdin
1184  fclose($pipes[0]);
1185 
1186  // Get results from stdout and stderr
1187  $res = stream_get_contents($pipes[1]);
1188  $err = stream_get_contents($pipes[2]);
1189  fclose($pipes[1]);
1190 
1191  // Close the process and check its return value
1192  if (proc_close($process) != 0) {
1193  throw new LDIFExportException($err);
1194  }
1195  } else {
1196  throw new LDIFExportException(_('proc_open failed to execute ldapsearch'));
1197  }
1198  return $res;
1199  }
1200 
1201  function dn_exists ($dn): bool
1202  {
1203  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, '', 'dn_exists('.$dn.')');
1204  return (@ldap_read($this->cid, $dn, '(objectClass=*)', ['objectClass']) !== FALSE);
1205  }
1206 
1207  function parseLdif (string $str_attr): array
1208  {
1209  /* First we split the string into lines */
1210  $fileLines = preg_split("/\n/", $str_attr);
1211  if (end($fileLines) != '') {
1212  $fileLines[] = '';
1213  }
1214 
1215  /* Joining lines */
1216  $line = NULL;
1217  $entry = [];
1218  $entries = [];
1219  $entryStart = -1;
1220  foreach ($fileLines as $lineNumber => $fileLine) {
1221  if (preg_match('/^ /', $fileLine)) {
1222  if ($line === NULL) {
1223  throw new LDIFImportException(sprintf(_('Error line %s, first line of an entry cannot start with a space'), $lineNumber));
1224  }
1225  /* Append to current line */
1226  $line .= substr($fileLine, 1);
1227  } else {
1228  if ($line !== NULL) {
1229  if (preg_match('/^#/', $line)
1230  || (preg_match('/^version:/', $line) && empty($entry))) {
1231  /* Ignore comment */
1232  /* Ignore version number */
1233  } else {
1234  /* Line has ended */
1235  list ($key, $value) = explode(':', $line, 2);
1236  $value = trim($value);
1237  if (preg_match('/^:/', $value)) {
1238  $value = base64_decode(trim(substr($value, 1)));
1239  }
1240  if (preg_match('/^</', $value)) {
1241  throw new LDIFImportException(sprintf(_('Error line %s, references to an external file are not supported'), $lineNumber));
1242  }
1243  if ($value === '') {
1244  throw new LDIFImportException(sprintf(_('Error line %s, attribute "%s" has no value'), $lineNumber, $key));
1245  }
1246  if ($key == 'dn') {
1247  if (!empty($entry)) {
1248  throw new LDIFImportException(sprintf(_('Error line %s, an entry bloc can only have one dn'), $lineNumber));
1249  }
1250  $entry['dn'] = $value;
1251  $entryStart = $lineNumber;
1252  } elseif (empty($entry)) {
1253  throw new LDIFImportException(sprintf(_('Error line %s, an entry bloc should start with the dn'), $lineNumber));
1254  } else {
1255  if (!isset($entry[$key])) {
1256  $entry[$key] = [];
1257  }
1258  $entry[$key][] = $value;
1259  }
1260  }
1261  }
1262  /* Start new line */
1263  $line = trim($fileLine);
1264  if ($line == '') {
1265  if (!empty($entry)) {
1266  /* Entry is finished */
1267  $entries[$entryStart] = $entry;
1268  }
1269  /* Start a new entry */
1270  $entry = [];
1271  $entryStart = -1;
1272  $line = NULL;
1273  }
1274  }
1275  }
1276 
1277  return $entries;
1278  }
1279 
1295  function import_complete_ldif ($srp, $str_attr, $JustModify, $DeleteOldEntries)
1296  {
1297  $entries = $this->parseLdif($str_attr);
1298 
1299  if ($this->reconnect) {
1300  $this->connect();
1301  }
1302 
1303  foreach ($entries as $startLine => $entry) {
1304  /* Delete before insert */
1305  $usermdir = ($this->dn_exists($entry['dn']) && $DeleteOldEntries);
1306  /* Should we use Modify instead of Add */
1307  $usemodify = ($this->dn_exists($entry['dn']) && $JustModify);
1308 
1309  /* If we can't Import, return with a file error */
1310  if (!$this->import_single_entry($srp, $entry, $usemodify, $usermdir)) {
1311  throw new LDIFImportException(sprintf(_('Error while importing dn: "%s", please check your LDIF from line %s on!'), $entry['dn'][0], $startLine));
1312  }
1313  }
1314 
1315  return count($entries);
1316  }
1317 
1332  protected function import_single_entry ($srp, $data, $modify, $delete)
1333  {
1334  global $config;
1335 
1336  if (!$config) {
1337  trigger_error("Can't import ldif, can't read config object.");
1338  }
1339 
1340  if ($this->reconnect) {
1341  $this->connect();
1342  }
1343 
1344  $ret = FALSE;
1345  $dn = NULL;
1346  $operation = NULL;
1347 
1348  /* If dn is an index of data, we should try to insert the data */
1349  if (isset($data['dn'])) {
1350  /* Fix dn */
1351  $tmp = ldap_explode_dn($data['dn'], 0);
1352  unset($tmp['count']);
1353  $dn = '';
1354  foreach ($tmp as $tm) {
1355  $dn .= trim($tm).',';
1356  }
1357  $dn = preg_replace('/,$/', '', $dn);
1358  unset($data['dn']);
1359 
1360  /* Creating Entry */
1361  $this->cd($dn);
1362 
1363  /* Delete existing entry */
1364  if ($delete) {
1365  $this->rmdir_recursive($srp, $dn);
1366  }
1367 
1368  /* Create missing trees */
1369  $this->cd($config->current['BASE']);
1370  try {
1371  $this->create_missing_trees($srp, preg_replace('/^[^,]+,/', '', $dn));
1372  } catch (FusionDirectoryError $error) {
1373  $error->display();
1374  }
1375  $this->cd($dn);
1376 
1377  $operation = LDAP_MOD;
1378  if (!$modify) {
1379  $this->cat($srp, $dn);
1380  if ($this->count($srp)) {
1381  /* The destination entry exists, overwrite it with the new entry */
1382  $attrs = $this->fetch($srp);
1383  foreach (array_keys($attrs) as $name) {
1384  if (!is_numeric($name)) {
1385  if (in_array($name, ['dn','count'])) {
1386  continue;
1387  }
1388  if (!isset($data[$name])) {
1389  $data[$name] = [];
1390  }
1391  }
1392  }
1393  $ret = $this->modify($data);
1394  } else {
1395  /* The destination entry doesn't exists, create it */
1396  $operation = LDAP_ADD;
1397  $ret = $this->add($data);
1398  }
1399  } else {
1400  /* Keep all vars that aren't touched by this ldif */
1401  $ret = $this->modify($data);
1402  }
1403  }
1404 
1405  if (!$this->success()) {
1406  $error = new FusionDirectoryLdapError($dn, $operation, $this->get_error(), $this->get_errno());
1407  $error->display();
1408  }
1409 
1410 
1411  return $ret;
1412  }
1413 
1419  function get_objectclasses ($force_reload = FALSE)
1420  {
1421  /* Return the cached results. */
1422  if (class_available('session') && session::is_set('LDAP_CACHE::get_objectclasses') && !$force_reload) {
1423  return session::get('LDAP_CACHE::get_objectclasses');
1424  }
1425 
1426  // Get base to look for schema
1427  $res = @ldap_read($this->cid, '', 'objectClass=*', ['subschemaSubentry']);
1428  $attrs = @ldap_get_entries($this->cid, $res);
1429  if (!isset($attrs[0]['subschemasubentry'][0])) {
1430  return [];
1431  }
1432 
1433  /* Get list of objectclasses and fill array */
1434  $nb = $attrs[0]['subschemasubentry'][0];
1435  $objectclasses = [];
1436  $res = ldap_read($this->cid, $nb, 'objectClass=*', ['objectclasses']);
1437  $attrs = ldap_get_entries($this->cid, $res);
1438  if (!isset($attrs[0])) {
1439  return [];
1440  }
1441  foreach ($attrs[0]['objectclasses'] as $val) {
1442  if (preg_match('/^[0-9]+$/', $val)) {
1443  continue;
1444  }
1445  $name = 'OID';
1446  $pattern = explode(' ', $val);
1447  $ocname = preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1448  $objectclasses[$ocname] = [];
1449 
1450  $value = '';
1451  foreach ($pattern as $chunk) {
1452  switch ($chunk) {
1453 
1454  case '(':
1455  $value = '';
1456  break;
1457 
1458  case ')':
1459  if ($name != '') {
1460  $v = $this->value2container($value);
1461  if (in_array($name, ['MUST', 'MAY']) && !is_array($v)) {
1462  $v = [$v];
1463  }
1464  $objectclasses[$ocname][$name] = $v;
1465  }
1466  $name = '';
1467  $value = '';
1468  break;
1469 
1470  case 'NAME':
1471  case 'DESC':
1472  case 'SUP':
1473  case 'STRUCTURAL':
1474  case 'ABSTRACT':
1475  case 'AUXILIARY':
1476  case 'MUST':
1477  case 'MAY':
1478  if ($name != '') {
1479  $v = $this->value2container($value);
1480  if (in_array($name, ['MUST','MAY']) && !is_array($v)) {
1481  $v = [$v];
1482  }
1483  $objectclasses[$ocname][$name] = $v;
1484  }
1485  $name = $chunk;
1486  $value = '';
1487  break;
1488 
1489  default: $value .= $chunk.' ';
1490  }
1491  }
1492  }
1493  if (class_available('session')) {
1494  session::set('LDAP_CACHE::get_objectclasses', $objectclasses);
1495  }
1496 
1497  return $objectclasses;
1498  }
1499 
1500 
1501  function value2container ($value)
1502  {
1503  /* Set emtpy values to "TRUE" only */
1504  if (preg_match('/^\s*$/', $value)) {
1505  return TRUE;
1506  }
1507 
1508  /* Remove ' and " if needed */
1509  $value = preg_replace('/^[\'"]/', '', $value);
1510  $value = preg_replace('/[\'"] *$/', '', $value);
1511 
1512  /* Convert to array if $ is inside... */
1513  if (preg_match('/\$/', $value)) {
1514  $container = preg_split('/\s*\$\s*/', $value);
1515  } else {
1516  $container = chop($value);
1517  }
1518 
1519  return $container;
1520  }
1521 
1527  function log ($string)
1528  {
1529  if (session::is_set('config')) {
1530  $cfg = session::get('config');
1531  if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])) {
1532  syslog(LOG_INFO, $string);
1533  }
1534  }
1535  }
1536 
1537  /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1538 
1544  function getCn ($dn)
1545  {
1546  $simple = explode(",", $dn);
1547 
1548  foreach ($simple as $piece) {
1549  $partial = explode("=", $piece);
1550 
1551  if ($partial[0] == "cn") {
1552  return $partial[1];
1553  }
1554  }
1555  }
1556 
1557  public static function get_naming_contexts ($server, $admin = '', $password = '')
1558  {
1559  /* Build LDAP connection */
1560  $ds = ldap_connect($server);
1561  if (!$ds) {
1562  die('Can\'t bind to LDAP. No check possible!');
1563  }
1564  ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1565  ldap_bind($ds, $admin, $password);
1566 
1567  /* Get base to look for naming contexts */
1568  $res = @ldap_read($ds, '', 'objectClass=*', ['namingContexts']);
1569  $attrs = @ldap_get_entries($ds, $res);
1570 
1571  logging::debug(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $attrs[0]['namingcontexts'], 'get_naming_contexts');
1572  return $attrs[0]['namingcontexts'];
1573  }
1574 }
rename_dn($source, $dest)
Move the given Ldap entry from $source to $dest.
Definition: class_ldap.inc:718
htmlescape(string $str)
Escape string for HTML output.
Definition: php_setup.inc:32
set_size_limit($size)
Set a size limit.
Definition: class_ldap.inc:500
get_error($details=TRUE)
Get the error.
parse_result($srp)
Parse last result.
Definition: class_ldap.inc:410
object_match_filter($dn, $filter)
Search object from a filter.
Definition: class_ldap.inc:479
clearResult($srp)
Clear a result.
Definition: class_ldap.inc:576
static get($name)
Accessor of a session var.
getSearchResource()
Get the search ressource.
Definition: class_ldap.inc:150
cd($dir)
Change directory.
Definition: class_ldap.inc:315
const DEBUG_LDAP
static prepare4filter($dn)
Function to fix problematic characters in DN&#39;s that are used for search requests. I...
Definition: class_ldap.inc:163
rm($attrs="", $dn="")
Remove.
Definition: class_ldap.inc:644
rmdir_recursive($srp, $deletedn)
Function rmdir_recursive.
Definition: class_ldap.inc:773
get_errno()
Get the errno.
static set($name, $value)
Set a value in a session.
Error returned by an LDAP operation called from FusionDirectory.
log($string)
Add a string in log file.
success()
Success.
rebind($ldap, $referral)
Rebind.
Definition: class_ldap.inc:261
disconnect()
Disconnect to LDAP server.
Definition: class_ldap.inc:300
connect()
Create a connection to LDAP server.
Definition: class_ldap.inc:184
__construct($binddn, $bindpw, $hostname, $follow_referral=FALSE, $tls=FALSE)
Create a LDAP connection.
Definition: class_ldap.inc:86
static invalidCredentialsError()
Error text that must be returned for invalid user or password.
Definition: class_ldap.inc:174
fetch($srp, bool $cleanUpNumericIndices=FALSE)
Fetch.
Definition: class_ldap.inc:520
getDN($srp)
Accessor of the DN.
Definition: class_ldap.inc:589
import_single_entry($srp, $data, $modify, $delete)
Function to Imports a single entry.
__wakeup()
Remove bogus resources after unserialize.
Definition: class_ldap.inc:106
static debug(int $level, int $line, string $function, string $file, $data, string $info='')
Debug output method.
getParentDir($basedn='')
Accessor of the parent directory of the basedn.
Definition: class_ldap.inc:331
Parent class for all exceptions thrown in FusionDirectory.
This class contains all ldap function needed to make ldap operations easy.
Definition: class_ldap.inc:34
hitSizeLimit()
Check if the search hit the size limit.
Fatal error class. Does not extend FusionDirectoryError.
Exception class which can be thrown by LDAP class if LDIF export fails.
get_objectclasses($force_reload=FALSE)
Get the object classes.
generateLdif(string $dn, string $filter='(objectClass=*)', string $scope='sub', int $limit=0, int $wrap=NULL)
Generates an ldif for all entries matching the filter settings, scope and limit.
modify(array $attrs)
Modify a entry of the directory LDAP.
Definition: class_ldap.inc:839
static init(string $server, string $base, string $binddn='', string $pass='')
Initialize a LDAP connection.
Definition: class_ldap.inc:127
count($srp)
Return the numbers of entries.
Definition: class_ldap.inc:616
import_complete_ldif($srp, $str_attr, $JustModify, $DeleteOldEntries)
Function to imports ldifs.
add($attrs)
Add entry in the LDAP directory.
Definition: class_ldap.inc:892
search($srp, $filter, $attrs=[], $scope='subtree', array $controls=NULL)
Search about filter.
Definition: class_ldap.inc:350
resetResult($srp)
Reset the result.
Definition: class_ldap.inc:566
Parent class for all errors in FusionDirectory.
unbind()
Unbind to LDAP server.
Definition: class_ldap.inc:290
modify_batch(array $changes)
Modify a entry of the directory LDAP with fine control.
Definition: class_ldap.inc:867
rmdir($deletedn)
Remove directory.
Definition: class_ldap.inc:691
get_additional_error()
Get the LDAP additional error.
getCn($dn)
Function to get cn.
static is_set($name)
Check if the name of the session is set.
reconnect()
Reconnect to LDAP server.
Definition: class_ldap.inc:280
Exception class which can be thrown by LDAP if the LDIF format is broken.
class_available($name)
Checks if a class is available.
Definition: functions.inc:92